summaryrefslogtreecommitdiff
path: root/modules/scirenderer/src
diff options
context:
space:
mode:
authorShashank2017-05-29 12:40:26 +0530
committerShashank2017-05-29 12:40:26 +0530
commit0345245e860375a32c9a437c4a9d9cae807134e9 (patch)
treead51ecbfa7bcd3cc5f09834f1bb8c08feaa526a4 /modules/scirenderer/src
downloadscilab_for_xcos_on_cloud-0345245e860375a32c9a437c4a9d9cae807134e9.tar.gz
scilab_for_xcos_on_cloud-0345245e860375a32c9a437c4a9d9cae807134e9.tar.bz2
scilab_for_xcos_on_cloud-0345245e860375a32c9a437c4a9d9cae807134e9.zip
CMSCOPE changed
Diffstat (limited to 'modules/scirenderer/src')
-rwxr-xr-xmodules/scirenderer/src/org/scilab/forge/scirenderer/Canvas.java113
-rwxr-xr-xmodules/scirenderer/src/org/scilab/forge/scirenderer/Drawer.java29
-rwxr-xr-xmodules/scirenderer/src/org/scilab/forge/scirenderer/DrawingTools.java138
-rwxr-xr-xmodules/scirenderer/src/org/scilab/forge/scirenderer/PackageInfo.java30
-rwxr-xr-xmodules/scirenderer/src/org/scilab/forge/scirenderer/SciRendererException.java53
-rwxr-xr-xmodules/scirenderer/src/org/scilab/forge/scirenderer/buffers/BuffersManager.java45
-rwxr-xr-xmodules/scirenderer/src/org/scilab/forge/scirenderer/buffers/DataBuffer.java35
-rwxr-xr-xmodules/scirenderer/src/org/scilab/forge/scirenderer/buffers/ElementsBuffer.java52
-rwxr-xr-xmodules/scirenderer/src/org/scilab/forge/scirenderer/buffers/IndicesBuffer.java46
-rwxr-xr-xmodules/scirenderer/src/org/scilab/forge/scirenderer/clipping/ClippingManager.java42
-rwxr-xr-xmodules/scirenderer/src/org/scilab/forge/scirenderer/clipping/ClippingPlane.java63
-rwxr-xr-xmodules/scirenderer/src/org/scilab/forge/scirenderer/data/AbstractDataProvider.java68
-rwxr-xr-xmodules/scirenderer/src/org/scilab/forge/scirenderer/data/DataProvider.java37
-rwxr-xr-xmodules/scirenderer/src/org/scilab/forge/scirenderer/data/DataUser.java23
-rwxr-xr-xmodules/scirenderer/src/org/scilab/forge/scirenderer/implementation/g2d/G2DCanvas.java189
-rwxr-xr-xmodules/scirenderer/src/org/scilab/forge/scirenderer/implementation/g2d/G2DCanvasFactory.java37
-rwxr-xr-xmodules/scirenderer/src/org/scilab/forge/scirenderer/implementation/g2d/G2DDrawingTools.java147
-rwxr-xr-xmodules/scirenderer/src/org/scilab/forge/scirenderer/implementation/g2d/buffers/G2DBuffersManager.java111
-rwxr-xr-xmodules/scirenderer/src/org/scilab/forge/scirenderer/implementation/g2d/buffers/G2DElementsBuffer.java209
-rwxr-xr-xmodules/scirenderer/src/org/scilab/forge/scirenderer/implementation/g2d/buffers/G2DIndicesBuffer.java89
-rwxr-xr-xmodules/scirenderer/src/org/scilab/forge/scirenderer/implementation/g2d/clipping/G2DClippingManager.java74
-rwxr-xr-xmodules/scirenderer/src/org/scilab/forge/scirenderer/implementation/g2d/clipping/G2DClippingPlane.java109
-rwxr-xr-xmodules/scirenderer/src/org/scilab/forge/scirenderer/implementation/g2d/lighting/G2DLight.java144
-rwxr-xr-xmodules/scirenderer/src/org/scilab/forge/scirenderer/implementation/g2d/lighting/G2DLightManager.java140
-rwxr-xr-xmodules/scirenderer/src/org/scilab/forge/scirenderer/implementation/g2d/motor/AbstractDrawable3DObject.java426
-rwxr-xr-xmodules/scirenderer/src/org/scilab/forge/scirenderer/implementation/g2d/motor/BoundingBox.java176
-rwxr-xr-xmodules/scirenderer/src/org/scilab/forge/scirenderer/implementation/g2d/motor/Clippable.java32
-rwxr-xr-xmodules/scirenderer/src/org/scilab/forge/scirenderer/implementation/g2d/motor/ConvexObject.java321
-rwxr-xr-xmodules/scirenderer/src/org/scilab/forge/scirenderer/implementation/g2d/motor/DrawTools.java307
-rwxr-xr-xmodules/scirenderer/src/org/scilab/forge/scirenderer/implementation/g2d/motor/G2DStroke.java105
-rwxr-xr-xmodules/scirenderer/src/org/scilab/forge/scirenderer/implementation/g2d/motor/InvalidPolygonException.java23
-rwxr-xr-xmodules/scirenderer/src/org/scilab/forge/scirenderer/implementation/g2d/motor/LightHelper.java344
-rwxr-xr-xmodules/scirenderer/src/org/scilab/forge/scirenderer/implementation/g2d/motor/Motor3D.java617
-rwxr-xr-xmodules/scirenderer/src/org/scilab/forge/scirenderer/implementation/g2d/motor/PolyLine.java317
-rwxr-xr-xmodules/scirenderer/src/org/scilab/forge/scirenderer/implementation/g2d/motor/Scene.java250
-rwxr-xr-xmodules/scirenderer/src/org/scilab/forge/scirenderer/implementation/g2d/motor/Segment.java247
-rwxr-xr-xmodules/scirenderer/src/org/scilab/forge/scirenderer/implementation/g2d/motor/SpritedRectangle.java312
-rwxr-xr-xmodules/scirenderer/src/org/scilab/forge/scirenderer/implementation/g2d/motor/Triangle.java593
-rwxr-xr-xmodules/scirenderer/src/org/scilab/forge/scirenderer/implementation/g2d/renderer/G2DRenderer.java58
-rwxr-xr-xmodules/scirenderer/src/org/scilab/forge/scirenderer/implementation/g2d/renderer/G2DRendererManager.java48
-rwxr-xr-xmodules/scirenderer/src/org/scilab/forge/scirenderer/implementation/g2d/texture/G2DTextureDrawingTools.java207
-rwxr-xr-xmodules/scirenderer/src/org/scilab/forge/scirenderer/implementation/g2d/texture/G2DTextureManager.java513
-rwxr-xr-xmodules/scirenderer/src/org/scilab/forge/scirenderer/implementation/jogl/HardwareFailException.java30
-rwxr-xr-xmodules/scirenderer/src/org/scilab/forge/scirenderer/implementation/jogl/JoGLCanvas.java440
-rwxr-xr-xmodules/scirenderer/src/org/scilab/forge/scirenderer/implementation/jogl/JoGLCanvasFactory.java49
-rwxr-xr-xmodules/scirenderer/src/org/scilab/forge/scirenderer/implementation/jogl/JoGLCapacity.java104
-rwxr-xr-xmodules/scirenderer/src/org/scilab/forge/scirenderer/implementation/jogl/JoGLDrawingTools.java188
-rwxr-xr-xmodules/scirenderer/src/org/scilab/forge/scirenderer/implementation/jogl/JoGLParameters.java65
-rwxr-xr-xmodules/scirenderer/src/org/scilab/forge/scirenderer/implementation/jogl/buffers/JoGLBuffersManager.java226
-rwxr-xr-xmodules/scirenderer/src/org/scilab/forge/scirenderer/implementation/jogl/buffers/JoGLDataBuffer.java150
-rwxr-xr-xmodules/scirenderer/src/org/scilab/forge/scirenderer/implementation/jogl/buffers/JoGLElementsBuffer.java313
-rwxr-xr-xmodules/scirenderer/src/org/scilab/forge/scirenderer/implementation/jogl/buffers/JoGLIndicesBuffer.java116
-rwxr-xr-xmodules/scirenderer/src/org/scilab/forge/scirenderer/implementation/jogl/clipping/JoGLClippingManager.java78
-rwxr-xr-xmodules/scirenderer/src/org/scilab/forge/scirenderer/implementation/jogl/clipping/JoGLClippingPlane.java123
-rwxr-xr-xmodules/scirenderer/src/org/scilab/forge/scirenderer/implementation/jogl/drawer/JoGLShapeDrawer.java420
-rwxr-xr-xmodules/scirenderer/src/org/scilab/forge/scirenderer/implementation/jogl/lightning/JoGLLight.java188
-rwxr-xr-xmodules/scirenderer/src/org/scilab/forge/scirenderer/implementation/jogl/lightning/JoGLLightManager.java114
-rwxr-xr-xmodules/scirenderer/src/org/scilab/forge/scirenderer/implementation/jogl/picking/GLPickingManager.java85
-rwxr-xr-xmodules/scirenderer/src/org/scilab/forge/scirenderer/implementation/jogl/picking/JoGLPickingManager.java57
-rwxr-xr-xmodules/scirenderer/src/org/scilab/forge/scirenderer/implementation/jogl/picking/JoGLPickingTools.java65
-rwxr-xr-xmodules/scirenderer/src/org/scilab/forge/scirenderer/implementation/jogl/renderer/JoGLRenderer.java120
-rwxr-xr-xmodules/scirenderer/src/org/scilab/forge/scirenderer/implementation/jogl/renderer/JoGLRendererManager.java100
-rwxr-xr-xmodules/scirenderer/src/org/scilab/forge/scirenderer/implementation/jogl/texture/JoGLTextureManager.java745
-rwxr-xr-xmodules/scirenderer/src/org/scilab/forge/scirenderer/implementation/jogl/utils/G2DShortCuts.java57
-rwxr-xr-xmodules/scirenderer/src/org/scilab/forge/scirenderer/implementation/jogl/utils/GLShortCuts.java110
-rwxr-xr-xmodules/scirenderer/src/org/scilab/forge/scirenderer/lightning/Light.java126
-rwxr-xr-xmodules/scirenderer/src/org/scilab/forge/scirenderer/lightning/LightManager.java61
-rwxr-xr-xmodules/scirenderer/src/org/scilab/forge/scirenderer/picking/PickingManager.java27
-rwxr-xr-xmodules/scirenderer/src/org/scilab/forge/scirenderer/picking/PickingTask.java26
-rwxr-xr-xmodules/scirenderer/src/org/scilab/forge/scirenderer/picking/PickingTools.java38
-rwxr-xr-xmodules/scirenderer/src/org/scilab/forge/scirenderer/renderer/Renderer.java43
-rwxr-xr-xmodules/scirenderer/src/org/scilab/forge/scirenderer/renderer/RendererManager.java33
-rwxr-xr-xmodules/scirenderer/src/org/scilab/forge/scirenderer/ruler/DefaultRulerModel.java436
-rwxr-xr-xmodules/scirenderer/src/org/scilab/forge/scirenderer/ruler/DefaultRulerSpriteFactory.java63
-rwxr-xr-xmodules/scirenderer/src/org/scilab/forge/scirenderer/ruler/RulerDrawer.java726
-rwxr-xr-xmodules/scirenderer/src/org/scilab/forge/scirenderer/ruler/RulerDrawingResult.java136
-rwxr-xr-xmodules/scirenderer/src/org/scilab/forge/scirenderer/ruler/RulerModel.java225
-rwxr-xr-xmodules/scirenderer/src/org/scilab/forge/scirenderer/ruler/RulerSpriteFactory.java32
-rwxr-xr-xmodules/scirenderer/src/org/scilab/forge/scirenderer/ruler/graduations/AbstractGraduations.java233
-rwxr-xr-xmodules/scirenderer/src/org/scilab/forge/scirenderer/ruler/graduations/Graduations.java108
-rwxr-xr-xmodules/scirenderer/src/org/scilab/forge/scirenderer/ruler/graduations/LinearGraduations.java294
-rwxr-xr-xmodules/scirenderer/src/org/scilab/forge/scirenderer/ruler/graduations/LogarithmicGraduations.java348
-rwxr-xr-xmodules/scirenderer/src/org/scilab/forge/scirenderer/ruler/graduations/TinyIntervalFormat.java95
-rwxr-xr-xmodules/scirenderer/src/org/scilab/forge/scirenderer/ruler/graduations/UserDefinedFormat.java96
-rwxr-xr-xmodules/scirenderer/src/org/scilab/forge/scirenderer/shapes/appearance/Appearance.java190
-rwxr-xr-xmodules/scirenderer/src/org/scilab/forge/scirenderer/shapes/appearance/Color.java104
-rwxr-xr-xmodules/scirenderer/src/org/scilab/forge/scirenderer/shapes/appearance/Material.java100
-rwxr-xr-xmodules/scirenderer/src/org/scilab/forge/scirenderer/shapes/geometry/DefaultGeometry.java175
-rwxr-xr-xmodules/scirenderer/src/org/scilab/forge/scirenderer/shapes/geometry/Geometry.java176
-rwxr-xr-xmodules/scirenderer/src/org/scilab/forge/scirenderer/texture/AbstractTexture.java132
-rwxr-xr-xmodules/scirenderer/src/org/scilab/forge/scirenderer/texture/AbstractTextureDataProvider.java71
-rwxr-xr-xmodules/scirenderer/src/org/scilab/forge/scirenderer/texture/AnchorPosition.java63
-rwxr-xr-xmodules/scirenderer/src/org/scilab/forge/scirenderer/texture/BufferedImageTextureDrawingTools.java202
-rwxr-xr-xmodules/scirenderer/src/org/scilab/forge/scirenderer/texture/DrawnTextureDataProvider.java134
-rwxr-xr-xmodules/scirenderer/src/org/scilab/forge/scirenderer/texture/TextEntity.java203
-rwxr-xr-xmodules/scirenderer/src/org/scilab/forge/scirenderer/texture/Texture.java140
-rwxr-xr-xmodules/scirenderer/src/org/scilab/forge/scirenderer/texture/TextureBufferedImage.java88
-rwxr-xr-xmodules/scirenderer/src/org/scilab/forge/scirenderer/texture/TextureDataProvider.java125
-rwxr-xr-xmodules/scirenderer/src/org/scilab/forge/scirenderer/texture/TextureDrawer.java54
-rwxr-xr-xmodules/scirenderer/src/org/scilab/forge/scirenderer/texture/TextureDrawingTools.java89
-rwxr-xr-xmodules/scirenderer/src/org/scilab/forge/scirenderer/texture/TextureManager.java34
-rwxr-xr-xmodules/scirenderer/src/org/scilab/forge/scirenderer/tranformations/DegenerateMatrixException.java29
-rwxr-xr-xmodules/scirenderer/src/org/scilab/forge/scirenderer/tranformations/Rotation.java294
-rwxr-xr-xmodules/scirenderer/src/org/scilab/forge/scirenderer/tranformations/Transformation.java82
-rwxr-xr-xmodules/scirenderer/src/org/scilab/forge/scirenderer/tranformations/TransformationFactory.java680
-rwxr-xr-xmodules/scirenderer/src/org/scilab/forge/scirenderer/tranformations/TransformationManager.java118
-rwxr-xr-xmodules/scirenderer/src/org/scilab/forge/scirenderer/tranformations/TransformationManagerImpl.java226
-rwxr-xr-xmodules/scirenderer/src/org/scilab/forge/scirenderer/tranformations/TransformationManagerListener.java31
-rwxr-xr-xmodules/scirenderer/src/org/scilab/forge/scirenderer/tranformations/TransformationStack.java86
-rwxr-xr-xmodules/scirenderer/src/org/scilab/forge/scirenderer/tranformations/TransformationStackImpl.java98
-rwxr-xr-xmodules/scirenderer/src/org/scilab/forge/scirenderer/tranformations/TransformationStackListener.java28
-rwxr-xr-xmodules/scirenderer/src/org/scilab/forge/scirenderer/tranformations/Vector3d.java206
-rwxr-xr-xmodules/scirenderer/src/org/scilab/forge/scirenderer/tranformations/Vector3f.java106
-rwxr-xr-xmodules/scirenderer/src/org/scilab/forge/scirenderer/tranformations/Vector4d.java32
-rwxr-xr-xmodules/scirenderer/src/org/scilab/forge/scirenderer/utils/shapes/geometry/CubeFactory.java170
-rwxr-xr-xmodules/scirenderer/src/org/scilab/forge/scirenderer/utils/shapes/geometry/SphereFactory.java146
-rwxr-xr-xmodules/scirenderer/src/org/scilab/forge/scirenderer/utils/shapes/geometry/TetrahedronFactory.java138
117 files changed, 18558 insertions, 0 deletions
diff --git a/modules/scirenderer/src/org/scilab/forge/scirenderer/Canvas.java b/modules/scirenderer/src/org/scilab/forge/scirenderer/Canvas.java
new file mode 100755
index 000000000..167f38f58
--- /dev/null
+++ b/modules/scirenderer/src/org/scilab/forge/scirenderer/Canvas.java
@@ -0,0 +1,113 @@
+/*
+ * Scilab ( http://www.scilab.org/ ) - This file is part of Scilab
+ * Copyright (C) 2009-2011 - DIGITEO - Pierre Lando
+ *
+ * This file must be used under the terms of the CeCILL.
+ * This source file is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at
+ * http://www.cecill.info/licences/Licence_CeCILL_V2.1-en.txt
+ */
+
+package org.scilab.forge.scirenderer;
+
+import org.scilab.forge.scirenderer.buffers.BuffersManager;
+import org.scilab.forge.scirenderer.picking.PickingManager;
+import org.scilab.forge.scirenderer.renderer.RendererManager;
+import org.scilab.forge.scirenderer.texture.TextureManager;
+
+import java.awt.Dimension;
+
+/**
+ * @author Pierre Lando
+ */
+public interface Canvas {
+
+ /**
+ * Set this canvas main drawer.
+ * @param mainDrawer the new canvas main drawer.
+ */
+ void setMainDrawer(Drawer mainDrawer);
+
+ /**
+ * Return the canvas main drawer.
+ * @return the canvas main drawer.
+ */
+ Drawer getMainDrawer();
+
+ /**
+ * Return the renderer manager.
+ * @return the renderer manager.
+ */
+ RendererManager getRendererManager();
+
+ /**
+ * Return the buffers manager of this canvas.
+ * @return the buffers manager of this canvas.
+ */
+ BuffersManager getBuffersManager();
+
+ /**
+ * Return the picking manager.
+ * @return the picking manager.
+ */
+ PickingManager getPickingManager();
+
+ /**
+ * Texture manger getter.
+ * @return the texture manager.
+ */
+ TextureManager getTextureManager();
+
+ /**
+ * Return the canvas width.
+ * @return the canvas width.
+ */
+ int getWidth();
+
+ /**
+ * Return the canvas height.
+ * @return the canvas height.
+ */
+ int getHeight();
+
+ /**
+ * Return the canvas dimension.
+ * @return the canvas dimension.
+ */
+ Dimension getDimension();
+
+ /**
+ * Anti-aliasing level getter.
+ * - 0 for 1x
+ * - 1 for 2x
+ * - 2 for 4x
+ * - 3 for 8x
+ * - 4 for 16x
+ * @return the anti-aliasing level.
+ */
+ public int getAntiAliasingLevel();
+
+ /**
+ * Anti-aliasing level setter.
+ * - 0 for 1x
+ * - 1 for 2x
+ * - 2 for 4x
+ * - 3 for 8x
+ * - 4 for 16x
+ * @param antiAliasingLevel the new level.
+ */
+ public void setAntiAliasingLevel(int antiAliasingLevel);
+
+ /** Ask the canvas to perform asynchronous drawing. */
+ void redraw();
+
+ /** Ask the canvas to perform asynchronous drawing. */
+ void redrawAndWait();
+
+ /** Wait until a drawing has been performed */
+ void waitImage();
+
+ /** Destroy canvas : release Semaphore and associated threads */
+ void destroy();
+}
diff --git a/modules/scirenderer/src/org/scilab/forge/scirenderer/Drawer.java b/modules/scirenderer/src/org/scilab/forge/scirenderer/Drawer.java
new file mode 100755
index 000000000..a1f31ff71
--- /dev/null
+++ b/modules/scirenderer/src/org/scilab/forge/scirenderer/Drawer.java
@@ -0,0 +1,29 @@
+/*
+ * Scilab ( http://www.scilab.org/ ) - This file is part of Scilab
+ * Copyright (C) 2009-2011 - DIGITEO - Pierre Lando
+ *
+ * This file must be used under the terms of the CeCILL.
+ * This source file is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at
+ * http://www.cecill.info/licences/Licence_CeCILL_V2.1-en.txt
+ */
+
+package org.scilab.forge.scirenderer;
+
+/**
+ * @author Pierre Lando
+ */
+public interface Drawer {
+
+ /**
+ * Ask this drawer to draw with the given drawing tools.
+ * @param drawingTools the givens drawing tools.
+ */
+ void draw(DrawingTools drawingTools);
+
+ /**
+ * @return true if it is a 2D drawing
+ */
+ boolean is2DView();
+}
diff --git a/modules/scirenderer/src/org/scilab/forge/scirenderer/DrawingTools.java b/modules/scirenderer/src/org/scilab/forge/scirenderer/DrawingTools.java
new file mode 100755
index 000000000..0223ea754
--- /dev/null
+++ b/modules/scirenderer/src/org/scilab/forge/scirenderer/DrawingTools.java
@@ -0,0 +1,138 @@
+/*
+ * Scilab ( http://www.scilab.org/ ) - This file is part of Scilab
+ * Copyright (C) 2009-2011 - DIGITEO - Pierre Lando
+ *
+ * This file must be used under the terms of the CeCILL.
+ * This source file is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at
+ * http://www.cecill.info/licences/Licence_CeCILL_V2.1-en.txt
+ */
+
+package org.scilab.forge.scirenderer;
+
+import org.scilab.forge.scirenderer.buffers.ElementsBuffer;
+import org.scilab.forge.scirenderer.clipping.ClippingManager;
+import org.scilab.forge.scirenderer.lightning.LightManager;
+import org.scilab.forge.scirenderer.renderer.Renderer;
+import org.scilab.forge.scirenderer.shapes.appearance.Appearance;
+import org.scilab.forge.scirenderer.shapes.appearance.Color;
+import org.scilab.forge.scirenderer.shapes.geometry.Geometry;
+import org.scilab.forge.scirenderer.texture.AnchorPosition;
+import org.scilab.forge.scirenderer.texture.Texture;
+import org.scilab.forge.scirenderer.tranformations.TransformationManager;
+import org.scilab.forge.scirenderer.tranformations.Vector3d;
+
+/**
+ * @author Pierre Lando
+ */
+public interface DrawingTools {
+
+ /**
+ * Return the canvas where draw is done.
+ * @return the canvas where draw is done.
+ */
+ Canvas getCanvas();
+
+ /**
+ * Return the transformation manager.
+ * @return the transformation manager.
+ */
+ TransformationManager getTransformationManager();
+
+ /**
+ * Return the light manager.
+ * @return the light manager.
+ */
+ LightManager getLightManager();
+
+ /**
+ * Return the clipping manager.
+ * @return the clipping manager.
+ */
+ ClippingManager getClippingManager();
+
+ /**
+ * Clear the canvas with the given color.
+ * @param color the color used to clear the canvas.
+ */
+ void clear(Color color);
+
+ /**
+ * Clear the canvas with the given color.
+ * @param color the color used to clear the canvas.
+ */
+ void clear(java.awt.Color color);
+
+ /**
+ * Clear the depth buffer.
+ */
+ void clearDepthBuffer();
+
+ /**
+ * Ask the given renderer to perform a draw.
+ * @param renderer the given renderer.
+ */
+ void draw(Renderer renderer);
+
+ /**
+ * Draw the given geometry with default appearance.
+ * @param geometry the geometry to draw.
+ * @throws SciRendererException if the draw is not possible.
+ */
+ void draw(Geometry geometry) throws SciRendererException;
+
+ /**
+ * Draw the given geometry.
+ * @param geometry the geometry to draw.
+ * @param appearance the appearance to use.
+ * @throws SciRendererException if the draw is not possible.
+ */
+ void draw(Geometry geometry, Appearance appearance) throws SciRendererException;
+
+ /**
+ * Draw the texture on XY plane in current coordinate.
+ * The texture is drawn on the rectangle [(0,0)-(texture width,texture height)].
+ * @param texture the texture to drawn.
+ * @throws SciRendererException if the texture is not drawable.
+ */
+ void draw(Texture texture) throws SciRendererException;
+
+ /**
+ * Draw the given texture at all given position.
+ * @param texture the texture to draw.
+ * @param anchor the texture anchor position.
+ * @param positions the positions where the texture will be drawn.
+ * @throws SciRendererException if the texture is not drawable.
+ */
+ void draw(Texture texture, AnchorPosition anchor, ElementsBuffer positions) throws SciRendererException;
+
+ /**
+ * Draw the given texture at all given position with the given rotation angle.
+ * @param texture the texture to draw.
+ * @param anchor the texture anchor position.
+ * @param positions the positions where the texture will be drawn.
+ * @param rotationAngle the rotation angle.
+ * @throws SciRendererException if the texture is not drawable.
+ */
+ void draw(Texture texture, AnchorPosition anchor, ElementsBuffer positions, int offset, int stride, double rotationAngle) throws SciRendererException;
+
+ /**
+ * Draw the given texture at given position.
+ * @param texture the texture to draw.
+ * @param anchor the texture anchor position.
+ * @param position the position where the texture will be drawn.
+ * @throws SciRendererException if the texture is not drawable.
+ */
+ void draw(Texture texture, AnchorPosition anchor, Vector3d position) throws SciRendererException;
+
+ /**
+ * Draw the given texture at given position with the given rotation angle.
+ * @param texture the texture to draw.
+ * @param anchor the texture anchor position.
+ * @param position the position where the texture will be drawn.
+ * @param rotationAngle the rotation angle.
+ * @throws SciRendererException if the texture is not drawable.
+ */
+ void draw(Texture texture, AnchorPosition anchor, Vector3d position, double rotationAngle) throws SciRendererException;
+}
diff --git a/modules/scirenderer/src/org/scilab/forge/scirenderer/PackageInfo.java b/modules/scirenderer/src/org/scilab/forge/scirenderer/PackageInfo.java
new file mode 100755
index 000000000..d738fa9ff
--- /dev/null
+++ b/modules/scirenderer/src/org/scilab/forge/scirenderer/PackageInfo.java
@@ -0,0 +1,30 @@
+/*
+ * Scilab ( http://www.scilab.org/ ) - This file is part of Scilab
+ * Copyright (C) 2009-2011 - DIGITEO - Pierre Lando
+ *
+ * This file must be used under the terms of the CeCILL.
+ * This source file is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at
+ * http://www.cecill.info/licences/Licence_CeCILL_V2.1-en.txt
+ */
+
+package org.scilab.forge.scirenderer;
+
+/**
+ * This utility class give information about SciRenderer library.
+ * @author Pierre Lando
+ */
+public final class PackageInfo {
+
+ /**
+ * The current version of the library.
+ */
+ public static final String VERSION = "1.1.0";
+
+ /**
+ * Private constructor : this is an utility class.
+ */
+ private PackageInfo() {
+ }
+}
diff --git a/modules/scirenderer/src/org/scilab/forge/scirenderer/SciRendererException.java b/modules/scirenderer/src/org/scilab/forge/scirenderer/SciRendererException.java
new file mode 100755
index 000000000..c01e60d33
--- /dev/null
+++ b/modules/scirenderer/src/org/scilab/forge/scirenderer/SciRendererException.java
@@ -0,0 +1,53 @@
+/*
+ * Scilab ( http://www.scilab.org/ ) - This file is part of Scilab
+ * Copyright (C) 2009-2011 - DIGITEO - Pierre Lando
+ *
+ * This file must be used under the terms of the CeCILL.
+ * This source file is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at
+ * http://www.cecill.info/licences/Licence_CeCILL_V2.1-en.txt
+ */
+
+package org.scilab.forge.scirenderer;
+
+/**
+ * The SciRendererException is the superclass of all Exception from SciRenderer.
+ *
+ * @author Pierre Lando
+ */
+@SuppressWarnings(value = { "serial" })
+public class SciRendererException extends Exception {
+
+ /**
+ * Constructs a new exception with null as its detail message.
+ */
+ public SciRendererException() {
+ super();
+ }
+
+ /**
+ * Constructs a new exception with the specified detail message.
+ * @param message - the detail message. The detail message is saved for later retrieval by the #Throwable.getMessage() method.
+ */
+ public SciRendererException(String message) {
+ super(message);
+ }
+
+ /**
+ * Constructs a new exception with the specified detail message and cause.
+ * @param message - the detail message (which is saved for later retrieval by the Throwable.getMessage() method).
+ * @param cause - the cause (which is saved for later retrieval by the Throwable.getCause() method). (A null value is permitted, and indicates that the cause is nonexistent or unknown.)
+ */
+ public SciRendererException(String message, Throwable cause) {
+ super(message, cause);
+ }
+
+ /**
+ * Constructs a new exception with the specified cause and a detail message of (cause==null ? null : cause.toString()) (which typically contains the class and detail message of cause).
+ * @param cause - the cause (which is saved for later retrieval by the Throwable.getCause() method). (A null value is permitted, and indicates that the cause is nonexistent or unknown.)
+ */
+ public SciRendererException(Throwable cause) {
+ super(cause);
+ }
+}
diff --git a/modules/scirenderer/src/org/scilab/forge/scirenderer/buffers/BuffersManager.java b/modules/scirenderer/src/org/scilab/forge/scirenderer/buffers/BuffersManager.java
new file mode 100755
index 000000000..9808e4335
--- /dev/null
+++ b/modules/scirenderer/src/org/scilab/forge/scirenderer/buffers/BuffersManager.java
@@ -0,0 +1,45 @@
+/*
+ * Scilab ( http://www.scilab.org/ ) - This file is part of Scilab
+ * Copyright (C) 2009-2011 - DIGITEO - Pierre Lando
+ *
+ * This file must be used under the terms of the CeCILL.
+ * This source file is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at
+ * http://www.cecill.info/licences/Licence_CeCILL_V2.1-en.txt
+ */
+
+package org.scilab.forge.scirenderer.buffers;
+
+import java.util.Collection;
+
+/**
+ * Interface for a buffers manager.
+ * @author Pierre Lando
+ */
+public interface BuffersManager {
+
+ /**
+ * Create an elements buffer.
+ * @return a new elements buffer.
+ */
+ ElementsBuffer createElementsBuffer();
+
+ /**
+ * Create an indices buffer.
+ * @return a new indices buffer.
+ */
+ IndicesBuffer createIndicesBuffer();
+
+ /**
+ * Release all resources used by the given buffer.
+ * @param buffer the given buffer.
+ */
+ void dispose(DataBuffer buffer);
+
+ /**
+ * Release all resources used by the given buffers.
+ * @param buffers the given buffers.
+ */
+ void dispose(Collection <? extends DataBuffer > buffers);
+}
diff --git a/modules/scirenderer/src/org/scilab/forge/scirenderer/buffers/DataBuffer.java b/modules/scirenderer/src/org/scilab/forge/scirenderer/buffers/DataBuffer.java
new file mode 100755
index 000000000..232605071
--- /dev/null
+++ b/modules/scirenderer/src/org/scilab/forge/scirenderer/buffers/DataBuffer.java
@@ -0,0 +1,35 @@
+/*
+ * Scilab ( http://www.scilab.org/ ) - This file is part of Scilab
+ * Copyright (C) 2009-2011 - DIGITEO - Pierre Lando
+ *
+ * This file must be used under the terms of the CeCILL.
+ * This source file is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at
+ * http://www.cecill.info/licences/Licence_CeCILL_V2.1-en.txt
+ */
+
+package org.scilab.forge.scirenderer.buffers;
+
+import java.nio.Buffer;
+
+/**
+ * Interface for a data buffer.
+ * @author Pierre Lando
+ */
+public interface DataBuffer {
+
+ /**
+ * Return the data.
+ * @return the data.
+ */
+ Buffer getData();
+
+ /**
+ * Return the number of elements.
+ * @return the number of elements.
+ */
+ int getSize();
+
+ void clear();
+}
diff --git a/modules/scirenderer/src/org/scilab/forge/scirenderer/buffers/ElementsBuffer.java b/modules/scirenderer/src/org/scilab/forge/scirenderer/buffers/ElementsBuffer.java
new file mode 100755
index 000000000..e763fe7bd
--- /dev/null
+++ b/modules/scirenderer/src/org/scilab/forge/scirenderer/buffers/ElementsBuffer.java
@@ -0,0 +1,52 @@
+/*
+ * Scilab ( http://www.scilab.org/ ) - This file is part of Scilab
+ * Copyright (C) 2009-2011 - DIGITEO - Pierre Lando
+ *
+ * This file must be used under the terms of the CeCILL.
+ * This source file is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at
+ * http://www.cecill.info/licences/Licence_CeCILL_V2.1-en.txt
+ */
+
+package org.scilab.forge.scirenderer.buffers;
+
+import java.nio.FloatBuffer;
+
+/**
+ * @author Pierre Lando
+ */
+public interface ElementsBuffer extends DataBuffer {
+
+ /**
+ * Set the data.
+ * @param data the new data.
+ * @param elementSize the size of data elements.
+ */
+ void setData(float[] data, int elementSize);
+
+ /**
+ * Set the data.
+ * @param data the new data.
+ * @param elementSize the size of data elements.
+ */
+ void setData(Float[] data, int elementSize);
+
+ /**
+ * Set the data.
+ * @param data the new data.
+ * @param elementsSize the size of data elements.
+ */
+ void setData(FloatBuffer data, int elementsSize);
+
+ @Override
+ FloatBuffer getData();
+
+ /**
+ * Return the number of coordinate for one element.
+ * @return the number of coordinate for one element.
+ */
+ int getElementsSize();
+
+ void clear();
+}
diff --git a/modules/scirenderer/src/org/scilab/forge/scirenderer/buffers/IndicesBuffer.java b/modules/scirenderer/src/org/scilab/forge/scirenderer/buffers/IndicesBuffer.java
new file mode 100755
index 000000000..416cabe9f
--- /dev/null
+++ b/modules/scirenderer/src/org/scilab/forge/scirenderer/buffers/IndicesBuffer.java
@@ -0,0 +1,46 @@
+/*
+ * Scilab ( http://www.scilab.org/ ) - This file is part of Scilab
+ * Copyright (C) 2009-2011 - DIGITEO - Pierre Lando
+ *
+ * This file must be used under the terms of the CeCILL.
+ * This source file is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at
+ * http://www.cecill.info/licences/Licence_CeCILL_V2.1-en.txt
+ */
+
+package org.scilab.forge.scirenderer.buffers;
+
+import java.nio.IntBuffer;
+import java.util.Collection;
+
+/**
+ * @author Pierre Lando
+ */
+public interface IndicesBuffer extends DataBuffer {
+
+ /**
+ * Set the data
+ * @param indices the new data.
+ */
+ void setData(int[] indices);
+
+
+ /**
+ * Set the data
+ * @param indices the new data.
+ */
+ void setData(Collection<Integer> indices);
+
+ /**
+ * Set the data.
+ * @param indexBuffer the new data.
+ */
+ void setData(IntBuffer indexBuffer);
+
+ @Override
+ IntBuffer getData();
+
+
+ void clear();
+}
diff --git a/modules/scirenderer/src/org/scilab/forge/scirenderer/clipping/ClippingManager.java b/modules/scirenderer/src/org/scilab/forge/scirenderer/clipping/ClippingManager.java
new file mode 100755
index 000000000..e8ef4cd0d
--- /dev/null
+++ b/modules/scirenderer/src/org/scilab/forge/scirenderer/clipping/ClippingManager.java
@@ -0,0 +1,42 @@
+/*
+ * Scilab ( http://www.scilab.org/ ) - This file is part of Scilab
+ * Copyright (C) 2009-2011 - DIGITEO - Pierre Lando
+ *
+ * This file must be used under the terms of the CeCILL.
+ * This source file is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at
+ * http://www.cecill.info/licences/Licence_CeCILL_V2.1-en.txt
+ */
+
+package org.scilab.forge.scirenderer.clipping;
+
+/**
+ * Clipping manager interface.
+ *
+ * @author Pierre Lando
+ */
+public interface ClippingManager {
+
+ /**
+ * Return the number of available clipping plane.
+ * At least 6 clipping plane are supported.
+ * @return the number of available clipping plane.
+ */
+ int getClippingPlaneNumber();
+
+ /**
+ * Return the i-th clipping plane.
+ * {@code null} is returned if i is not a valid index.
+ * @param i the given index.
+ * @return the i-th clipping plane.
+ */
+ ClippingPlane getClippingPlane(int i);
+
+ /**
+ * Disable all clipping plane.
+ */
+ void disableClipping();
+
+ // TODO add an AABB quick call. (with transformation ?)
+}
diff --git a/modules/scirenderer/src/org/scilab/forge/scirenderer/clipping/ClippingPlane.java b/modules/scirenderer/src/org/scilab/forge/scirenderer/clipping/ClippingPlane.java
new file mode 100755
index 000000000..9bf3a9b64
--- /dev/null
+++ b/modules/scirenderer/src/org/scilab/forge/scirenderer/clipping/ClippingPlane.java
@@ -0,0 +1,63 @@
+/*
+ * Scilab ( http://www.scilab.org/ ) - This file is part of Scilab
+ * Copyright (C) 2009-2011 - DIGITEO - Pierre Lando
+ *
+ * This file must be used under the terms of the CeCILL.
+ * This source file is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at
+ * http://www.cecill.info/licences/Licence_CeCILL_V2.1-en.txt
+ */
+
+package org.scilab.forge.scirenderer.clipping;
+
+import org.scilab.forge.scirenderer.tranformations.Transformation;
+import org.scilab.forge.scirenderer.tranformations.Vector4d;
+
+/**
+ * @author Pierre Lando
+ */
+public interface ClippingPlane {
+
+ /**
+ * Return the status of this clipping plane.
+ * @return the status of this clipping plane.
+ */
+ boolean isEnable();
+
+ /**
+ * Set the status of this clipping plane.
+ * @param isEnable new status of this clipping plane.
+ */
+ void setEnable(boolean isEnable);
+
+ /**
+ * Set the clipping plane equation.
+ * @param v the plane coordinate.
+ */
+ void setEquation(Vector4d v);
+
+ /**
+ * Return the plane equation.
+ * @return the plane equation.
+ */
+ Vector4d getEquation();
+
+ /**
+ * Set the coordinate transformation for the plane.
+ * @param transformation the new coordinate transformation for the plane.
+ */
+ void setTransformation(Transformation transformation);
+
+ /**
+ * Return the coordinate transformation for the plane.
+ * @return the coordinate transformation for the plane.
+ */
+ Transformation getTransformation();
+
+ /**
+ * Return the clipping plane index.
+ * @return the clipping plane index.s
+ */
+ int getIndex();
+}
diff --git a/modules/scirenderer/src/org/scilab/forge/scirenderer/data/AbstractDataProvider.java b/modules/scirenderer/src/org/scilab/forge/scirenderer/data/AbstractDataProvider.java
new file mode 100755
index 000000000..34bf7b5c2
--- /dev/null
+++ b/modules/scirenderer/src/org/scilab/forge/scirenderer/data/AbstractDataProvider.java
@@ -0,0 +1,68 @@
+/*
+ * Scilab ( http://www.scilab.org/ ) - This file is part of Scilab
+ * Copyright (C) 2009-2012 - DIGITEO - Pierre Lando
+ *
+ * This file must be used under the terms of the CeCILL.
+ * This source file is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at
+ * http://www.cecill.info/licences/Licence_CeCILL_V2.1-en.txt
+ */
+
+package org.scilab.forge.scirenderer.data;
+
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.Set;
+
+/**
+ * @author Pierre Lando
+ * @param <DataUserType> The type of data user.
+ */
+public abstract class AbstractDataProvider<DataUserType extends DataUser> implements DataProvider<DataUserType> {
+
+ private final Set<DataUserType> users = Collections.synchronizedSet(new HashSet<DataUserType>());
+
+ @Override
+ public final void removeDataUser(DataUserType dataUser) {
+ users.remove(dataUser);
+ }
+
+ @Override
+ public final void addDataUser(DataUserType dataUser) {
+ users.add(dataUser);
+ }
+
+ /**
+ * Notify all registered data users for a data update.
+ */
+ protected final void fireUpdate() {
+ for (DataUserType dataUser : users) {
+ dataUser.dataUpdated();
+ }
+ }
+
+ /**
+ * Convert given value to a byte.
+ * double in [0, 1] are mapped to [0x00, 0xFF].
+ * @param value the given value.
+ * @return the byte corresponding to the given value.
+ */
+ protected byte toByte(double value) {
+ return (byte) (((int) (value * 255)) & 0xFF);
+ }
+
+ /**
+ * Convert given value to a byte.
+ * double in [0, 1] are mapped to [0x00, 0xFF].
+ * @param values the given value.
+ * @return the byte corresponding to the given value.
+ */
+ protected byte[] toByte(float[] values) {
+ byte bytes[] = new byte[values.length];
+ for (int i = 0; i < values.length; i++) {
+ bytes[i] = toByte(values[i]);
+ }
+ return bytes;
+ }
+}
diff --git a/modules/scirenderer/src/org/scilab/forge/scirenderer/data/DataProvider.java b/modules/scirenderer/src/org/scilab/forge/scirenderer/data/DataProvider.java
new file mode 100755
index 000000000..2ebf73cfb
--- /dev/null
+++ b/modules/scirenderer/src/org/scilab/forge/scirenderer/data/DataProvider.java
@@ -0,0 +1,37 @@
+/*
+ * Scilab ( http://www.scilab.org/ ) - This file is part of Scilab
+ * Copyright (C) 2009-2012 - DIGITEO - Pierre Lando
+ *
+ * This file must be used under the terms of the CeCILL.
+ * This source file is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at
+ * http://www.cecill.info/licences/Licence_CeCILL_V2.1-en.txt
+ */
+
+package org.scilab.forge.scirenderer.data;
+
+/**
+ * @author Pierre Lando
+ * @param <DataUserType> The type of data user.
+ */
+public interface DataProvider<DataUserType extends DataUser> {
+
+ /**
+ * Remove a data user.
+ * @param dataUser the data user to remove.
+ */
+ void removeDataUser(DataUserType dataUser);
+
+ /**
+ * Add a data user.
+ * @param texture the data user to add.
+ */
+ void addDataUser(DataUserType texture);
+
+ /**
+ * Data provider validity getter.
+ * @return the validity if this data provider.
+ */
+ boolean isValid();
+}
diff --git a/modules/scirenderer/src/org/scilab/forge/scirenderer/data/DataUser.java b/modules/scirenderer/src/org/scilab/forge/scirenderer/data/DataUser.java
new file mode 100755
index 000000000..7045caafd
--- /dev/null
+++ b/modules/scirenderer/src/org/scilab/forge/scirenderer/data/DataUser.java
@@ -0,0 +1,23 @@
+/*
+ * Scilab ( http://www.scilab.org/ ) - This file is part of Scilab
+ * Copyright (C) 2009-2012 - DIGITEO - Pierre Lando
+ *
+ * This file must be used under the terms of the CeCILL.
+ * This source file is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at
+ * http://www.cecill.info/licences/Licence_CeCILL_V2.1-en.txt
+ */
+
+package org.scilab.forge.scirenderer.data;
+
+/**
+ * @author Pierre Lando
+ */
+public interface DataUser {
+
+ /**
+ * Notify for data update.
+ */
+ void dataUpdated();
+}
diff --git a/modules/scirenderer/src/org/scilab/forge/scirenderer/implementation/g2d/G2DCanvas.java b/modules/scirenderer/src/org/scilab/forge/scirenderer/implementation/g2d/G2DCanvas.java
new file mode 100755
index 000000000..a130a1dca
--- /dev/null
+++ b/modules/scirenderer/src/org/scilab/forge/scirenderer/implementation/g2d/G2DCanvas.java
@@ -0,0 +1,189 @@
+/*
+ * Scilab ( http://www.scilab.org/ ) - This file is part of Scilab
+ * Copyright (C) 2012 - Scilab Enterprises - Calixte DENIZET
+ *
+ * This file must be used under the terms of the CeCILL.
+ * This source file is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at
+ * http://www.cecill.info/licences/Licence_CeCILL_V2.1-en.txt
+ */
+
+package org.scilab.forge.scirenderer.implementation.g2d;
+
+import java.awt.Dimension;
+import java.awt.Graphics2D;
+
+import org.scilab.forge.scirenderer.Canvas;
+import org.scilab.forge.scirenderer.Drawer;
+import org.scilab.forge.scirenderer.DrawingTools;
+import org.scilab.forge.scirenderer.implementation.g2d.buffers.G2DBuffersManager;
+import org.scilab.forge.scirenderer.implementation.g2d.motor.Motor3D;
+import org.scilab.forge.scirenderer.implementation.g2d.renderer.G2DRendererManager;
+import org.scilab.forge.scirenderer.implementation.g2d.texture.G2DTextureManager;
+import org.scilab.forge.scirenderer.picking.PickingManager;
+import org.scilab.forge.scirenderer.picking.PickingTask;
+
+/**
+ * G2D implementation of a Canvas.
+ *
+ * @author Calixte DENIZET
+ */
+public final class G2DCanvas implements Canvas {
+
+ private final G2DDrawingTools drawingTools;
+ private final G2DBuffersManager buffersManager;
+ private final G2DRendererManager rendererManager;
+ private final G2DTextureManager textureManager;
+
+ private final Motor3D motor;
+ private final Dimension dimension;
+
+ private boolean drawEnabled = true;
+
+ /** The anti-aliasing level */
+ private int antiAliasingLevel = 0;
+
+ private static final PickingManager PICKINGMANAGER = new PickingManager() {
+
+ @Override
+ public void addPickingTask(PickingTask pickingTask) { }
+ };
+
+ /**
+ * The current mainDrawer.
+ */
+ private Drawer mainDrawer;
+
+ /**
+ * Default constructor.
+ * @param autoDrawable the G2D autoDrawable this canvas depend on.
+ */
+ G2DCanvas(Graphics2D g2d, int width, int height) {
+ this.dimension = new Dimension(width, height);
+ this.motor = new Motor3D(this, g2d, dimension);
+
+ buffersManager = new G2DBuffersManager();
+ rendererManager = new G2DRendererManager();
+ drawingTools = new G2DDrawingTools(this);
+ motor.setClippingPlanes(drawingTools.getClippingManager().getClippingPlanes());
+ textureManager = new G2DTextureManager(this);
+ }
+
+ public DrawingTools getDrawingTools() {
+ return drawingTools;
+ }
+
+ public void setGraphics(Graphics2D g2d, int width, int height) {
+ this.dimension.width = width;
+ this.dimension.height = height;
+ this.motor.setGraphics(g2d);
+ }
+
+ // Implementation of getter & setter from Canvas.
+
+ @Override
+ public void setMainDrawer(Drawer mainDrawer) {
+ this.mainDrawer = mainDrawer;
+ }
+
+ @Override
+ public Drawer getMainDrawer() {
+ return mainDrawer;
+ }
+
+ @Override
+ public G2DRendererManager getRendererManager() {
+ return rendererManager;
+ }
+
+ @Override
+ public G2DBuffersManager getBuffersManager() {
+ return buffersManager;
+ }
+
+ @Override
+ public PickingManager getPickingManager() {
+ return PICKINGMANAGER;
+ }
+
+ @Override
+ public G2DTextureManager getTextureManager() {
+ return textureManager;
+ }
+
+ @Override
+ public int getWidth() {
+ return dimension.width;
+ }
+
+ @Override
+ public int getHeight() {
+ return dimension.height;
+ }
+
+ @Override
+ public Dimension getDimension() {
+ return dimension;
+ }
+
+ @Override
+ public int getAntiAliasingLevel() {
+ return antiAliasingLevel;
+ }
+
+ @Override
+ public void setAntiAliasingLevel(int antiAliasingLevel) {
+ this.antiAliasingLevel = antiAliasingLevel;
+ }
+
+ @Override
+ public void redraw() {
+ draw();
+ }
+
+ @Override
+ public void redrawAndWait() {
+ redraw();
+ }
+
+ @Override
+ public void waitImage() {
+ }
+
+ // G2DCanvas specific getter.
+
+ public void disableDraw() {
+ drawEnabled = false;
+ }
+
+ public void enableDraw() {
+ drawEnabled = true;
+ }
+
+ public void draw() {
+ if (drawEnabled) {
+ try {
+ mainDrawer.draw(drawingTools);
+ getMotor3D().setAntialiased(antiAliasingLevel != 0);
+ getMotor3D().draw();
+ } catch (Exception e) {
+ System.out.println(e + "::::" + mainDrawer);
+ e.printStackTrace();
+ }
+ }
+ }
+
+ /**
+ * Return the OpenGl context.
+ * @return the OpenGl context.
+ */
+ public Motor3D getMotor3D() {
+ return motor;
+ }
+
+ @Override
+ public void destroy() {
+ getMotor3D().clean();
+ }
+}
diff --git a/modules/scirenderer/src/org/scilab/forge/scirenderer/implementation/g2d/G2DCanvasFactory.java b/modules/scirenderer/src/org/scilab/forge/scirenderer/implementation/g2d/G2DCanvasFactory.java
new file mode 100755
index 000000000..673badec5
--- /dev/null
+++ b/modules/scirenderer/src/org/scilab/forge/scirenderer/implementation/g2d/G2DCanvasFactory.java
@@ -0,0 +1,37 @@
+/*
+ * Scilab ( http://www.scilab.org/ ) - This file is part of Scilab
+ * Copyright (C) 2009-2011 - DIGITEO - Pierre Lando
+ *
+ * This file must be used under the terms of the CeCILL.
+ * This source file is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at
+ * http://www.cecill.info/licences/Licence_CeCILL_V2.1-en.txt
+ */
+
+package org.scilab.forge.scirenderer.implementation.g2d;
+
+import java.awt.Graphics2D;
+
+/**
+ * @author Pierre Lando
+ */
+public final class G2DCanvasFactory {
+
+ /**
+ * Private constructor.
+ * This is an utility class.
+ */
+ private G2DCanvasFactory() {
+
+ }
+
+ /**
+ * Create a canvas from an auto drawable object.
+ * @param autoDrawable the auto drawable object.
+ * @return a canvas based on the given auto drawable object.
+ */
+ public static G2DCanvas createCanvas(Graphics2D g2d, int width, int height) {
+ return new G2DCanvas(g2d, width, height);
+ }
+}
diff --git a/modules/scirenderer/src/org/scilab/forge/scirenderer/implementation/g2d/G2DDrawingTools.java b/modules/scirenderer/src/org/scilab/forge/scirenderer/implementation/g2d/G2DDrawingTools.java
new file mode 100755
index 000000000..c8594150c
--- /dev/null
+++ b/modules/scirenderer/src/org/scilab/forge/scirenderer/implementation/g2d/G2DDrawingTools.java
@@ -0,0 +1,147 @@
+/*
+ * Scilab ( http://www.scilab.org/ ) - This file is part of Scilab
+ * Copyright (C) 2012 - Scilab Enterprises - Calixte DENIZET
+ *
+ * This file must be used under the terms of the CeCILL.
+ * This source file is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at
+ * http://www.cecill.info/licences/Licence_CeCILL_V2.1-en.txt
+ */
+
+package org.scilab.forge.scirenderer.implementation.g2d;
+
+import org.scilab.forge.scirenderer.DrawingTools;
+import org.scilab.forge.scirenderer.SciRendererException;
+import org.scilab.forge.scirenderer.buffers.ElementsBuffer;
+import org.scilab.forge.scirenderer.lightning.LightManager;
+import org.scilab.forge.scirenderer.renderer.Renderer;
+import org.scilab.forge.scirenderer.shapes.appearance.Appearance;
+import org.scilab.forge.scirenderer.shapes.appearance.Color;
+import org.scilab.forge.scirenderer.shapes.geometry.Geometry;
+import org.scilab.forge.scirenderer.texture.AnchorPosition;
+import org.scilab.forge.scirenderer.texture.Texture;
+import org.scilab.forge.scirenderer.tranformations.TransformationManager;
+import org.scilab.forge.scirenderer.tranformations.TransformationManagerImpl;
+import org.scilab.forge.scirenderer.tranformations.TransformationManagerListener;
+import org.scilab.forge.scirenderer.tranformations.Vector3d;
+
+import org.scilab.forge.scirenderer.implementation.g2d.G2DCanvas;
+import org.scilab.forge.scirenderer.implementation.g2d.clipping.G2DClippingManager;
+import org.scilab.forge.scirenderer.implementation.g2d.motor.Motor3D;
+import org.scilab.forge.scirenderer.implementation.g2d.lighting.G2DLightManager;
+
+/**
+ *
+ * JoGl implementation of the DrawingTools.
+ *
+ * @author Calixte DENIZET
+ */
+public class G2DDrawingTools implements DrawingTools {
+
+ private final TransformationManager transformationManager;
+ private final G2DLightManager lightManager;
+ private final G2DClippingManager clippingManager;
+ private final G2DCanvas g2dCanvas;
+
+ /**
+ * Default constructor.
+ * @param canvas the canvas where this drawing tools live.
+ */
+ G2DDrawingTools(G2DCanvas canvas) {
+ this.transformationManager = new TransformationManagerImpl(canvas);
+ this.lightManager = new G2DLightManager(this);
+ this.clippingManager = new G2DClippingManager(this);
+ this.g2dCanvas = canvas;
+
+ transformationManager.addListener(new TransformationManagerListener() {
+ @Override
+ public void transformationChanged(TransformationManager transformationManager) {
+ if (transformationManager.isUsingSceneCoordinate()) {
+ g2dCanvas.getMotor3D().setTransformation(transformationManager.getG2DProjection(), transformationManager.getG2DSingleProjection());
+ } else {
+ g2dCanvas.getMotor3D().setTransformation(transformationManager.getG2DWindowProjection(), transformationManager.getG2DSingleProjection());
+ }
+ }
+ });
+ }
+
+ public Motor3D getMotor3D() {
+ return g2dCanvas.getMotor3D();
+ }
+
+ @Override
+ public G2DCanvas getCanvas() {
+ return g2dCanvas;
+ }
+
+ @Override
+ public TransformationManager getTransformationManager() {
+ return transformationManager;
+ }
+
+ @Override
+ public LightManager getLightManager() {
+ return lightManager;
+ }
+
+ @Override
+ public G2DClippingManager getClippingManager() {
+ return clippingManager;
+ }
+
+ @Override
+ public void clear(Color color) {
+ g2dCanvas.getMotor3D().reset(color);
+ }
+
+ @Override
+ public void clear(java.awt.Color color) {
+ g2dCanvas.getMotor3D().reset(color);
+ }
+
+ @Override
+ public void clearDepthBuffer() {
+ g2dCanvas.getMotor3D().clearDepth();
+ }
+
+ @Override
+ public void draw(Renderer renderer) {
+ g2dCanvas.getRendererManager().draw(this, renderer);
+ }
+
+ @Override
+ public void draw(Geometry geometry) throws SciRendererException {
+ g2dCanvas.getMotor3D().draw(this, geometry, Appearance.getDefault());
+ }
+
+ @Override
+ public void draw(Geometry geometry, Appearance appearance) throws SciRendererException {
+ g2dCanvas.getMotor3D().draw(this, geometry, appearance);
+ }
+
+ @Override
+ public void draw(Texture texture) throws SciRendererException {
+ g2dCanvas.getTextureManager().draw(this, texture);
+ }
+
+ @Override
+ public void draw(Texture texture, AnchorPosition anchor, ElementsBuffer positions) {
+ g2dCanvas.getMotor3D().draw(this, texture, anchor, positions, 0, 1, 0);
+ }
+
+ @Override
+ public void draw(Texture texture, AnchorPosition anchor, ElementsBuffer positions, int offset, int stride, double rotationAngle) {
+ g2dCanvas.getMotor3D().draw(this, texture, anchor, positions, offset, stride, rotationAngle);
+ }
+
+ @Override
+ public void draw(Texture texture, AnchorPosition anchor, Vector3d position) {
+ g2dCanvas.getMotor3D().draw(this, texture, anchor, position, 0);
+ }
+
+ @Override
+ public void draw(Texture texture, AnchorPosition anchor, Vector3d position, double rotationAngle) {
+ g2dCanvas.getMotor3D().draw(this, texture, anchor, position, rotationAngle);
+ }
+}
diff --git a/modules/scirenderer/src/org/scilab/forge/scirenderer/implementation/g2d/buffers/G2DBuffersManager.java b/modules/scirenderer/src/org/scilab/forge/scirenderer/implementation/g2d/buffers/G2DBuffersManager.java
new file mode 100755
index 000000000..00dbec8cf
--- /dev/null
+++ b/modules/scirenderer/src/org/scilab/forge/scirenderer/implementation/g2d/buffers/G2DBuffersManager.java
@@ -0,0 +1,111 @@
+/*
+ * Scilab ( http://www.scilab.org/ ) - This file is part of Scilab
+ * Copyright (C) 2009-2011 - DIGITEO - Pierre Lando
+ *
+ * This file must be used under the terms of the CeCILL.
+ * This source file is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at
+ * http://www.cecill.info/licences/Licence_CeCILL_V2.1-en.txt
+ */
+
+package org.scilab.forge.scirenderer.implementation.g2d.buffers;
+
+import org.scilab.forge.scirenderer.buffers.BuffersManager;
+import org.scilab.forge.scirenderer.buffers.DataBuffer;
+import org.scilab.forge.scirenderer.buffers.ElementsBuffer;
+import org.scilab.forge.scirenderer.buffers.IndicesBuffer;
+
+import java.util.Collection;
+import java.util.HashSet;
+import java.util.Set;
+
+/**
+ * @author Pierre Lando
+ */
+public final class G2DBuffersManager implements BuffersManager {
+
+ /**
+ * Set off current buffers.
+ */
+ private final Set<DataBuffer> buffers = new HashSet<DataBuffer>();
+
+ // todo : est ce utile d'avoir buffers... pourquoi garder une reference la-dessus
+ // peut etre pr savoir qu'un buffer vient de ce manager et pas d'un autre.
+
+ /**
+ * Default constructor.
+ */
+ public G2DBuffersManager() {
+ }
+
+ @Override
+ public ElementsBuffer createElementsBuffer() {
+ G2DElementsBuffer newBuffer = new G2DElementsBuffer();
+ buffers.add(newBuffer);
+ return newBuffer;
+ }
+
+ @Override
+ public IndicesBuffer createIndicesBuffer() {
+ G2DIndicesBuffer newBuffer = new G2DIndicesBuffer();
+ buffers.add(newBuffer);
+ return newBuffer;
+ }
+
+ @Override
+ public void dispose(DataBuffer buffer) {
+ DataBuffer localBuffer = getLocalBuffer(buffer);
+ if (localBuffer != null) {
+ localBuffer.clear();
+ buffers.remove(localBuffer);
+ }
+ }
+
+ @Override
+ public void dispose(Collection <? extends DataBuffer > buffers) {
+ for (DataBuffer buffer : buffers) {
+ dispose(buffer);
+ }
+ }
+
+ /**
+ * This method check buffer to be from here.
+ * @param buffer the given buffer.
+ * @return the G2D instance of the buffer.
+ */
+ private DataBuffer getLocalBuffer(DataBuffer buffer) {
+ if (buffers.contains(buffer)) {
+ return buffer;
+ }
+
+ return null;
+ }
+
+
+ /**
+ * This method check buffer to be from here.
+ * @param buffer the given buffer.
+ * @return the G2D instance of the buffer.
+ */
+ private IndicesBuffer getLocalIndicesBuffer(IndicesBuffer buffer) {
+ if (buffer instanceof G2DIndicesBuffer && buffers.contains(buffer)) {
+ return buffer;
+ }
+
+ return null;
+ }
+
+ /**
+ * This method check buffer to be from here.
+ * @param buffer the given buffer.
+ * @return the G2D instance of the buffer.
+ */
+ private ElementsBuffer getLocalElementsBuffer(ElementsBuffer buffer) {
+ if (buffer instanceof G2DElementsBuffer && buffers.contains(buffer)) {
+ return buffer;
+ }
+
+ return null;
+ }
+}
diff --git a/modules/scirenderer/src/org/scilab/forge/scirenderer/implementation/g2d/buffers/G2DElementsBuffer.java b/modules/scirenderer/src/org/scilab/forge/scirenderer/implementation/g2d/buffers/G2DElementsBuffer.java
new file mode 100755
index 000000000..d8f0e17f3
--- /dev/null
+++ b/modules/scirenderer/src/org/scilab/forge/scirenderer/implementation/g2d/buffers/G2DElementsBuffer.java
@@ -0,0 +1,209 @@
+/*
+ * Scilab ( http://www.scilab.org/ ) - This file is part of Scilab
+ * Copyright (C) 2012 - ScilabEnterprises - Calixte DENIZET
+ *
+ * This file must be used under the terms of the CeCILL.
+ * This source file is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at
+ * http://www.cecill.info/licences/Licence_CeCILL_V2.1-en.txt
+ */
+
+package org.scilab.forge.scirenderer.implementation.g2d.buffers;
+
+import org.scilab.forge.scirenderer.buffers.DataBuffer;
+import org.scilab.forge.scirenderer.buffers.ElementsBuffer;
+
+import java.nio.FloatBuffer;
+
+/**
+ * @author Calixte DENIZET
+ */
+@SuppressWarnings(value = { "serial" })
+public class G2DElementsBuffer implements DataBuffer, ElementsBuffer {
+
+ /**
+ * The current size of one element.
+ */
+ public static final int ELEMENT_SIZE = 4;
+
+ /**
+ * The default vertex.
+ */
+ private static final float[] DEFAULT_VERTEX = new float[] {0, 0, 0, 1};
+
+ /**
+ * the data this buffer contain.
+ */
+ private FloatBuffer data;
+ private final Object mutex;
+
+ /**
+ * Default constructor.
+ * The constructor is package : only {@link G2DBuffersManager} can instantiate this object.
+ */
+ G2DElementsBuffer() {
+ mutex = new Object();
+ data = null;
+ }
+
+ @Override
+ public void setData(float[] newData, int elementSize) {
+ // Check the given vertex size
+ if ((elementSize < 1) || (elementSize > ELEMENT_SIZE)) {
+ throw new BadElementSizeException(elementSize, 1, ELEMENT_SIZE);
+ }
+
+ int verticesNumber = newData.length / elementSize;
+ //FloatBuffer buffer = BufferUtil.newFloatBuffer(ELEMENT_SIZE * verticesNumber);
+ FloatBuffer buffer = FloatBuffer.allocate(ELEMENT_SIZE * verticesNumber);
+ buffer.rewind();
+
+
+ // Fill buffer with given data.
+ // Missing coordinate are filled with the 'DEFAULT_VERTEX' ones.
+ int k = 0;
+ for (int i = 0; i < verticesNumber; i++) {
+ for (int j = 0; j < ELEMENT_SIZE; j++) {
+ if (j < elementSize) {
+ buffer.put(newData[k++]);
+ } else {
+ buffer.put(DEFAULT_VERTEX[j]);
+ }
+ }
+ }
+
+ buffer.rewind();
+ setData(buffer);
+ }
+
+ @Override
+ public void setData(Float[] newData, int elementSize) {
+
+ // Check the given vertex size
+ if ((elementSize < 1) || (elementSize > ELEMENT_SIZE)) {
+ throw new BadElementSizeException(elementSize, 1, ELEMENT_SIZE);
+ }
+
+ int verticesNumber = newData.length / elementSize;
+ //FloatBuffer buffer = BufferUtil.newFloatBuffer(ELEMENT_SIZE * verticesNumber);
+ FloatBuffer buffer = FloatBuffer.allocate(ELEMENT_SIZE * verticesNumber);
+ buffer.rewind();
+
+
+ // Fill buffer with given data.
+ // Missing coordinate are filled with the 'DEFAULT_VERTEX' ones.
+ int k = 0;
+ for (int i = 0; i < verticesNumber; i++) {
+ for (int j = 0; j < ELEMENT_SIZE; j++) {
+ if (j < elementSize) {
+ buffer.put(newData[k++]);
+ } else {
+ buffer.put(DEFAULT_VERTEX[j]);
+ }
+ }
+ }
+
+ buffer.rewind();
+ setData(buffer);
+ }
+
+ @Override
+ public void setData(FloatBuffer newData, int elementsSize) {
+ // Check the given vertex size
+ if ((elementsSize < 1) || (elementsSize > ELEMENT_SIZE)) {
+ throw new BadElementSizeException(elementsSize, 1, ELEMENT_SIZE);
+ }
+
+ if (elementsSize == 4) {
+ // No need to complete buffer.
+ if (newData != null) {
+ newData.rewind();
+ }
+ setData(newData);
+ return;
+ }
+
+ int verticesNumber = newData.limit() / elementsSize;
+ //FloatBuffer buffer = BufferUtil.newFloatBuffer(ELEMENT_SIZE * verticesNumber);
+ FloatBuffer buffer = FloatBuffer.allocate(ELEMENT_SIZE * verticesNumber);
+ buffer.rewind();
+
+ // Fill buffer with given data.
+ // Missing coordinate are filled with the 'DEFAULT_VERTEX' ones.
+ newData.rewind();
+ for (int i = 0; i < verticesNumber; i++) {
+ for (int j = 0; j < ELEMENT_SIZE; j++) {
+ if (j < elementsSize) {
+ buffer.put(newData.get());
+ } else {
+ buffer.put(DEFAULT_VERTEX[j]);
+ }
+ }
+ }
+
+ buffer.rewind();
+ setData(buffer);
+ }
+
+ @Override
+ public int getSize() {
+ synchronized (mutex) {
+ if (data == null) {
+ return 0;
+ } else {
+ return data.limit() / ELEMENT_SIZE;
+ }
+ }
+ }
+
+ @Override
+ public int getElementsSize() {
+ return ELEMENT_SIZE;
+ }
+
+ @Override
+ public FloatBuffer getData() {
+ synchronized (mutex) {
+ if (data != null) {
+ return data;
+ } else {
+ return null;
+ }
+ }
+ }
+
+ /**
+ * Really set the data.
+ * @param data the new data.
+ */
+ private void setData(FloatBuffer data) {
+ synchronized (mutex) {
+ this.data = data;
+ }
+ }
+
+ /**
+ * A specific runtime exception for bad elements size.
+ */
+ private static class BadElementSizeException extends RuntimeException {
+
+ /**
+ * Default constructor.
+ * @param size the size given for elements.
+ * @param min the minimum possible size.
+ * @param max the upper bound of possible size (excluded of possible size).
+ */
+ public BadElementSizeException(int size, int min, int max) {
+ super("Bad vertex elements size : " + size + ". Should be in [" + min + ", " + (max - 1) + "]");
+ }
+ }
+
+ @Override
+ public void clear() {
+ if (data != null) {
+ data.clear();
+ }
+ data = null;
+ }
+}
diff --git a/modules/scirenderer/src/org/scilab/forge/scirenderer/implementation/g2d/buffers/G2DIndicesBuffer.java b/modules/scirenderer/src/org/scilab/forge/scirenderer/implementation/g2d/buffers/G2DIndicesBuffer.java
new file mode 100755
index 000000000..9504c2937
--- /dev/null
+++ b/modules/scirenderer/src/org/scilab/forge/scirenderer/implementation/g2d/buffers/G2DIndicesBuffer.java
@@ -0,0 +1,89 @@
+/*
+ * Scilab ( http://www.scilab.org/ ) - This file is part of Scilab
+ * Copyright (C) 2012 - Scilab Enterprises - Calixte DENIZET
+ *
+ * This file must be used under the terms of the CeCILL.
+ * This source file is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at
+ * http://www.cecill.info/licences/Licence_CeCILL_V2.1-en.txt
+ */
+
+package org.scilab.forge.scirenderer.implementation.g2d.buffers;
+
+import org.scilab.forge.scirenderer.buffers.DataBuffer;
+import org.scilab.forge.scirenderer.buffers.IndicesBuffer;
+
+import java.nio.IntBuffer;
+import java.util.Collection;
+
+/**
+ * @author Calixte DENIZET
+ */
+public class G2DIndicesBuffer implements IndicesBuffer, DataBuffer {
+
+ /**
+ * the data this buffer contain.
+ */
+ private IntBuffer data;
+
+ /**
+ * Default constructor.
+ * The constructor is package : only {@link G2DBuffersManager} can instantiate this object.
+ */
+ G2DIndicesBuffer() {
+ data = null;
+ }
+
+ @Override
+ public void setData(int[] indices) {
+ //IntBuffer buffer = BufferUtil.newIntBuffer(indices.length);
+ IntBuffer buffer = IntBuffer.allocate(indices.length);
+ buffer.rewind();
+ buffer.put(indices);
+ buffer.rewind();
+ this.data = buffer;
+ }
+
+ @Override
+ public void setData(Collection<Integer> indices) {
+ IntBuffer buffer = IntBuffer.allocate(indices.size());
+ buffer.rewind();
+ for (int index : indices) {
+ buffer.put(index);
+ }
+ buffer.rewind();
+ this.data = buffer;
+ }
+
+ @Override
+ public void setData(IntBuffer indexBuffer) {
+ //IntBuffer buffer = BufferUtil.newIntBuffer(indexBuffer.limit());
+ IntBuffer buffer = IntBuffer.allocate(indexBuffer.limit());
+ buffer.rewind();
+ indexBuffer.rewind();
+ buffer.put(indexBuffer);
+ buffer.rewind();
+ indexBuffer.rewind();
+ this.data = buffer;
+ }
+
+ @Override
+ public int getSize() {
+ if (data == null) {
+ return 0;
+ } else {
+ return data.limit();
+ }
+ }
+
+ @Override
+ public IntBuffer getData() {
+ return data.asReadOnlyBuffer();
+ }
+
+ public void clear() {
+ data.clear();
+ data = null;
+ }
+}
diff --git a/modules/scirenderer/src/org/scilab/forge/scirenderer/implementation/g2d/clipping/G2DClippingManager.java b/modules/scirenderer/src/org/scilab/forge/scirenderer/implementation/g2d/clipping/G2DClippingManager.java
new file mode 100755
index 000000000..2dbaa0b2f
--- /dev/null
+++ b/modules/scirenderer/src/org/scilab/forge/scirenderer/implementation/g2d/clipping/G2DClippingManager.java
@@ -0,0 +1,74 @@
+/*
+ * Scilab ( http://www.scilab.org/ ) - This file is part of Scilab
+ * Copyright (C) 2011-2012 - Scilab Enterprises - Calixte DENIZET
+ *
+ * This file must be used under the terms of the CeCILL.
+ * This source file is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at
+ * http://www.cecill.info/licences/Licence_CeCILL_V2.1-en.txt
+ */
+
+package org.scilab.forge.scirenderer.implementation.g2d.clipping;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.scilab.forge.scirenderer.clipping.ClippingManager;
+import org.scilab.forge.scirenderer.clipping.ClippingPlane;
+import org.scilab.forge.scirenderer.implementation.g2d.G2DDrawingTools;
+
+/**
+ * @author Calixte DENIZET
+ */
+public class G2DClippingManager implements ClippingManager {
+
+ /**
+ * Used drawing tools.
+ */
+ private final G2DDrawingTools drawingTools;
+
+ /**
+ * Clipping planes array.
+ */
+ private final List<ClippingPlane> clippingPlanes;
+
+ /**
+ * Default constructor.
+ * @param drawingTools used drawing tools.
+ */
+ public G2DClippingManager(G2DDrawingTools drawingTools) {
+ this.drawingTools = drawingTools;
+ this.clippingPlanes = new ArrayList<ClippingPlane>(6);
+ }
+
+ public List<ClippingPlane> getClippingPlanes() {
+ return clippingPlanes;
+ }
+
+ @Override
+ public int getClippingPlaneNumber() {
+ return Integer.MAX_VALUE;
+ }
+
+ @Override
+ public ClippingPlane getClippingPlane(int i) {
+ if (i < 0 || i >= getClippingPlaneNumber()) {
+ return null;
+ } else {
+ if (i >= clippingPlanes.size() || clippingPlanes.get(i) == null) {
+ clippingPlanes.add(i, new G2DClippingPlane(i, drawingTools));
+ }
+ return clippingPlanes.get(i);
+ }
+ }
+
+ @Override
+ public void disableClipping() {
+ for (ClippingPlane clippingPlane : clippingPlanes) {
+ if (clippingPlane != null) {
+ clippingPlane.setEnable(false);
+ }
+ }
+ }
+}
diff --git a/modules/scirenderer/src/org/scilab/forge/scirenderer/implementation/g2d/clipping/G2DClippingPlane.java b/modules/scirenderer/src/org/scilab/forge/scirenderer/implementation/g2d/clipping/G2DClippingPlane.java
new file mode 100755
index 000000000..134aa2f3a
--- /dev/null
+++ b/modules/scirenderer/src/org/scilab/forge/scirenderer/implementation/g2d/clipping/G2DClippingPlane.java
@@ -0,0 +1,109 @@
+/*
+ * Scilab ( http://www.scilab.org/ ) - This file is part of Scilab
+ * Copyright (C) 2009-2011 - DIGITEO - Pierre Lando
+ *
+ * This file must be used under the terms of the CeCILL.
+ * This source file is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at
+ * http://www.cecill.info/licences/Licence_CeCILL_V2.1-en.txt
+ */
+
+package org.scilab.forge.scirenderer.implementation.g2d.clipping;
+
+import org.scilab.forge.scirenderer.clipping.ClippingPlane;
+import org.scilab.forge.scirenderer.tranformations.Transformation;
+import org.scilab.forge.scirenderer.tranformations.TransformationFactory;
+import org.scilab.forge.scirenderer.tranformations.Vector4d;
+import org.scilab.forge.scirenderer.implementation.g2d.G2DDrawingTools;
+
+/**
+ * @author Pierre Lando
+ */
+public class G2DClippingPlane implements ClippingPlane {
+
+ /**
+ * GL index of this clipping plane.
+ */
+ private final int index;
+
+ /**
+ * Clipping plane enabled status.
+ */
+ private boolean isEnable;
+
+ private G2DDrawingTools drawingTools;
+
+ /**
+ * Clipping plane equation look like: {@code x*a + y*b + z*c + d = 0}.
+ * Where {@code equation} is {@code [a, b, c, d]}.
+ */
+ private Vector4d equation = new Vector4d(0, 0, 0, 0);
+ private Vector4d projectedEquation = new Vector4d(0, 0, 0, 0);
+ private Transformation transformation = TransformationFactory.getIdentity();
+ private Transformation projectionTransf;
+ private boolean updated;
+
+ /**
+ * Default constructor.
+ * @param index the id of this clipping plane.
+ */
+ public G2DClippingPlane(int index, G2DDrawingTools drawingTools) {
+ this.isEnable = false;
+ this.index = index;
+ this.drawingTools = drawingTools;
+ }
+
+ @Override
+ public boolean isEnable() {
+ return isEnable;
+ }
+
+ @Override
+ public void setEnable(boolean isEnable) {
+ this.isEnable = isEnable;
+ }
+
+ @Override
+ public void setEquation(Vector4d v) {
+ Transformation t = drawingTools.getTransformationManager().getModelViewStack().peek();
+ if (t != null) {
+ equation = getTransformedEquation(v, t);
+ }
+ }
+
+ @Override
+ public Vector4d getEquation() {
+ Transformation t = drawingTools.getMotor3D().getCurrentSingleTransformation();
+ if (t != null && projectionTransf != t) {
+ projectionTransf = t;
+ projectedEquation = getTransformedEquation(equation, t);
+ }
+
+ return projectedEquation;
+ }
+
+ @Override
+ public void setTransformation(Transformation transformation) { }
+
+ @Override
+ public Transformation getTransformation() {
+ return transformation;
+ }
+
+ @Override
+ public int getIndex() {
+ return index;
+ }
+
+ private static final Vector4d getTransformedEquation(Vector4d equation, Transformation transf) {
+ double[] matrix = transf.getInverseTransformation().getMatrix();
+ double[] v = equation.getData();
+ double x = matrix[0] * v[0] + matrix[1] * v[1] + matrix[2] * v[2] + matrix[3] * v[3];
+ double y = matrix[4] * v[0] + matrix[5] * v[1] + matrix[6] * v[2] + matrix[7] * v[3];
+ double z = matrix[8] * v[0] + matrix[9] * v[1] + matrix[10] * v[2] + matrix[11] * v[3];
+ double w = matrix[12] * v[0] + matrix[13] * v[1] + matrix[14] * v[2] + matrix[15] * v[3];
+
+ return new Vector4d(x, y, z, w);
+ }
+}
diff --git a/modules/scirenderer/src/org/scilab/forge/scirenderer/implementation/g2d/lighting/G2DLight.java b/modules/scirenderer/src/org/scilab/forge/scirenderer/implementation/g2d/lighting/G2DLight.java
new file mode 100755
index 000000000..b983fff49
--- /dev/null
+++ b/modules/scirenderer/src/org/scilab/forge/scirenderer/implementation/g2d/lighting/G2DLight.java
@@ -0,0 +1,144 @@
+/*
+ * Scilab ( http://www.scilab.org/ ) - This file is part of Scilab
+ * Copyright (C) 2013 - Pedro SOUZA
+ *
+ * This file must be used under the terms of the CeCILL.
+ * This source file is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at
+ * http://www.cecill.info/licences/Licence_CeCILL_V2.1-en.txt
+ */
+
+package org.scilab.forge.scirenderer.implementation.g2d.lighting;
+
+
+import org.scilab.forge.scirenderer.lightning.Light;
+import org.scilab.forge.scirenderer.shapes.appearance.Color;
+import org.scilab.forge.scirenderer.tranformations.Vector3d;
+
+/**
+ * @author Pedro SOUZA
+ */
+public class G2DLight implements Light {
+
+ private int index;
+ private boolean isEnable;
+ private Color ambientColor = new Color(0, 0, 0);
+ private Color diffuseColor = new Color(0, 0, 0);
+ private Color specularColor = new Color(0, 0, 0);
+ private Vector3d position = new Vector3d(0, 0, 0);
+ private Vector3d spotDirection = new Vector3d(0, 0, -1);
+ private Vector3d direction = new Vector3d(0, 0, 0);
+ private float spotAngle = 180;
+ private boolean isDirectional = false;
+
+
+ public G2DLight(int index) {
+ this.index = index;
+ }
+
+ @Override
+ public boolean isEnable() {
+ return isEnable;
+ }
+
+ @Override
+ public void setEnable(boolean enable) {
+ if (enable != isEnable) {
+ isEnable = enable;
+ }
+ }
+
+ @Override
+ public Color getAmbientColor() {
+ return ambientColor;
+ }
+
+ @Override
+ public void setAmbientColor(Color color) {
+ if (color != null) {
+ ambientColor = color;
+ }
+ }
+
+ @Override
+ public Color getDiffuseColor() {
+ return diffuseColor;
+ }
+
+ @Override
+ public void setDiffuseColor(Color color) {
+ if (color != null) {
+ diffuseColor = color;
+ }
+ }
+
+ @Override
+ public Color getSpecularColor() {
+ return specularColor;
+ }
+
+ @Override
+ public void setSpecularColor(Color color) {
+ if (color != null) {
+ specularColor = color;
+ }
+ }
+
+ @Override
+ public Vector3d getPosition() {
+ return position;
+ }
+
+ @Override
+ public void setPosition(Vector3d position) {
+ if (position != null) {
+ isDirectional = false;
+ this.position = position;
+ }
+ }
+
+ public Vector3d getDirection() {
+ return direction;
+ }
+
+ public void setDirection(Vector3d direction) {
+ if (direction != null) {
+ isDirectional = true;
+ this.direction = direction.getNormalized();
+ }
+ }
+
+ @Override
+ public Vector3d getSpotDirection() {
+ return spotDirection;
+ }
+
+ @Override
+ public void setSpotDirection(Vector3d spotDirection) {
+ if (spotDirection != null) {
+ this.spotDirection = spotDirection;
+ }
+ }
+
+ @Override
+ public float getSpotAngle() {
+ return spotAngle;
+ }
+
+ @Override
+ public void setSpotAngle(float angle) {
+ if (angle != spotAngle) {
+ spotAngle = angle;
+ }
+ }
+
+ @Override
+ public int getIndex() {
+ return index;
+ }
+
+ public boolean isPoint() {
+ return !isDirectional;
+ }
+}
diff --git a/modules/scirenderer/src/org/scilab/forge/scirenderer/implementation/g2d/lighting/G2DLightManager.java b/modules/scirenderer/src/org/scilab/forge/scirenderer/implementation/g2d/lighting/G2DLightManager.java
new file mode 100755
index 000000000..c8315edff
--- /dev/null
+++ b/modules/scirenderer/src/org/scilab/forge/scirenderer/implementation/g2d/lighting/G2DLightManager.java
@@ -0,0 +1,140 @@
+/*
+ * Scilab ( http://www.scilab.org/ ) - This file is part of Scilab
+ * Copyright (C) 2013 - Pedro SOUZA
+ *
+ * This file must be used under the terms of the CeCILL.
+ * This source file is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at
+ * http://www.cecill.info/licences/Licence_CeCILL_V2.1-en.txt
+ */
+
+package org.scilab.forge.scirenderer.implementation.g2d.lighting;
+
+import org.scilab.forge.scirenderer.lightning.Light;
+import org.scilab.forge.scirenderer.lightning.LightManager;
+import org.scilab.forge.scirenderer.shapes.appearance.Material;
+import org.scilab.forge.scirenderer.implementation.g2d.G2DDrawingTools;
+import org.scilab.forge.scirenderer.tranformations.Transformation;
+import org.scilab.forge.scirenderer.tranformations.Vector3f;
+
+
+
+/**
+ * @author Pedro SOUZA
+ */
+public class G2DLightManager implements LightManager {
+
+ /**
+ * The drawing tools.
+ */
+ private final G2DDrawingTools drawingTools;
+
+ /**
+ * The lights.
+ */
+ private final G2DLight[] lights;
+
+ /**
+ * The current lightning status.
+ */
+ private boolean isLightningEnable = DEFAULT_LIGHTNING_STATUS;
+
+ private Material material;
+
+ /**
+ * Default constructor.
+ * @param drawingTools the drawing tools.
+ */
+ public G2DLightManager(G2DDrawingTools drawingTools) {
+ this.drawingTools = drawingTools;
+ lights = new G2DLight[getLightNumber()];
+ }
+
+ @Override
+ public int getLightNumber() {
+ return 16;
+ }
+
+ @Override
+ public Light getLight(int i) {
+ if (i < 0 || i >= getLightNumber()) {
+ return null;
+ } else {
+ if (lights[i] == null) {
+ lights[i] = new G2DLight(i);
+ }
+ return lights[i];
+ }
+ }
+
+ @Override
+ public void setLightningEnable(boolean isLightningEnable) {
+ this.isLightningEnable = isLightningEnable;
+ }
+
+ @Override
+ public boolean isLightningEnable() {
+ return isLightningEnable;
+ }
+
+ @Override
+ public void setMaterial(Material material) {
+ this.material = material;
+ }
+
+ public Material getMaterial() {
+ return material;
+ }
+
+ /**
+ * Returns the camera position used to perform the lighting.
+ */
+ public Vector3f getCameraPosition() {
+ double[] m = drawingTools.getTransformationManager().getTransformation().getMatrix();
+ //extract the translation of the matrix
+ return new Vector3f((float)m[12], (float)m[13], (float)m[14]);
+ }
+
+ /**
+ * Returns the vertex transformation as a float array.
+ */
+ public float[] getVertexTransform() {
+ float[] ret = new float[16];
+ double[] m = drawingTools.getTransformationManager().getTransformation().getMatrix();
+ for (int i = 0; i < 16; ++i) {
+ ret[i] = (float)m[i];
+ }
+ return ret;
+ }
+
+ /**
+ * Returns the normal transformation as a float array.
+ * The normal transformation is defined as the inverse transpose
+ * of the vertex transformation.
+ */
+ public float[] getNormalTransform() {
+ float[] ret = new float[16];
+ double[] m = drawingTools.getTransformationManager().getTransformation().getInverseTransformation().getMatrix();
+
+ //only the top 3x3 matrix is used.
+ ret[0] = (float)m[0];
+ ret[4] = (float)m[1];
+ ret[8] = (float)m[2];
+ ret[12] = 0.f;
+ ret[1] = (float)m[4];
+ ret[5] = (float)m[5];
+ ret[9] = (float)m[6];
+ ret[13] = 0.f;
+ ret[2] = (float)m[8];
+ ret[6] = (float)m[9];
+ ret[10] = (float)m[10];
+ ret[14] = 0.f;
+ ret[3] = 0.f;
+ ret[7] = 0.f;
+ ret[11] = 0.f;
+ ret[15] = 1.f;
+
+ return ret;
+ }
+}
diff --git a/modules/scirenderer/src/org/scilab/forge/scirenderer/implementation/g2d/motor/AbstractDrawable3DObject.java b/modules/scirenderer/src/org/scilab/forge/scirenderer/implementation/g2d/motor/AbstractDrawable3DObject.java
new file mode 100755
index 000000000..47117feb4
--- /dev/null
+++ b/modules/scirenderer/src/org/scilab/forge/scirenderer/implementation/g2d/motor/AbstractDrawable3DObject.java
@@ -0,0 +1,426 @@
+/*
+ * Scilab ( http://www.scilab.org/ ) - This file is part of Scilab
+ * Copyright (C) 2012 - Scilab Enterprises - Calixte Denizet
+ *
+ * This file must be used under the terms of the CeCILL.
+ * This source file is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at
+ * http://www.cecill.info/licences/Licence_CeCILL_V2.1-en.txt
+ */
+
+package org.scilab.forge.scirenderer.implementation.g2d.motor;
+
+import java.awt.Color;
+import java.awt.Graphics2D;
+import java.awt.Shape;
+import java.awt.geom.Path2D;
+import java.awt.geom.Rectangle2D;
+import java.util.HashSet;
+import java.util.Set;
+
+import org.scilab.forge.scirenderer.tranformations.Vector3d;
+
+/**
+ * @author Calixte DENIZET
+ */
+public abstract class AbstractDrawable3DObject {
+
+ public static final double PRECISION = 1e-8;
+
+ private static int defaultPrecedence = 0;
+
+ protected final Vector3d[] vertices;
+ protected final Color[] colors;
+ protected final Color color;
+
+ protected int precedence;
+ protected Vector3d v0;
+ protected Vector3d v1;
+ protected Vector3d v0v1;
+ protected double nv0v1;
+ protected Vector3d normal;
+ protected BoundingBox bbox;
+
+ /**
+ * Default constructor
+ * @param vertices the vertices
+ */
+ public AbstractDrawable3DObject(Vector3d[] vertices, Color[] colors) throws InvalidPolygonException {
+ if (vertices == null || vertices.length == 0) {
+ throw new InvalidPolygonException("Invalid 3D Object: no vertices was given");
+ }
+ this.vertices = vertices;
+ if (colors != null && AbstractDrawable3DObject.isMonochromatic(colors)) {
+ this.color = colors[0];
+ this.colors = null;
+ } else {
+ this.colors = colors;
+ this.color = null;
+ }
+ if (isDegenerate()) {
+ throw new InvalidPolygonException("Invalid 3D Object: two vertices are the same");
+ }
+ if (isNanOrInf()) {
+ throw new InvalidPolygonException("Invalid 3D Object: contains NaN or Inf coordinates");
+ }
+ setPrecedence(defaultPrecedence++);
+ }
+
+ final Color getColor(final int i) {
+ if (colors != null) {
+ return colors[i];
+ }
+
+ return color;
+ }
+
+ final boolean isMonochromatic() {
+ return color != null;
+ }
+
+ /**
+ * Get the bounding box
+ * @return the bounding box
+ */
+ final BoundingBox getBBox() {
+ if (bbox == null) {
+ bbox = BoundingBox.getBoundingBox(this);
+ }
+
+ return bbox;
+ }
+
+ /**
+ * Test if an array of colors contains only one color or not
+ * @param colors the colors array
+ * @return true if the array is monochromatic
+ */
+ public static boolean isMonochromatic(Color[] colors) {
+ if (colors != null && colors.length > 0) {
+ Color c = colors[0];
+ for (int i = 1; i < colors.length; i++) {
+ if (!c.equals(colors[i])) {
+ return false;
+ }
+ }
+ }
+
+ return true;
+ }
+
+ /**
+ * Draw this object on a Graphics2D object
+ * @param g2d the Graphics2d object where to draw
+ */
+ public abstract void draw(Graphics2D g2d);
+
+ /**
+ * Reset the default precedence
+ */
+ public static void resetDefaultPrecedence() {
+ defaultPrecedence = 0;
+ }
+
+ /**
+ * Set the precedence of this object.
+ * @param precedence the precedence of this object
+ */
+ public void setPrecedence(int precedence) {
+ this.precedence = precedence;
+ }
+
+ /**
+ * Get the precedence of this object, i.e. its position in the list of the draw objects.
+ * The first object has a precedence of 0, the second has a precedence of 1, ...
+ * @param the precedence
+ */
+ public int getPrecedence() {
+ return precedence;
+ }
+
+ /**
+ * Get the normal vector.
+ * If no normal vector has been set then it is calculated in using the cross product of the first two vectors.
+ * @return the normal vector.
+ */
+ public Vector3d getProvidedNormal() {
+ return normal;
+ }
+
+ /**
+ * Get the normal vector.
+ * If no normal vector has been set then it is calculated in using the cross product of the first two vectors.
+ * @return the normal vector.
+ */
+ public Vector3d getNormal() {
+ if (v0v1 == null) {
+ setNormal();
+ }
+
+ return v0v1;
+ }
+
+ /**
+ * Set the normal vector
+ */
+ protected void setNormal() {
+ v0 = vertices[1].minus(vertices[0]);
+ if (vertices.length >= 3) {
+ v1 = vertices[2].minus(vertices[0]);
+ v0v1 = Vector3d.product(v0, v1);
+ nv0v1 = v0v1.getNorm();
+ v0v1 = v0v1.times(1 / nv0v1);;
+ } else {
+ v0v1 = new Vector3d(0, 0, 0);
+ }
+ }
+
+ /**
+ * Determinates if the object is contained into a plane
+ * @return true if the object is planar
+ */
+ protected boolean isPlanar() {
+ Vector3d n = getNormal();
+ if (n.isZero() || vertices.length == 3) {
+ return true;
+ }
+
+ for (int i = 1; i < vertices.length; i++) {
+ if (!isNull(n.scalar(vertices[0].minus(vertices[i])))) {
+ return false;
+ }
+ }
+
+ return true;
+ }
+
+ public int isBehind(Vector3d v, double a) {
+ double[] mM = minmax3D(this, v);
+
+ if (isPositiveOrNull(mM[0] + a)) {
+ return 1;
+ }
+ if (mM[1] + a < 0) {
+ return -1;
+ }
+
+ return 0;
+ }
+
+ public static boolean isBehind(Vector3d M, Vector3d v, double a) {
+ return isPositiveOrNull(M.scalar(v) + a);
+ }
+
+ /**
+ * Get the projected polyline of this object
+ * @return a path 2D
+ */
+ protected Path2D getProjectedPolyLine() {
+ Path2D.Double path = new Path2D.Double();
+ path.moveTo(vertices[0].getX(), vertices[0].getY());
+ for (int i = 1; i < vertices.length; i++) {
+ path.lineTo(vertices[i].getX(), vertices[i].getY());
+ }
+
+ return path;
+ }
+
+ /**
+ * Get the projected contour (i.e. a closed polyline) of this object
+ * @return a path 2D
+ */
+ protected Path2D getProjectedContour() {
+ Path2D path = getProjectedPolyLine();
+ path.closePath();
+
+ return path;
+ }
+
+ /**
+ * @param d a number
+ * @return true if d is near zero
+ */
+ protected final static boolean isNull(final double d) {
+ return Math.abs(d) <= PRECISION;
+ }
+
+ /**
+ * @param d a number
+ * @return true if d is greater than zero
+ */
+ protected final static boolean isPositiveOrNull(final double d) {
+ return d >= 0 || isNull(d);
+ }
+
+ /**
+ * @param d a number
+ * @return true if d is greater than zero
+ */
+ protected final static boolean isNegativeOrNull(final double d) {
+ return d <= 0 || isNull(d);
+ }
+
+ /**
+ * @param d1 a number
+ * @param d2 a number
+ * @return true if d1 is greater than d2
+ */
+ protected final static boolean isGreaterOrEqual(final double d1, final double d2) {
+ return isPositiveOrNull(d1 - d2);
+ }
+
+ /**
+ * @param d1 a number
+ * @param d2 a number
+ * @return true if d1 is lower than d2
+ */
+ protected final static boolean isLowerOrEqual(final double d1, final double d2) {
+ return isPositiveOrNull(d2 - d1);
+ }
+
+ /**
+ * @param d1 a number
+ * @param d2 a number
+ * @return true if d1 is equal to d2
+ */
+ protected final static boolean isEqual(final double d1, final double d2) {
+ return isNull(d1 - d2);
+ }
+
+ /**
+ * Get min-max of the projections of the vertices of o on v
+ * @param o an object
+ * @param v a vector
+ * @return an array of size 2 containing min-max.
+ */
+ protected static final double[] minmax3D(final AbstractDrawable3DObject o, final Vector3d v) {
+ double min = v.scalar(o.vertices[0]);
+ double max = min;
+
+ for (int i = 1; i < o.vertices.length; i++) {
+ double s = v.scalar(o.vertices[i]);
+ if (s < min) {
+ min = s;
+ } else if (s > max) {
+ max = s;
+ }
+ }
+
+ return new double[] {min, max};
+ }
+
+ /**
+ * Get min-max of the projections of the vertices of o on v
+ * @param o an object
+ * @param v a vector
+ * @return an array of size 2 containing min-max.
+ */
+ protected static final double[] minmax2D(final AbstractDrawable3DObject o, final double x, final double y) {
+ double min = x * o.vertices[0].getX() + y * o.vertices[0].getY();
+ double max = min;
+
+ for (int i = 1; i < o.vertices.length; i++) {
+ double s = x * o.vertices[i].getX() + y * o.vertices[i].getY();
+ if (s < min) {
+ min = s;
+ } else if (s > max) {
+ max = s;
+ }
+ }
+
+ return new double[] {min, max};
+ }
+
+ protected static final Color getColorsBarycenter(final Color c1, final Color c2, final double w1, final double w2) {
+ if (c1 != null && c2 != null && !c1.equals(c2)) {
+ float[] comp1 = c1.getComponents(null);
+ float[] comp2 = c2.getComponents(null);
+
+ return new Color((float) (comp1[0] * w1 + comp2[0] * w2),
+ (float) (comp1[1] * w1 + comp2[1] * w2),
+ (float) (comp1[2] * w1 + comp2[2] * w2),
+ (float) (comp1[3] * w1 + comp2[3] * w2));
+ }
+
+ return c1;
+ }
+
+ /**
+ * @return true if there are two vertices which are indentical
+ */
+ protected boolean isDegenerate() {
+ Set<Vector3d> set = new HashSet<Vector3d>();
+ for (Vector3d v : vertices) {
+ set.add(v);
+ }
+
+ return set.size() != vertices.length;
+ }
+
+ protected boolean isNanOrInf() {
+ for (Vector3d v : vertices) {
+ if (isNanOrInf(v)) {
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+ public static final boolean isNanOrInf(final Vector3d v) {
+ final double x = v.getX();
+ if (Double.isNaN(x) || Double.isInfinite(x)) {
+ return true;
+ }
+ final double y = v.getY();
+ if (Double.isNaN(y) || Double.isInfinite(y)) {
+ return true;
+ }
+ final double z = v.getZ();
+ if (Double.isNaN(z) || Double.isInfinite(z)) {
+ return true;
+ }
+ return false;
+ }
+
+ /**
+ * Create a clip rect for 2D view according to clipping planes passed as arguments
+ * @param v the clipping plane equation
+ */
+ public final static void makeClip(final double[] clip, final double[] v) {
+ if (v[1] == 0) {
+ double x = -v[3] / v[0];
+ if (Double.isNaN(clip[0])) {
+ clip[0] = x;
+ } else if (clip[0] > x) {
+ clip[1] = clip[0];
+ clip[0] = x;
+ } else {
+ clip[1] = x;
+ }
+ } else {
+ double y = -v[3] / v[1];
+ if (Double.isNaN(clip[2])) {
+ clip[2] = y;
+ } else if (clip[2] > y) {
+ clip[3] = clip[2];
+ clip[2] = y;
+ } else {
+ clip[3] = y;
+ }
+ }
+ }
+
+ /**
+ * Get the clipping shape (for 2D view)
+ * @return the clipping shape
+ */
+ public final static Shape getClip(final double[] clip) {
+ if (!Double.isNaN(clip[0]) && !Double.isNaN(clip[1]) && !Double.isNaN(clip[2]) && !Double.isNaN(clip[3])) {
+ return new Rectangle2D.Double(clip[0], clip[2], clip[1] - clip[0], clip[3] - clip[2]);
+ }
+
+ return null;
+ }
+}
diff --git a/modules/scirenderer/src/org/scilab/forge/scirenderer/implementation/g2d/motor/BoundingBox.java b/modules/scirenderer/src/org/scilab/forge/scirenderer/implementation/g2d/motor/BoundingBox.java
new file mode 100755
index 000000000..a101e17e4
--- /dev/null
+++ b/modules/scirenderer/src/org/scilab/forge/scirenderer/implementation/g2d/motor/BoundingBox.java
@@ -0,0 +1,176 @@
+/*
+ * Scilab ( http://www.scilab.org/ ) - This file is part of Scilab
+ * Copyright (C) 2012 - Scilab Enterprises - Calixte Denizet
+ *
+ * This file must be used under the terms of the CeCILL.
+ * This source file is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at
+ * http://www.cecill.info/licences/Licence_CeCILL_V2.1-en.txt
+ */
+
+package org.scilab.forge.scirenderer.implementation.g2d.motor;
+
+import org.scilab.forge.scirenderer.tranformations.Vector3d;
+
+/**
+ * @author Calixte DENIZET
+ *
+ * Bounding box of a 3D object, useful to speed-up intersection detection.
+ */
+public class BoundingBox {
+
+ private double minX = Double.POSITIVE_INFINITY;
+ private double maxX = Double.NEGATIVE_INFINITY;
+ private double minY = Double.POSITIVE_INFINITY;
+ private double maxY = Double.NEGATIVE_INFINITY;
+ private double minZ = Double.POSITIVE_INFINITY;
+ private double maxZ = Double.NEGATIVE_INFINITY;
+
+ /**
+ * Default constructor
+ * @param minX the minimal X
+ * @param maxX the maximal X
+ * @param minY the minimal Y
+ * @param maxY the maximal Y
+ * @param minZ the minimal Z
+ * @param maxZ the maximal Z
+ */
+ public BoundingBox(double minX, double maxX, double minY, double maxY, double minZ, double maxZ) {
+ this.minX = minX;
+ this.maxX = maxX;
+ this.minY = minY;
+ this.maxY = maxY;
+ this.minZ = minZ;
+ this.maxZ = maxZ;
+ }
+
+ /**
+ * Get the relative x-position of this bounding-box and of the box
+ * @param box a BoundingBox
+ * @return 1 if box is on the right, -1 if on the left and 0 if nothing.
+ */
+ public int xCompare(BoundingBox box) {
+ if (box.minX >= maxX) {
+ return -1;
+ }
+
+ if (minX >= box.maxX) {
+ return 1;
+ }
+
+ return 0;
+ }
+
+ /**
+ * Get the relative y-position of this bounding-box and of the box
+ * @param box a BoundingBox
+ * @return 1 if box is on the bottom, -1 if on the top and 0 if nothing.
+ */
+ public int yCompare(BoundingBox box) {
+ if (box.minY >= maxY) {
+ return -1;
+ }
+
+ if (minY >= box.maxY) {
+ return 1;
+ }
+
+ return 0;
+ }
+
+ /**
+ * Get the relative z-position of this bounding-box and of the box
+ * @param box a BoundingBox
+ * @return 1 if box is on the front, -1 if behind and 0 if nothing.
+ */
+ public int zCompare(BoundingBox box) {
+ if (box.minZ >= maxZ) {
+ return 1;
+ }
+
+ if (minZ >= box.maxZ) {
+ return -1;
+ }
+
+ return 0;
+ }
+
+ /**
+ * @param box a BoundingBox
+ * @return true if this BoundingBox and the box have an intersection
+ */
+ public boolean isIntersecting(BoundingBox box) {
+ return box.maxX >= minX && maxX >= box.minX
+ && box.maxY >= minY && maxY >= box.minY
+ && box.maxZ >= minZ && maxZ >= box.minZ;
+ }
+
+ /**
+ * @return true if the bbox are non-intersecting and no z-overlapping
+ */
+ public boolean isNonZOverlapping(BoundingBox box) {
+ return (box.maxX < minX || maxX < box.minX || box.maxY < minY || maxY < box.minY) || ((box.maxZ < minZ || maxZ < box.minZ) && (maxX == box.minX || box.maxX == minX || box.minY == maxY || minY == box.maxY));
+ }
+
+ /**
+ * @param box a BoundingBox
+ * @return true if this BoundingBox and the box have a strict intersection
+ */
+ public boolean isStrictlyIntersecting(BoundingBox box) {
+ return box.maxX > minX && maxX > box.minX
+ && box.maxY > minY && maxY > box.minY
+ && box.maxZ > minZ && maxZ > box.minZ;
+ }
+
+ /**
+ * Get the bounding box of an object
+ * @param object a 3D object
+ * @return the corresponding bounding-box
+ */
+ public static BoundingBox getBoundingBox(AbstractDrawable3DObject object) {
+ Vector3d[] vertices = object.vertices;
+ double minX = Double.POSITIVE_INFINITY;
+ double maxX = Double.NEGATIVE_INFINITY;
+ double minY = Double.POSITIVE_INFINITY;
+ double maxY = Double.NEGATIVE_INFINITY;
+ double minZ = Double.POSITIVE_INFINITY;
+ double maxZ = Double.NEGATIVE_INFINITY;
+
+ for (int i = 0; i < vertices.length; i++) {
+ double x = vertices[i].getX();
+ double y = vertices[i].getY();
+ double z = vertices[i].getZ();
+ if (x < minX) {
+ minX = x;
+ }
+
+ if (x > maxX) {
+ maxX = x;
+ }
+
+ if (y < minY) {
+ minY = y;
+ }
+
+ if (y > maxY) {
+ maxY = y;
+ }
+
+ if (z < minZ) {
+ minZ = z;
+ }
+
+ if (z > maxZ) {
+ maxZ = z;
+ }
+ }
+
+ return new BoundingBox(minX, maxX, minY, maxY, minZ, maxZ);
+ }
+
+ @Override
+ public String toString() {
+ return "[" + minX + ";" + maxX + "]x" + "[" + minY + ";" + maxY + "]x" + "[" + minZ + ";" + maxZ + "]";
+ }
+}
diff --git a/modules/scirenderer/src/org/scilab/forge/scirenderer/implementation/g2d/motor/Clippable.java b/modules/scirenderer/src/org/scilab/forge/scirenderer/implementation/g2d/motor/Clippable.java
new file mode 100755
index 000000000..9e507e874
--- /dev/null
+++ b/modules/scirenderer/src/org/scilab/forge/scirenderer/implementation/g2d/motor/Clippable.java
@@ -0,0 +1,32 @@
+/*
+ * Scilab ( http://www.scilab.org/ ) - This file is part of Scilab
+ * Copyright (C) 2013 - Scilab Enterprises - Calixte Denizet
+ *
+ * This file must be used under the terms of the CeCILL.
+ * This source file is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at
+ * http://www.cecill.info/licences/Licence_CeCILL_V2.1-en.txt
+ */
+
+package org.scilab.forge.scirenderer.implementation.g2d.motor;
+
+import java.util.List;
+
+import org.scilab.forge.scirenderer.tranformations.Vector4d;
+
+/**
+ * @author Calixte DENIZET
+ *
+ * Interface to represent a clippable object.
+ */
+public interface Clippable {
+
+ /**
+ * Break this ConvexObject against a plane
+ * @param v plane definition
+ * @return a list of ConvexObject.
+ */
+ public List<ConvexObject> breakObject(Vector4d v);
+
+} \ No newline at end of file
diff --git a/modules/scirenderer/src/org/scilab/forge/scirenderer/implementation/g2d/motor/ConvexObject.java b/modules/scirenderer/src/org/scilab/forge/scirenderer/implementation/g2d/motor/ConvexObject.java
new file mode 100755
index 000000000..c0c473f68
--- /dev/null
+++ b/modules/scirenderer/src/org/scilab/forge/scirenderer/implementation/g2d/motor/ConvexObject.java
@@ -0,0 +1,321 @@
+/*
+ * Scilab ( http://www.scilab.org/ ) - This file is part of Scilab
+ * Copyright (C) 2012 - Scilab Enterprises - Calixte Denizet
+ *
+ * This file must be used under the terms of the CeCILL.
+ * This source file is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at
+ * http://www.cecill.info/licences/Licence_CeCILL_V2.1-en.txt
+ */
+
+package org.scilab.forge.scirenderer.implementation.g2d.motor;
+
+import java.awt.Color;
+import java.awt.Graphics2D;
+import java.awt.Shape;
+import java.util.ArrayList;
+import java.util.List;
+
+import org.scilab.forge.scirenderer.tranformations.Vector3d;
+import org.scilab.forge.scirenderer.tranformations.Vector4d;
+
+/**
+ * @author Calixte DENIZET
+ *
+ * Class to represent a convex object.
+ * Collision and relative positions of convexs object are relatively easy to determinate.
+ * About the method isBehind, it could be interesting to use the algorithm of Chung-Wang.
+ */
+public abstract class ConvexObject extends AbstractDrawable3DObject implements Clippable {
+
+ private List<ConvexObject> areas;
+
+ /**
+ * Default constructor
+ * @param vertices the vertices
+ * @param colors the colors
+ */
+ public ConvexObject(Vector3d[] vertices, Color[] colors) throws InvalidPolygonException {
+ super(vertices, colors);
+ }
+
+ /**
+ * Abstract method
+ * Break this ConvexObject against the ConvexObject o
+ * @param o a ConvexObject
+ * @return a list of ConvexObject.
+ */
+ public abstract List<ConvexObject> breakObject(ConvexObject o);
+
+ /**
+ * {@inheritDoc}
+ */
+ public abstract List<ConvexObject> breakObject(Vector4d v);
+
+ public void addArea(ConvexObject co) {
+ if (areas == null) {
+ areas = new ArrayList<ConvexObject>();
+ }
+ areas.add(co);
+ }
+
+ protected void drawAreas(Graphics2D g2d) {
+ if (areas != null) {
+ for (ConvexObject co : areas) {
+ Shape oldClip = g2d.getClip();
+ g2d.clip(this.getProjectedContour());
+ co.draw(g2d);
+ g2d.setClip(oldClip);
+ }
+ }
+ }
+
+ /**
+ * Test the coplanarity of two objects
+ * @param o a ConvexObject
+ * @return true if the two objects are coplanar
+ */
+ public boolean areCoplanar(ConvexObject o) {
+ if (!(this instanceof Segment)) {
+ double sc = vertices[0].scalar(getNormal());
+ if (o instanceof Segment) {
+ return isEqual(sc, o.vertices[0].scalar(v0v1)) && isEqual(sc, o.vertices[1].scalar(v0v1));
+ }
+ return isEqual(sc, o.vertices[0].scalar(v0v1)) && isEqual(sc, o.vertices[1].scalar(v0v1)) && isEqual(sc, o.vertices[2].scalar(v0v1));
+ }
+
+ if (!(o instanceof Segment)) {
+ return o.areCoplanar(this);
+ }
+
+ if (o.vertices[0].equals(vertices[0]) || o.vertices[1].equals(vertices[0]) || o.vertices[0].equals(vertices[1]) || o.vertices[1].equals(vertices[1])) {
+ return true;
+ }
+
+ getNormal();
+ o.getNormal();
+ Vector3d v = Vector3d.product(v0, o.v0);
+ return isNull(v.scalar(vertices[0].minus(o.vertices[0])));
+ }
+
+ /**
+ * Check if o is behind this.
+ * Take care: the algorithms used are for convex objects (typically tri-tri, seg-seg or tri-seg)
+ * @return true if o is behind this
+ */
+ public int isBehind(ConvexObject o) {
+ BoundingBox bbox = getBBox();
+ BoundingBox obbox = o.getBBox();
+ // Quick test in using bounding boxes
+ if (bbox.isNonZOverlapping(obbox)) {
+ return 0;
+ }
+
+ // Check if the two objects intersect in projection plane or not
+ if (check2DIntersection(o)) {
+ // We have a strict intersection or an intersection on an edge
+ if (areCoplanar(o)) {
+ return getPrecedence() > o.getPrecedence() ? 1 : -1;
+ }
+
+ // Quick test with bounding-box along z-axis
+ int ret = bbox.zCompare(obbox);
+ if (ret != 0) {
+ return ret;
+ }
+
+ // In the most of the cases, one of the two following test are sufficient to determinate
+ // if one object is behind or on front of the plane containing this or o
+ ret = check(o, getNormal());
+ if (ret != 0) {
+ return ret;
+ }
+
+ ret = check(o, o.getNormal());
+ if (ret != 0) {
+ return ret;
+ }
+
+ // Check against the cross product of one edge of this and one edge of o
+ int M = vertices.length == 2 ? 1 : vertices.length;
+ int N = o.vertices.length == 2 ? 1 : o.vertices.length;
+ for (int j = 0; j < M; j++) {
+ int l = (j + 1 < vertices.length) ? j + 1 : 0;
+ Vector3d e = vertices[l].minus(vertices[j]);
+ for (int k = 0; k < N; k++) {
+ int m = (k + 1 < o.vertices.length) ? k + 1 : 0;
+ Vector3d oe = o.vertices[m].minus(o.vertices[k]);
+ ret = check(o, Vector3d.product(e, oe).getNormalized());
+ if (ret != 0) {
+ return ret;
+ }
+ }
+ }
+
+ // At this point: there is a collision between the two objects
+ return 2;
+ } else {
+ return 0;
+ }
+ }
+
+ /**
+ * Check the intersections of the projection on the xOy-plane of this and o
+ * The algorithm is the following: for each edge, determinate the normal vector and project all the points
+ * of this and o on the normal. If the intersection of [this.min,this.max] and [o.min, o.max] is empty, then
+ * we have a separating line so the two objects are separated.
+ * @param o the object to test with this
+ * @return true if there is a collision
+ */
+ public boolean check2DIntersection(final ConvexObject o) {
+ int ret = check2D(this, o);
+ if (ret != -1) {
+ return false;
+ }
+
+ ret = check2D(o, this);
+ if (ret != -1) {
+ return false;
+ }
+
+ return true;
+ }
+
+ /**
+ * Check the intersections of the projection on the xOy-plane of this and o
+ * The algorithm is the following: for each edge, determinate the normal vector and project all the points
+ * of this and o on the normal. If the intersection of [this.min,this.max] and [o.min, o.max] is empty, then
+ * we have a separating line so the two objects are separated.
+ * @param o the object to test with this
+ * @return true if there is a collision
+ */
+ public boolean check2DTrueIntersection(final ConvexObject o) {
+ int ret = check2D2(this, o);
+ if (ret == 1) {
+ return true;
+ } else if (ret == 0) {
+ return false;
+ }
+
+ ret = check2D2(o, this);
+ if (ret == 1) {
+ return true;
+ } else if (ret == 0) {
+ return false;
+ }
+
+ return true;
+ }
+
+ /**
+ * Check 2D intersection of two convex objects
+ * @param o1 first object
+ * @param o2 second object
+ * @return -1 if strict intersection, 1 if intersection on an edge and 0 if no intersection
+ */
+ private static final int check2D(final ConvexObject o1, final ConvexObject o2) {
+ // When o1 is a Segment (i.e. o1.vertices;length == 2) it is mandatory to check against ortho(v1-v0) and ortho(v0-v1)
+ int M = o1.vertices.length == 2 ? 1 : o1.vertices.length;
+ for (int i = 0; i < M; i++) {
+ int j = (i + 1 < o1.vertices.length) ? i + 1 : 0;
+ double xN = o1.vertices[i].getY() - o1.vertices[j].getY();
+ double yN = o1.vertices[j].getX() - o1.vertices[i].getX();
+ double n = Math.hypot(xN, yN);
+ xN /= n;
+ yN /= n;
+ double[] mM = minmax2D(o1, xN, yN);
+ double min = mM[0];
+ double max = mM[1];
+
+ mM = minmax2D(o2, xN, yN);
+ double omin = mM[0];
+ double omax = mM[1];
+
+ if (max < omin || omax < min) {
+ return 0;
+ }
+
+ if (isEqual(max, omin) || isEqual(omax, min)) {
+ return 1;
+ }
+ }
+
+ return -1;
+ }
+
+ /**
+ * Check 2D intersection of two convex objects
+ * @param o1 first object
+ * @param o2 second object
+ * @return -1 if strict intersection, 1 if intersection on an edge and 0 if no intersection
+ */
+ private static final int check2D2(final ConvexObject o1, final ConvexObject o2) {
+ // When o1 is a Segment (i.e. o1.vertices;length == 2) it is mandatory to check against ortho(v1-v0) and ortho(v0-v1)
+ int M = o1.vertices.length == 2 ? 1 : o1.vertices.length;
+ boolean bool = false;
+ for (int i = 0; i < M; i++) {
+ int j = (i + 1 < o1.vertices.length) ? i + 1 : 0;
+ double xN = o1.vertices[i].getY() - o1.vertices[j].getY();
+ double yN = o1.vertices[j].getX() - o1.vertices[i].getX();
+ double n = Math.hypot(xN, yN);
+ xN /= n;
+ yN /= n;
+ double[] mM = minmax2D(o1, xN, yN);
+ double min = mM[0];
+ double max = mM[1];
+
+ mM = minmax2D(o2, xN, yN);
+ double omin = mM[0];
+ double omax = mM[1];
+
+ if (max < omin || omax < min) {
+ return 0;
+ }
+
+ if (!bool && (isEqual(max, omin) || isEqual(omax, min))) {
+ bool = true;
+ }
+ }
+
+ if (bool) {
+ return 1;
+ }
+
+ return -1;
+ }
+
+ /**
+ * Check the intersection this and o against vector v.
+ * The algorithm is just to project this and o on the vector v and to check if the two projected sets
+ * can be separated.
+ * @param v the vector where to project
+ * @return 1 if o is behind this, 0 if it is undeterminated and -1 if this is behind o.
+ */
+ protected int check(final ConvexObject o, final Vector3d v) {
+ if (!v.isNearZero()) {
+ double[] mM = minmax3D(this, v);
+ double min = mM[0];
+ double max = mM[1];
+
+ mM = minmax3D(o, v);
+ double omin = mM[0];
+ double omax = mM[1];
+ double z = v.getZ();
+
+ if (Math.signum(z) == 0) {
+ return 0;
+ }
+
+ if (isLowerOrEqual(max, omin)) {
+ return (int) Math.signum(z);
+ }
+
+ if (isLowerOrEqual(omax, min)) {
+ return (int) - Math.signum(z);
+ }
+ }
+
+ return 0;
+ }
+}
diff --git a/modules/scirenderer/src/org/scilab/forge/scirenderer/implementation/g2d/motor/DrawTools.java b/modules/scirenderer/src/org/scilab/forge/scirenderer/implementation/g2d/motor/DrawTools.java
new file mode 100755
index 000000000..925751d5c
--- /dev/null
+++ b/modules/scirenderer/src/org/scilab/forge/scirenderer/implementation/g2d/motor/DrawTools.java
@@ -0,0 +1,307 @@
+/*
+ * Scilab ( http://www.scilab.org/ ) - This file is part of Scilab
+ * Copyright (C) 2012 - Scilab Enterprises - Calixte Denizet
+ *
+ * This file must be used under the terms of the CeCILL.
+ * This source file is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at
+ * http://www.cecill.info/licences/Licence_CeCILL_V2.1-en.txt
+ */
+
+package org.scilab.forge.scirenderer.implementation.g2d.motor;
+
+import java.awt.BasicStroke;
+import java.awt.Color;
+import java.awt.GradientPaint;
+import java.awt.Graphics2D;
+import java.awt.LinearGradientPaint;
+import java.awt.Paint;
+import java.awt.RenderingHints;
+import java.awt.Shape;
+import java.awt.Stroke;
+import java.awt.geom.AffineTransform;
+import java.awt.geom.Area;
+import java.awt.geom.NoninvertibleTransformException;
+import java.awt.geom.Path2D;
+import java.awt.geom.Rectangle2D;
+import java.awt.image.BufferedImage;
+import java.awt.image.DataBufferInt;
+
+import java.awt.geom.Point2D;
+import java.awt.MultipleGradientPaint;
+
+/**
+ * @author Calixte DENIZET
+ */
+public final class DrawTools {
+
+ private static final Stroke stroke = new BasicStroke(1.0f, BasicStroke.CAP_BUTT, BasicStroke.JOIN_BEVEL);
+ private static final Stroke EMPTYSTROKE = new BasicStroke(0f, BasicStroke.CAP_BUTT, BasicStroke.JOIN_BEVEL);
+ private static final Color TRANSLUCENT_BLACK = new Color(0, 0, 0, 0);
+
+ /**
+ * Fill a triangle in using a Gouraud shading
+ * Only two gradient are used rather than three.
+ * @param g2d the Graphics2D where to draw
+ * @param t the Triangle to fill
+ */
+ public static final void fillGouraud(final Graphics2D g2d, final Triangle t) {
+ Path2D contour = t.getProjectedContour();
+ double[] v0 = new double[] {t.vertices[0].getX(), t.vertices[0].getY()};
+ double[] v1 = new double[] {t.vertices[1].getX(), t.vertices[1].getY()};
+ double[] v2 = new double[] {t.vertices[2].getX(), t.vertices[2].getY()};
+ double[] pv0 = get2DProjection(v0[0], v0[1], v1[0], v1[1], v2[0], v2[1]);
+ double[] pv1 = get2DProjection(v1[0], v1[1], v0[0], v0[1], v2[0], v2[1]);
+ double[] pv2 = get2DProjection(v2[0], v2[1], v0[0], v0[1], v1[0], v1[1]);
+
+ Paint oldPaint = g2d.getPaint();
+ Area area = new Area(contour);
+ area.add(new Area(stroke.createStrokedShape(contour)));
+
+
+ g2d.setColor(t.getColor(0));
+ g2d.fill(area);
+
+
+ float[] col = t.getColor(1).getComponents(null);
+ GradientPaint gp = new GradientPaint((float) v1[0], (float) v1[1], t.getColor(1), (float) pv1[0], (float) pv1[1], new Color(col[0], col[1], col[2], 0.0f));
+ g2d.setPaint(gp);
+ g2d.fill(area);
+
+
+ col = t.getColor(2).getComponents(null);
+ gp = new GradientPaint((float) v2[0], (float) v2[1], t.getColor(2), (float) pv2[0], (float) pv2[1], new Color(col[0], col[1], col[2], 0.0f));
+ g2d.setPaint(gp);
+ g2d.fill(area);
+
+ g2d.setPaint(oldPaint);
+ }
+
+ /**
+ * Draw a texture (ie a BufferedImage) in a triangle
+ * @param g2d the Graphics2D where to draw
+ * @param image the texture to apply
+ * @param ximg the x-coordinates of the triangle to use in the texture
+ * @param yimg the y-coordinates of the triangle to use in the texture
+ * @param xdest the x-coordinates of the destination triangle
+ * @param ydest the y-coordinates of the destination triangle
+ * @param key the rendering hint to use for interpolation
+ */
+ public static final void drawTriangleTexture(final Graphics2D g2d, final BufferedImage image, final double[] ximg, final double[] yimg, final double[] xdest, final double[] ydest, Object key) {
+ try {
+ double w = image.getWidth();
+ double h = image.getHeight();
+
+ Path2D.Double path = new Path2D.Double();
+ path.moveTo(xdest[0], ydest[0]);
+ path.lineTo(xdest[1], ydest[1]);
+ path.lineTo(xdest[2], ydest[2]);
+ path.closePath();
+ Area area = new Area(path);
+ area.add(new Area(stroke.createStrokedShape(path)));
+
+ boolean is1d = is1d(ximg, yimg);
+
+ // if we have a 1D texture we must slighlty modified the coordinates to use the algorithm below.
+ if (checkSourceCoordinates(ximg, yimg)) {
+ // three coordinates are the same in 1D texture
+ int[] pixels = ((DataBufferInt) image.getRaster().getDataBuffer()).getData();
+ int index = (int) Math.floor(w * ximg[0]);
+ Color color;
+ if (index >= pixels.length) {
+ color = new Color(pixels[pixels.length - 1]);
+ } else if (index < 0) {
+ color = new Color(pixels[0]);
+ } else {
+ color = new Color(pixels[index]);
+ }
+ //color = Color.PINK;
+
+ g2d.setColor(color);
+ g2d.fill(area);
+ return;
+ }
+
+ AffineTransform translationDest = AffineTransform.getTranslateInstance(xdest[0], ydest[0]);
+ AffineTransform translationImg = AffineTransform.getTranslateInstance(-w * ximg[0], -h * yimg[0]);
+
+ AffineTransform toDest = new AffineTransform(xdest[1] - xdest[0], ydest[1] - ydest[0], xdest[2] - xdest[0], ydest[2] - ydest[0], 0, 0);
+ AffineTransform fromImg = new AffineTransform(w * (ximg[1] - ximg[0]), h * (yimg[1] - yimg[0]), w * (ximg[2] - ximg[0]), h * (yimg[2] - yimg[0]), 0, 0).createInverse();
+
+ AffineTransform transformation = new AffineTransform();
+ transformation.concatenate(translationDest);
+ transformation.concatenate(toDest);
+ transformation.concatenate(fromImg);
+ transformation.concatenate(translationImg);
+
+ AffineTransform oldTransform = g2d.getTransform();
+
+ // For now we don't enter in this
+ // SVGGraphics2D doesn't handle MultipleGradient :(
+ if (false && is1d && key == RenderingHints.VALUE_INTERPOLATION_BILINEAR) {
+ int[] pixels = ((DataBufferInt) image.getRaster().getDataBuffer()).getData();
+ float[] fractions = new float[pixels.length];
+ for (int i = 0; i < fractions.length; i++) {
+ fractions[i] = (((float) i) / (fractions.length - 1));
+ }
+
+ Color[] colors = new Color[pixels.length];
+ for (int i = 0; i < colors.length; i++) {
+ colors[i] = new Color(pixels[i]);
+ }
+ LinearGradientPaint gradient = new LinearGradientPaint(new Point2D.Double(0, 0), new Point2D.Double(pixels.length, 0), fractions, colors, MultipleGradientPaint.CycleMethod.NO_CYCLE, MultipleGradientPaint.ColorSpaceType.SRGB, transformation);
+ Shape oldClip = g2d.getClip();
+ g2d.clip(area);
+ g2d.setPaint(gradient);
+ g2d.fill(area);
+ g2d.setClip(oldClip);
+ } else {
+ clamp(g2d, ximg, yimg, xdest, ydest, transformation, image);
+ Object oldKey = g2d.getRenderingHint(RenderingHints.KEY_INTERPOLATION);
+ g2d.setRenderingHint(RenderingHints.KEY_INTERPOLATION, key);
+ g2d.setStroke(EMPTYSTROKE);
+ Shape oldClip = g2d.getClip();
+ g2d.clip(area);
+ g2d.drawImage(image, transformation, null);
+ g2d.setClip(oldClip);
+ if (oldKey != null) {
+ g2d.setRenderingHint(RenderingHints.KEY_INTERPOLATION, oldKey);
+ }
+ }
+
+ g2d.setTransform(oldTransform);
+ } catch (NoninvertibleTransformException e) {
+ System.err.println(e);
+ }
+ }
+
+ /**
+ * Draw a texture (ie a BufferedImage) in a parallelogram
+ * @param g2d the Graphics2D where to draw
+ * @param image the texture to apply
+ * @param ximg the x-coordinates of the parallelogram to use in the texture
+ * @param yimg the y-coordinates of the parallelogram to use in the texture
+ * @param xdest the x-coordinates of the destination parallelogram
+ * @param ydest the y-coordinates of the destination parallelogram
+ * @param key the rendering hint to use for interpolation
+ */
+ public static final void drawParallelogramTexture(final Graphics2D g2d, final BufferedImage image, final double[] ximg, final double[] yimg, final double[] xdest, final double[] ydest, Object key) {
+ try {
+ Object oldKey = g2d.getRenderingHint(RenderingHints.KEY_INTERPOLATION);
+
+ double w = image.getWidth();
+ double h = image.getHeight();
+
+ AffineTransform translationDest = AffineTransform.getTranslateInstance(xdest[0], ydest[0]);
+ AffineTransform translationImg = AffineTransform.getTranslateInstance(-w * ximg[0], -h * yimg[0]);
+
+ AffineTransform toDest = new AffineTransform(xdest[1] - xdest[0], ydest[1] - ydest[0], xdest[2] - xdest[0], ydest[2] - ydest[0], 0, 0);
+ AffineTransform fromImg = new AffineTransform(w * (ximg[1] - ximg[0]), h * (yimg[1] - yimg[0]), w * (ximg[2] - ximg[0]), h * (yimg[2] - yimg[0]), 0, 0).createInverse();
+
+ AffineTransform transformation = new AffineTransform();
+ transformation.concatenate(translationDest);
+ transformation.concatenate(toDest);
+ transformation.concatenate(fromImg);
+ transformation.concatenate(translationImg);
+
+ AffineTransform oldTransform = g2d.getTransform();
+ g2d.setRenderingHint(RenderingHints.KEY_INTERPOLATION, key);
+ g2d.drawImage(image, transformation, null);
+ g2d.setTransform(oldTransform);
+
+ if (oldKey != null) {
+ g2d.setRenderingHint(RenderingHints.KEY_INTERPOLATION, oldKey);
+ }
+ } catch (NoninvertibleTransformException e) { }
+ }
+
+ /**
+ * Check and modify the coordinates if we have a 1D texture (i.e. all the y-coords are zero)
+ * @param x the x-coordinates
+ * @param y the y-coordinates
+ */
+ private static final boolean checkSourceCoordinates(final double[] x, final double[] y) {
+ if (is1d(x, y)) {
+ if (!AbstractDrawable3DObject.isEqual(x[0], x[1]) && !AbstractDrawable3DObject.isEqual(x[1], x[2]) && !AbstractDrawable3DObject.isEqual(x[2], x[0])) {
+ y[0] = 1;
+ } else if (AbstractDrawable3DObject.isEqual(x[0], x[1]) && !AbstractDrawable3DObject.isEqual(x[1], x[2])) {
+ y[0] = 1;
+ } else if (AbstractDrawable3DObject.isEqual(x[0], x[2]) && !AbstractDrawable3DObject.isEqual(x[2], x[1])) {
+ y[2] = 1;
+ } else if (AbstractDrawable3DObject.isEqual(x[1], x[2]) && !AbstractDrawable3DObject.isEqual(x[2], x[0])) {
+ y[2] = 1;
+ } else {
+ return true;
+ }
+
+ y[0] = !AbstractDrawable3DObject.isNull(y[0]) ? 1 : 0;
+ y[1] = !AbstractDrawable3DObject.isNull(y[1]) ? 1 : 0;
+ y[2] = !AbstractDrawable3DObject.isNull(y[2]) ? 1 : 0;
+ }
+
+ return false;
+ }
+
+ /**
+ * Check if the triangle in texture is degenerate
+ * @param x x-coordinates
+ * @param y y-coordinates
+ * @return true if 1d
+ */
+ private static final boolean is1d(final double[] x, final double[] y) {
+ return AbstractDrawable3DObject.isNull(y[0]) && AbstractDrawable3DObject.isNull(y[1]) && AbstractDrawable3DObject.isNull(y[2]);
+ }
+
+ private static final void clamp(Graphics2D g2d, double[] ximg, double[] yimg, double[] xdest, double[] ydest, AffineTransform transformation, BufferedImage image) {
+ if (ximg[0] < 0 || ximg[1] < 0 || ximg[2] < 0 || ximg[0] > 1 || ximg[1] > 1 || ximg[2] > 1) {
+ double w = image.getWidth();
+ double h = image.getHeight();
+ int[] pixels = ((DataBufferInt) image.getRaster().getDataBuffer()).getData();
+ Path2D.Double path = new Path2D.Double();
+ path.moveTo(w * ximg[0], h * yimg[0]);
+ path.lineTo(w * ximg[1], h * yimg[1]);
+ path.lineTo(w * ximg[2], h * yimg[2]);
+ path.closePath();
+ Area tri = new Area(path);
+ Rectangle2D bounds = tri.getBounds2D();
+
+ if (bounds.getX() < 0) {
+ Area rect = new Area(new Rectangle2D.Double(bounds.getX(), bounds.getY(), -bounds.getX(), bounds.getHeight()));
+ tri.intersect(rect);
+ if (!tri.isEmpty()) {
+ tri.transform(transformation);
+ g2d.setColor(new Color(pixels[0]));
+ g2d.fill(tri);
+ }
+ }
+
+ if (bounds.getX() + bounds.getWidth() > w) {
+ tri = new Area(path);
+ Area rect = new Area(new Rectangle2D.Double(w, bounds.getY(), bounds.getX() + bounds.getWidth() - w, bounds.getHeight()));
+ tri.intersect(rect);
+ if (!tri.isEmpty()) {
+ tri.transform(transformation);
+ g2d.setColor(new Color(pixels[pixels.length - 1]));
+ g2d.fill(tri);
+ }
+ }
+ }
+ }
+
+ /**
+ * Get the projection in 2D of point A on line (BC)
+ * @param A the point to project
+ * @param B a point of the line
+ * @param C an other point of the line (different of B)
+ * @return the projected point
+ */
+ private static final double[] get2DProjection(final double xA, final double yA, final double xB, final double yB, final double xC, final double yC) {
+ final double xBC = xC - xB;
+ final double yBC = yC - yB;
+ final double n = xBC * xBC + yBC * yBC;
+ final double s = (xBC * (xA - xB) + yBC * (yA - yB)) / n;
+
+ return new double[] {xB + s * xBC, yB + s * yBC};
+ }
+}
diff --git a/modules/scirenderer/src/org/scilab/forge/scirenderer/implementation/g2d/motor/G2DStroke.java b/modules/scirenderer/src/org/scilab/forge/scirenderer/implementation/g2d/motor/G2DStroke.java
new file mode 100755
index 000000000..f2fbc8617
--- /dev/null
+++ b/modules/scirenderer/src/org/scilab/forge/scirenderer/implementation/g2d/motor/G2DStroke.java
@@ -0,0 +1,105 @@
+/*
+ * Scilab ( http://www.scilab.org/ ) - This file is part of Scilab
+ * Copyright (C) 2012 - Scilab Enterprises - Calixte Denizet
+ *
+ * This file must be used under the terms of the CeCILL.
+ * This source file is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at
+ * http://www.cecill.info/licences/Licence_CeCILL_V2.1-en.txt
+ */
+
+package org.scilab.forge.scirenderer.implementation.g2d.motor;
+
+import java.awt.BasicStroke;
+
+import org.scilab.forge.scirenderer.shapes.appearance.Appearance;
+
+/**
+ * @author Calixte DENIZET
+ */
+public class G2DStroke extends BasicStroke {
+
+ private static final int[] array = new int[16];
+ private static final G2DStroke BASIC = new G2DStroke(1, null, 0);
+ private static float[] prevArray;
+ private static float prevFactor = -1;
+ private static short prevPattern = -1;
+
+ public G2DStroke(float lineWidth, float[] dash, float phase) {
+ super(lineWidth, CAP_BUTT, JOIN_MITER, 10.0f, dash, phase);
+ }
+
+ public static G2DStroke getStroke(Appearance appearance, double dashPhase) {
+ Appearance usedAppearance;
+ if (appearance == null) {
+ usedAppearance = new Appearance();
+ } else {
+ usedAppearance = appearance;
+ }
+
+ float factor = usedAppearance.getLineWidth();
+ if (factor == 0) {
+ return new G2DStroke(0, null, 0);
+ }
+
+ short pattern = usedAppearance.getLinePattern();
+ if (pattern == -1 ) {
+ if (factor == 1) {
+ return BASIC;
+ }
+
+ return new G2DStroke(factor, null, 0);
+ }
+
+ if (factor != prevFactor || pattern != prevPattern) {
+ prevFactor = factor;
+ prevPattern = pattern;
+ prevArray = decodePattern(factor, pattern);
+ }
+
+ return new G2DStroke(factor, prevArray, (float) dashPhase);
+ }
+
+ private static final float[] decodePattern(final float factor, short pattern) {
+ // If the pattern is 1111101011111010, from right to left it becomes
+ // 0101111101011111, the first 0 is put on the right 1011111010111110 and it is converted into
+ // 1, 1, 5, 1, 1, 1, 5, 1
+ int n = 0xFFFF & pattern;
+ int i = 0;
+ int t = Integer.numberOfTrailingZeros(n);
+ n = (n >> t);
+ int k = Integer.numberOfLeadingZeros(n) - 16;
+
+ // Here we try to have a shorter pattern (EPS and PS don't like too long pattern in setdash function)
+ // If the pattern is 101101101101, we can factorize the number by 101 (101+101x1000+101x1000000+101x1000000000)
+ // so we test if the pattern can be divided by 101010...., by 100100100..., ...)
+ int twopm1 = (1 << 16) - 1;
+ for (int j = 2; 2 <= 16; j++) {
+ int q = twopm1 / ((1 << j) - 1);
+ if (n % q == 0) {
+ n = n / q;
+ break;
+ }
+ }
+
+ while (n != 0) {
+ t = Integer.numberOfTrailingZeros(n);
+ if (t == 0) {
+ t = Integer.numberOfTrailingZeros(0xFFFF - n);
+ }
+
+ array[i++] = t;
+ n = n >> t;
+ }
+ array[i] = k;
+
+ float[] ret = new float[i + 1];
+
+ for (int j = 0; j <= i; j++) {
+ ret[j] = ((float) array[j]) * factor;
+ }
+
+ return ret;
+ }
+}
diff --git a/modules/scirenderer/src/org/scilab/forge/scirenderer/implementation/g2d/motor/InvalidPolygonException.java b/modules/scirenderer/src/org/scilab/forge/scirenderer/implementation/g2d/motor/InvalidPolygonException.java
new file mode 100755
index 000000000..c6fd1c600
--- /dev/null
+++ b/modules/scirenderer/src/org/scilab/forge/scirenderer/implementation/g2d/motor/InvalidPolygonException.java
@@ -0,0 +1,23 @@
+/*
+ * Scilab ( http://www.scilab.org/ ) - This file is part of Scilab
+ * Copyright (C) 2012 - Scilab Enterprises - Calixte Denizet
+ *
+ * This file must be used under the terms of the CeCILL.
+ * This source file is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at
+ * http://www.cecill.info/licences/Licence_CeCILL_V2.1-en.txt
+ */
+
+package org.scilab.forge.scirenderer.implementation.g2d.motor;
+
+/**
+ * @author Calixte DENIZET
+ */
+@SuppressWarnings(value = { "serial" })
+public class InvalidPolygonException extends Exception {
+
+ public InvalidPolygonException(String msg) {
+ super(msg);
+ }
+}
diff --git a/modules/scirenderer/src/org/scilab/forge/scirenderer/implementation/g2d/motor/LightHelper.java b/modules/scirenderer/src/org/scilab/forge/scirenderer/implementation/g2d/motor/LightHelper.java
new file mode 100755
index 000000000..905c302a8
--- /dev/null
+++ b/modules/scirenderer/src/org/scilab/forge/scirenderer/implementation/g2d/motor/LightHelper.java
@@ -0,0 +1,344 @@
+/*
+ * Scilab ( http://www.scilab.org/ ) - This file is part of Scilab
+ * Copyright (C) 2013 - Pedro SOUZA
+ *
+ * This file must be used under the terms of the CeCILL.
+ * This source file is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at
+ * http://www.cecill.info/licences/Licence_CeCILL_V2.1-en.txt
+ */
+
+package org.scilab.forge.scirenderer.implementation.g2d.motor;
+
+import java.awt.Color;
+import java.nio.FloatBuffer;
+import java.nio.IntBuffer;
+
+
+import org.scilab.forge.scirenderer.tranformations.Vector3f;
+import org.scilab.forge.scirenderer.implementation.g2d.lighting.G2DLight;
+import org.scilab.forge.scirenderer.shapes.appearance.Material;
+
+/**
+ * @author Pedro SOUZA
+ */
+public class LightHelper {
+
+ /**
+ * @param buffer the float buffer.
+ * @param stride the stride between elements.
+ * @return an array of Vector3f from the given float buffer.
+ */
+ public static Vector3f[] getVector3f(FloatBuffer buffer, int stride) {
+ if (buffer == null) {
+ return null;
+ }
+ if (stride < 3) {
+ return null;
+ }
+
+ float[] floats;
+ buffer.rewind();
+ if (buffer.hasArray()) {
+ floats = buffer.array();
+ } else {
+ floats = new float[buffer.limit()];
+ buffer.get(floats);
+ }
+
+ Vector3f[] ret = new Vector3f[floats.length / stride];
+ for (int i = 0; i < floats.length; i += stride) {
+ ret[i] = new Vector3f(floats[i], floats[i + 1], floats[i + 2]);
+ }
+ return ret;
+ }
+
+ /**
+ * @param buffer the float buffer.
+ * @param index the indices buffer.
+ * @param stride the stride between elements.
+ * @param transf matrix to transform the vector, if null no transformation is applied.
+ * @return an array of Vector3f from the given float buffer.
+ */
+ public static Vector3f[] getIndexedVector3f(FloatBuffer buffer, IntBuffer index, int stride, float[] transf) {
+ if (buffer == null || index == null) {
+ return null;
+ }
+ if (stride < 3) {
+ return null;
+ }
+
+ float[] floats;
+ buffer.rewind();
+ if (buffer.hasArray()) {
+ floats = buffer.array();
+ } else {
+ floats = new float[buffer.limit()];
+ buffer.get(floats);
+ }
+
+ int[] idx;
+ index.rewind();
+ if (index.hasArray()) {
+ idx = index.array();
+ } else {
+ idx = new int[index.limit()];
+ index.get(idx);
+ }
+
+ Vector3f[] ret = new Vector3f[idx.length];
+ float x, y, z;
+ if (transf != null && transf.length == 16) {
+ for (int i = 0; i < idx.length; ++i) {
+ ret[i] = transform(floats[stride * idx[i]], floats[stride * idx[i] + 1], floats[stride * idx[i] + 2], transf);
+ }
+ } else {
+ for (int i = 0; i < idx.length; ++i) {
+ ret[i] = new Vector3f(floats[stride * idx[i]], floats[stride * idx[i] + 1], floats[stride * idx[i] + 2]);
+ }
+ }
+ return ret;
+ }
+
+ static Vector3f transform(float x, float y, float z, float[] transf) {
+ float xx = transf[0] * x + transf[4] * y + transf[8] * z + transf[12];
+ float yy = transf[1] * x + transf[5] * y + transf[9] * z + transf[13];
+ float zz = transf[2] * x + transf[6] * y + transf[10] * z + transf[14];
+ return new Vector3f(xx, yy, zz);
+ }
+
+ static Vector3f transformDirection(float x, float y, float z, float[] transf) {
+ float xx = transf[0] * x + transf[4] * y + transf[8] * z;
+ float yy = transf[1] * x + transf[5] * y + transf[9] * z;
+ float zz = transf[2] * x + transf[6] * y + transf[10] * z;
+ return new Vector3f(xx, yy, zz);
+ }
+
+ /**
+ * Apply the given ambient color to the output.
+ * @param ambient the ambient color.
+ * @param output the color vector to apply the ambient color.
+ * @param additive if true the ambient color is added to output.
+ * @return the resulting color vector.
+ */
+ public static Color[] applyAmbient(Color ambient, Color[] output, boolean additive) {
+ for (int i = 0; i < output.length; ++i) {
+ if (additive) {
+ output[i] = getColorSum(ambient, output[i]);
+ } else {
+ output[i] = ambient;
+ }
+ }
+ return output;
+ }
+
+ /**
+ * Apply the given ambient color to the output.
+ * @param ambient the ambient color.
+ * @param input the input color.
+ * @param output the color vector to apply the ambient color.
+ * @param additive if true the ambient color is added to output.
+ * @return the resulting color vector.
+ */
+ public static Color[] applyAmbient(Color ambient, Color[] input, Color[] output, boolean additive) {
+ for (int i = 0; i < output.length; ++i) {
+ if (additive) {
+ output[i] = getColorSum(getColorProduct(ambient, input[i]), output[i]);
+ } else {
+ output[i] = getColorProduct(ambient, input[i]);
+ }
+ }
+ return output;
+ }
+
+ /**
+ * Apply diffuse light to the output colors
+ * @param light the light position or direction.
+ * @param directional if true the vector light is considered a direction otherwise a position.
+ * @param vertices the surface vertices.
+ * @param normals the surface normals.
+ * @param colors the surface per-vertex colors.
+ * @param dffuse the light diffuse color.
+ * @param output the output color vector.
+ * @param additive if true the calculated diffuse color is added to the output.
+ * @return the resulting color vector.
+ */
+ public static Color[] applyDiffuse(Vector3f light, boolean directional, Vector3f[] vertices, Vector3f[] normals, Color[] colors, Color diffuse, Color[] output, boolean additive) {
+ float ndotl;
+ for (int i = 0; i < colors.length; ++i) {
+
+ if (directional) {
+ ndotl = normals[i].scalar(light);
+ } else {
+ Vector3f ray = light.minus(vertices[i]).getNormalized();
+ ndotl = normals[i].scalar(ray);
+ }
+ ndotl = clamp(ndotl);
+ Color c = getColorProduct(colors[i], diffuse);
+ if (additive) {
+ output[i] = getColorSum(getColorProduct(c, ndotl), output[i]);
+ } else {
+ output[i] = getColorProduct(c, ndotl);
+ }
+ }
+ return output;
+ }
+
+ /**
+ * Apply diffuse light to the output colors
+ * @param light the light position or direction.
+ * @param directional if true the vector light is considered a direction otherwise a position.
+ * @param vertices the surface vertices.
+ * @param normals the surface normals.
+ * @param color the surface color.
+ * @param output the output color vector.
+ * @param additive if true the calculated diffuse color is added to the output.
+ * @return the resulting color vector.
+ */
+ public static Color[] applyDiffuse(Vector3f light, boolean directional, Vector3f[] vertices, Vector3f[] normals, Color color, Color[] output, boolean additive) {
+ float ndotl;
+ for (int i = 0; i < output.length; ++i) {
+
+ if (directional) {
+ ndotl = normals[i].scalar(light);
+ } else {
+ Vector3f ray = light.minus(vertices[i]).getNormalized();
+ ndotl = normals[i].scalar(ray);
+ }
+ ndotl = clamp(ndotl);
+ if (additive) {
+ output[i] = getColorSum(getColorProduct(color, ndotl), output[i]);
+ } else {
+ output[i] = getColorProduct(color, ndotl);
+ }
+ }
+ return output;
+ }
+
+ public static Color[] applySpecular(Vector3f camera, Vector3f light, float shininess, boolean directional, Vector3f[] vertices, Vector3f[] normals, Color specular, Color[] output, boolean additive) {
+
+ for (int i = 0; i < output.length; ++i) {
+
+ Vector3f view = camera.minus(vertices[i]).getNormalized();
+ Vector3f half;
+ float ndotl;
+ if (directional) {
+ half = view.plus(light);
+ ndotl = normals[i].scalar(light);
+ } else {
+ Vector3f ray = light.minus(vertices[i]).getNormalized();
+ half = view.plus(ray);
+ ndotl = normals[i].scalar(ray);
+ }
+ half = half.getNormalized();
+
+ float s = 0.0f;
+ if (ndotl > 0.0f) {
+ s = normals[i].scalar(half);
+ s = clamp(s);
+ s = (float)Math.pow((double)s, (double)shininess);
+ }
+
+ if (additive) {
+ output[i] = getColorSum(getColorProduct(specular, s), output[i]);
+ } else {
+ output[i] = getColorProduct(specular, s);
+ }
+ }
+ return output;
+ }
+
+ /**
+ * Apply a per-vertex lighting to the given colors
+ * @param light the light.
+ * @param mat the material properties.
+ * @param camera the camera position.
+ * @param vertices the surface vertices.
+ * @param normals the surface normals.
+ * @param colors the surface per-vertex colors.
+ * @param output the output color vector.
+ * @param transf the light transformation matrix. If null no transformation is applyed.
+ * @param additive if true the calculated color is added to the output.
+ * @return the resulting color vector.
+ */
+ public static Color[] applyLight(G2DLight light, Material mat, Vector3f camera, Vector3f[] vertices, Vector3f[] normals, Color[] colors, Color[] output, float[] transf, boolean additive) {
+ Color ambient = getColorProduct(mat.getAmbientColor(), light.getAmbientColor());
+ Color diffuse = getColorProduct(mat.getDiffuseColor(), light.getDiffuseColor());
+ Color specular = getColorProduct(mat.getSpecularColor(), light.getSpecularColor());
+
+ Color[] finalColor;
+ if (mat.isColorMaterialEnable()) {
+ finalColor = applyAmbient(light.getAmbientColor(), colors, output, additive);
+ } else {
+ finalColor = applyAmbient(ambient, output, additive);
+ }
+
+ float[] v;
+ if (light.isPoint()) {
+ v = light.getPosition().getDataAsFloatArray();
+ } else {
+ v = light.getDirection().getDataAsFloatArray();
+ }
+
+ Vector3f vec;
+ if (transf != null && transf.length == 16) {
+ if (light.isPoint()) {
+ vec = transform(v[0], v[1], v[2], transf);
+ } else {
+ vec = transformDirection(v[0], v[1], v[2], transf).getNormalized();
+ }
+ } else {
+ vec = new Vector3f(v[0], v[1], v[2]);
+ }
+
+ if (mat.isColorMaterialEnable()) {
+ finalColor = applyDiffuse(vec, !light.isPoint(), vertices, normals, colors, light.getDiffuseColor(), finalColor, true);
+ } else {
+ finalColor = applyDiffuse(vec, !light.isPoint(), vertices, normals, diffuse, finalColor, true);
+ }
+
+ finalColor = applySpecular(camera, vec, mat.getShininess(), !light.isPoint(), vertices, normals, specular, finalColor, true);
+
+ return finalColor;
+ }
+
+ /**
+ * return the product of the given colors
+ */
+ private static Color getColorProduct(Color a, Color b) {
+ float[] ca = a.getComponents(null);
+ float[] cb = b.getComponents(null);
+ return new Color(ca[0] * cb[0], ca[1] * cb[1], ca[2] * cb[2]);
+ }
+
+ /**
+ * return the clamped product of the color
+ */
+ private static Color getColorProduct(Color a, float f) {
+ float[] ca = a.getComponents(null);
+ return new Color(clamp(ca[0] * f), clamp(ca[1] * f), clamp(ca[2] * f));
+ }
+
+ /**
+ * return the clamped sum of the given colors
+ */
+ private static Color getColorSum(Color a, Color b) {
+ float[] ca = a.getComponents(null);
+ float[] cb = b.getComponents(null);
+ return new Color(clamp(ca[0] + cb[0]), clamp(ca[1] + cb[1]), clamp(ca[2] + cb[2]));
+ }
+
+ /**
+ * Clamp the given value to [0, 1]
+ */
+ private static float clamp(float f) {
+ f = f < 0.0f ? 0.0f : f;
+ f = f > 1.0f ? 1.0f : f;
+ return f;
+ }
+
+ static Vector3f reflect(Vector3f I, Vector3f N) {
+ return I.minus(N.times(2 * I.scalar(N)));
+ }
+}
diff --git a/modules/scirenderer/src/org/scilab/forge/scirenderer/implementation/g2d/motor/Motor3D.java b/modules/scirenderer/src/org/scilab/forge/scirenderer/implementation/g2d/motor/Motor3D.java
new file mode 100755
index 000000000..9b6be63b7
--- /dev/null
+++ b/modules/scirenderer/src/org/scilab/forge/scirenderer/implementation/g2d/motor/Motor3D.java
@@ -0,0 +1,617 @@
+/*
+ * Scilab ( http://www.scilab.org/ ) - This file is part of Scilab
+ * Copyright (C) 2012-2013 - Scilab Enterprises - Calixte Denizet
+ *
+ * This file must be used under the terms of the CeCILL.
+ * This source file is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at
+ * http://www.cecill.info/licences/Licence_CeCILL_V2.1-en.txt
+ */
+
+package org.scilab.forge.scirenderer.implementation.g2d.motor;
+
+import java.awt.Color;
+import java.awt.Dimension;
+import java.awt.Graphics2D;
+import java.awt.RenderingHints;
+import java.awt.image.BufferedImage;
+import java.nio.FloatBuffer;
+import java.nio.IntBuffer;
+import java.util.Arrays;
+import java.util.List;
+
+import org.scilab.forge.scirenderer.DrawingTools;
+import org.scilab.forge.scirenderer.buffers.ElementsBuffer;
+import org.scilab.forge.scirenderer.clipping.ClippingPlane;
+import org.scilab.forge.scirenderer.implementation.g2d.G2DCanvas;
+import org.scilab.forge.scirenderer.implementation.g2d.buffers.G2DElementsBuffer;
+import org.scilab.forge.scirenderer.implementation.g2d.texture.G2DTextureDrawingTools;
+import org.scilab.forge.scirenderer.implementation.g2d.texture.G2DTextureManager;
+import org.scilab.forge.scirenderer.shapes.appearance.Appearance;
+import org.scilab.forge.scirenderer.shapes.geometry.Geometry;
+import org.scilab.forge.scirenderer.shapes.geometry.Geometry.FaceCullingMode;
+import org.scilab.forge.scirenderer.texture.AnchorPosition;
+import org.scilab.forge.scirenderer.texture.Texture;
+import org.scilab.forge.scirenderer.tranformations.Transformation;
+import org.scilab.forge.scirenderer.tranformations.Vector3d;
+import org.scilab.forge.scirenderer.tranformations.Vector3f;
+
+import org.scilab.forge.scirenderer.lightning.Light;
+import org.scilab.forge.scirenderer.lightning.LightManager;
+import org.scilab.forge.scirenderer.implementation.g2d.lighting.G2DLight;
+import org.scilab.forge.scirenderer.implementation.g2d.lighting.G2DLightManager;
+import org.scilab.forge.scirenderer.shapes.appearance.Material;
+
+/**
+ * @author Calixte DENIZET
+ */
+public class Motor3D {
+
+ private Transformation transf;
+ private Transformation singleTransf;
+ private FaceCullingMode mode = FaceCullingMode.BOTH;
+ private Graphics2D g2d;
+ private Dimension dim;
+ private G2DTextureDrawingTools textureDrawingTools;
+ private G2DCanvas canvas;
+
+ /**
+ * Default constructor
+ * @param g2d a Graphics2D object where to draw
+ * @param dim the graphic dimensions
+ */
+ public Motor3D(G2DCanvas canvas, Graphics2D g2d, Dimension dim) {
+ this.canvas = canvas;
+ this.g2d = g2d;
+ this.dim = dim;
+ this.textureDrawingTools = new G2DTextureDrawingTools(g2d);
+ AbstractDrawable3DObject.resetDefaultPrecedence();
+ }
+
+ public void setGraphics(Graphics2D g2d) {
+ this.g2d = g2d;
+ this.textureDrawingTools.setGraphics(g2d);
+ }
+
+ public void setAntialiased(boolean aa) {
+ if (aa) {
+ g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
+ } else {
+ g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_OFF);
+ }
+ }
+
+ public boolean is2DView() {
+ return canvas.getMainDrawer().is2DView();
+ }
+
+ public void setClippingPlanes(List<ClippingPlane> clippingPlanes) {
+ Scene.setClippingPlanes(clippingPlanes);
+ }
+
+ /**
+ * Set the face culling mode
+ * @param mode the mode to set
+ */
+ public void setFaceCullingMode(FaceCullingMode mode) {
+ this.mode = mode;
+ }
+
+ /**
+ * Set the current transformation
+ * @param transf the transformation to set
+ */
+ public void setTransformation(Transformation transf, Transformation single) {
+ this.transf = transf;
+ this.singleTransf = single;
+ }
+
+ public Transformation getCurrentTransformation() {
+ return transf;
+ }
+
+ public Transformation getCurrentSingleTransformation() {
+ return singleTransf;
+ }
+
+ /**
+ * Reset this motor
+ * @param color the filling color
+ */
+ public void reset(Color color) {
+ transf = null;
+ mode = FaceCullingMode.BOTH;
+ g2d.setColor(color);
+ g2d.fillRect(0, 0, (int) dim.getWidth(), (int) dim.getHeight());
+ Scene.clear();
+ }
+
+ /**
+ * Clear the depth buffer
+ */
+ public void clearDepth() {
+ Scene.clearDepth();
+ }
+
+ /**
+ * Draw the scene in the Graphics2D
+ */
+ public void draw() {
+ Scene.drawRoot(g2d);
+ clean();
+ }
+
+ public void clean() {
+ Scene.clearAll();
+ G2DTextureManager.clear();
+ }
+
+ public void drawTexture(DrawingTools drawingTools, BufferedImage image, Texture texture) {
+ try {
+ SpritedRectangle o = new SpritedRectangle(new Vector3d(0, 0, 0), transf, image, texture.getMagnificationFilter());
+ add(o);
+ } catch (InvalidPolygonException e) { }
+ }
+
+ /**
+ * Add the geometry to the scene
+ * @param drawingTools the DrawingTools
+ * @param geometry the geometry to draw
+ * @param appearance the appearance to use
+ */
+ public void draw(DrawingTools drawingTools, Geometry geometry, Appearance appearance) {
+ setFaceCullingMode(geometry.getFaceCullingMode());
+ FloatBuffer vertexBuffer = geometry.getVertices().getData();
+
+ IntBuffer indicesBuffer = null;;
+ if (geometry.getIndices() != null) {
+ indicesBuffer = geometry.getIndices().getData();
+ }
+
+ IntBuffer wireIndicesBuffer = null;
+ if (geometry.getWireIndices() != null) {
+ wireIndicesBuffer = geometry.getWireIndices().getData();
+ }
+
+ FloatBuffer colorBuffer = null;
+ if (geometry.getColors() != null) {
+ colorBuffer = geometry.getColors().getData();
+ }
+
+ FloatBuffer normalBuffer = null;
+ if (geometry.getNormals() != null) {
+ normalBuffer = geometry.getNormals().getData();
+ }
+
+ Texture texture = appearance.getTexture();
+ FloatBuffer textureCoordinatesBuffer = null;
+ BufferedImage image = null;
+ if (texture != null && geometry.getTextureCoordinates() != null) {
+ textureCoordinatesBuffer = geometry.getTextureCoordinates().getData();
+ image = ((G2DTextureManager.G2DTexture) texture).getImage();
+ }
+
+ G2DLightManager lm = (G2DLightManager)drawingTools.getLightManager();
+ lm.setMaterial(appearance.getMaterial());
+
+ if (geometry.getFillDrawingMode() != Geometry.FillDrawingMode.NONE) {
+ addTriangles(vertexBuffer, normalBuffer, colorBuffer, appearance.getFillColor(), indicesBuffer, textureCoordinatesBuffer, image, texture, geometry.getFillDrawingMode(), lm);
+ }
+
+ if (geometry.getLineDrawingMode() != Geometry.LineDrawingMode.NONE) {
+ if (appearance.getLineColor() == null) {
+ addSegments(vertexBuffer, colorBuffer, null, wireIndicesBuffer, geometry.getLineDrawingMode(), appearance);
+ } else {
+ addSegments(vertexBuffer, null, appearance.getLineColor(), wireIndicesBuffer, geometry.getLineDrawingMode(), appearance);
+ }
+ }
+ }
+
+ public void draw(DrawingTools drawingTools, Texture texture, AnchorPosition anchor, ElementsBuffer positions, int offset, int stride, double rotationAngle) {
+ FloatBuffer positionsBuffer = positions.getData();
+ float[] buffer;
+ offset = offset < 0 ? 0 : offset;
+ stride = stride < 1 ? 1 : stride;
+
+ positionsBuffer.rewind();
+ if (positionsBuffer.hasArray()) {
+ buffer = positionsBuffer.array();
+ } else {
+ buffer = new float[positionsBuffer.limit()];
+ positionsBuffer.get(buffer);
+ }
+
+ Vector3d[] verticesArray = getMultiVectors(buffer, transf, false);
+ for (int i = offset; i < verticesArray.length; i += stride) {
+ try {
+ SpritedRectangle o = new SpritedRectangle(verticesArray[i], texture, anchor, textureDrawingTools, rotationAngle);
+ add(o);
+ } catch (InvalidPolygonException e) { }
+ }
+ }
+
+ public void draw(DrawingTools drawingTools, Texture texture, AnchorPosition anchor, Vector3d position, double rotationAngle) {
+ try {
+ add(new SpritedRectangle(transf.project(position), texture, anchor, textureDrawingTools, rotationAngle));
+ } catch (InvalidPolygonException e) { }
+ }
+
+ /**
+ * Add a Triangle to the scene
+ * @param tri the triangle to add
+ */
+ private void add(Triangle tri) {
+ final boolean is2d = is2DView();
+ if (is2d) {
+ Scene.addToRoot(is2d, tri);
+ } else {
+ Vector3d normal = tri.getNormal();
+ if (normal != null) {
+ //normal = transf.projectDirection(normal);
+ if ((mode == FaceCullingMode.CW && normal.getZ() > 0) || (mode == FaceCullingMode.CCW && normal.getZ() < 0) || mode == FaceCullingMode.BOTH) {
+ Scene.addToRoot(is2d, tri);
+ }
+ } else {
+ Scene.addToRoot(is2d, tri);
+ }
+ }
+ }
+
+ /**
+ * Add a segment to the scene
+ * @param s the segment to add
+ */
+ private void add(Segment s) {
+ Scene.addToRoot(is2DView(), s);
+ }
+
+ private void add(SpritedRectangle sprite) {
+ Scene.addToRoot(is2DView(), sprite);
+ }
+
+ private void add(PolyLine p) {
+ Scene.addToRoot(is2DView(), p);
+ }
+
+ /**
+ * Get arrays from Buffer
+ * @param vertices a buffer containing vertices
+ * @param colors a buffer containing the colors
+ * @param defaultColor the color to use when colors is null
+ * @param indices a buffer containg the index of the vertices to retrieve
+ * @return an array of length 2 containing the vertices array and the colors array
+ */
+ private Object[] getArrays(FloatBuffer vertices, FloatBuffer colors, Color defaultColor, FloatBuffer textureCoords, IntBuffer indices) {
+ float[] buffer;
+ Vector3d[] verticesArray;
+ Vector3d[] textureCoordsArray = null;
+ Color[] colorsArray;
+
+ vertices.rewind();
+ if (vertices.hasArray()) {
+ buffer = vertices.array();
+ } else {
+ buffer = new float[vertices.limit()];
+ vertices.get(buffer);
+ }
+ verticesArray = getMultiVectors(buffer, transf, false);
+
+ if (colors != null) {
+ colors.rewind();
+ if (colors.hasArray()) {
+ buffer = colors.array();
+ } else {
+ buffer = new float[colors.limit()];
+ colors.get(buffer);
+ }
+ colorsArray = getMultiColors(buffer);
+ } else {
+ colorsArray = new Color[vertices.limit() / G2DElementsBuffer.ELEMENT_SIZE];
+ Arrays.fill(colorsArray, defaultColor);
+ }
+
+ if (textureCoords != null) {
+ textureCoords.rewind();
+ if (textureCoords.hasArray()) {
+ buffer = textureCoords.array();
+ } else {
+ buffer = new float[textureCoords.limit()];
+ textureCoords.get(buffer);
+ }
+ textureCoordsArray = getMultiVectors(buffer);
+ }
+
+ if (indices != null) {
+ indices.rewind();
+ int[] ind;
+ if (indices.hasArray()) {
+ ind = indices.array();
+ } else {
+ ind = new int[indices.limit()];
+ indices.get(ind);
+ }
+ Vector3d[] va = new Vector3d[ind.length];
+ Color[] ca = new Color[ind.length];
+ Vector3d[] ta = null;
+ if (textureCoords != null) {
+ ta = new Vector3d[ind.length];
+ }
+
+ for (int i = 0; i < ind.length; i++) {
+ va[i] = verticesArray[ind[i]];
+ ca[i] = colorsArray[ind[i]];
+ if (ta != null) {
+ ta[i] = textureCoordsArray[ind[i]];
+ }
+ }
+ verticesArray = va;
+ colorsArray = ca;
+ textureCoordsArray = ta;
+ }
+
+ return new Object[] {verticesArray, colorsArray, textureCoordsArray};
+ }
+
+ /**
+ * Convert the buffer vertices into vertices array and put the segments in the scene
+ * @param vertices a buffer containing vertices
+ * @param colors a buffer containing the colors
+ * @param defaultColor the color to use when colors is null
+ * @param indices a buffer containg the index of the vertices to retrieve
+ * @param drawingMode the drawing mode
+ * @param stroke the Stroke to use to draw a segment
+ */
+ private void addSegments(FloatBuffer vertices, FloatBuffer colors, Color defaultColor, IntBuffer indices, Geometry.LineDrawingMode drawingMode, Appearance appearance) {
+ Object[] arrays = getArrays(vertices, colors, defaultColor, null, indices);
+ Vector3d[] verticesArray = (Vector3d[]) arrays[0];
+ Color[] colorsArray = (Color[]) arrays[1];
+ Vector3d[] v;
+ Color[] c;
+ double cumLength = 0;
+
+ if (verticesArray.length <= 1) {
+ return;
+ }
+
+ switch (drawingMode) {
+ case SEGMENTS_STRIP :
+ if (is2DView()) {
+ List<PolyLine> list = PolyLine.getPolyLines(verticesArray, colorsArray, G2DStroke.getStroke(appearance, 0), false);
+ for (PolyLine p : list) {
+ add(p);
+ }
+ } else {
+ for (int i = 0; i < verticesArray.length - 1; i++) {
+ v = new Vector3d[] {verticesArray[i], verticesArray[i + 1]};
+ c = new Color[] {colorsArray[i], colorsArray[i + 1]};
+ try {
+ add(new Segment(v, c, G2DStroke.getStroke(appearance, cumLength), false));
+ cumLength += Segment.getLength(v);
+ } catch (InvalidPolygonException e) {
+ cumLength = 0;
+ }
+ }
+ }
+ break;
+ case SEGMENTS_LOOP :
+ if (is2DView()) {
+ List<PolyLine> list = PolyLine.getPolyLines(verticesArray, colorsArray, G2DStroke.getStroke(appearance, 0), true);
+ for (PolyLine p : list) {
+ add(p);
+ }
+ } else {
+ for (int i = 0; i < verticesArray.length - 1; i++) {
+ v = new Vector3d[] {verticesArray[i], verticesArray[i + 1]};
+ c = new Color[] {colorsArray[i], colorsArray[i + 1]};
+ try {
+ add(new Segment(v, c, G2DStroke.getStroke(appearance, cumLength), false));
+ cumLength += Segment.getLength(v);
+ } catch (InvalidPolygonException e) {
+ cumLength = 0;
+ }
+ }
+ int n = verticesArray.length - 1;
+ v = new Vector3d[] {verticesArray[n], verticesArray[0]};
+ c = new Color[] {colorsArray[n], colorsArray[0]};
+ try {
+ add(new Segment(v, c, G2DStroke.getStroke(appearance, cumLength), false));
+ } catch (InvalidPolygonException e) { }
+ }
+ break;
+ case SEGMENTS :
+ default :
+ for (int i = 0; i < verticesArray.length - 1; i += 2) {
+ v = new Vector3d[] {verticesArray[i], verticesArray[i + 1]};
+ c = new Color[] {colorsArray[i], colorsArray[i + 1]};
+ try {
+ add(new Segment(v, c, G2DStroke.getStroke(appearance, 0), is2DView()));
+ } catch (InvalidPolygonException e) { }
+ }
+ break;
+ }
+ }
+
+ /**
+ * Convert the buffer vertices into vertices array and put the triangles in the scene
+ * @param vertices a buffer containing vertices
+ * @param normals a buffer containing the normals (not used)
+ * @param colors a buffer containing the colors
+ * @param defaultColor the color to use when colors is null
+ * @param indices a buffer containg the index of the vertices to retrieve
+ * @param drawingMode the drawing mode
+ */
+ 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) {
+ Object[] arrays = getArrays(vertices, colors, defaultColor, textureCoords, indices);
+ Vector3d[] verticesArray = (Vector3d[]) arrays[0];
+ Color[] colorsArray = (Color[]) arrays[1];
+ Vector3d[] textureCoordsArray = (Vector3d[]) arrays[2];
+ Vector3d[] v;
+ Color[] c;
+ Texture.Filter filter = Texture.Filter.NEAREST;
+
+ if (texture != null) {
+ filter = texture.getMagnificationFilter();
+ }
+
+ colorsArray = applyLighting(vertices, normals, indices, colorsArray, lightManager);
+
+ switch (drawingMode) {
+ case TRIANGLE_FAN :
+ for (int i = 1; i < verticesArray.length - 1; i++) {
+ v = new Vector3d[] {verticesArray[0], verticesArray[i], verticesArray[i + 1]};
+ try {
+ if (image == null) {
+ c = new Color[] {colorsArray[0], colorsArray[i], colorsArray[i + 1]};
+ add(new Triangle(v, c, null));
+ } else {
+ add(new Triangle(v, new Vector3d[] {textureCoordsArray[0], textureCoordsArray[i], textureCoordsArray[i + 1]}, image, filter));
+ }
+ } catch (InvalidPolygonException e) { }
+ }
+ int n = verticesArray.length - 1;
+ v = new Vector3d[] {verticesArray[0], verticesArray[n], verticesArray[1]};
+ try {
+ if (image == null) {
+ c = new Color[] {colorsArray[0], colorsArray[n], colorsArray[1]};
+ add(new Triangle(v, c, null));
+ } else {
+ add(new Triangle(v, new Vector3d[] {textureCoordsArray[0], textureCoordsArray[n], textureCoordsArray[1]}, image, filter));
+ }
+ } catch (InvalidPolygonException e) { }
+ break;
+ case TRIANGLE_STRIP :
+ for (int i = 0; i < verticesArray.length - 2; i++) {
+ v = new Vector3d[] {verticesArray[i], verticesArray[i + 1], verticesArray[i + 2]};
+ try {
+ if (image == null) {
+ c = new Color[] {colorsArray[i], colorsArray[i + 1], colorsArray[i + 2]};
+ add(new Triangle(v, c, null));
+ } else {
+ add(new Triangle(v, new Vector3d[] {textureCoordsArray[i], textureCoordsArray[i + 1], textureCoordsArray[i + 2]}, image, filter));
+ }
+ } catch (InvalidPolygonException e) { }
+ }
+ break;
+ case TRIANGLES :
+ default :
+ for (int i = 0; i < verticesArray.length - 2; i += 3) {
+ v = new Vector3d[] {verticesArray[i], verticesArray[i + 1], verticesArray[i + 2]};
+ try {
+ if (image == null) {
+ c = new Color[] {colorsArray[i], colorsArray[i + 1], colorsArray[i + 2]};
+ add(new Triangle(v, c, null));
+ } else {
+ add(new Triangle(v, new Vector3d[] {textureCoordsArray[i], textureCoordsArray[i + 1], textureCoordsArray[i + 2]}, image, filter));
+ }
+ } catch (InvalidPolygonException e) { }
+ }
+ break;
+ }
+ }
+
+ /**
+ * Convert an array of float into an array of Vector3d objects
+ * @param vertices an array of float containing (vertices.length / G2DElementsBuffer.ELEMENT_SIZE) vectors coordinates
+ * @param t the transformation to use for the projection
+ * @param dir if true t.projectDirection() is used rather than t.project()
+ * @return an array of Vector3d containg the vertices
+ */
+ private static final Vector3d[] getMultiVectors(final float[] vertices, final Transformation t, final boolean dir) {
+ Vector3d[] v = new Vector3d[vertices.length / G2DElementsBuffer.ELEMENT_SIZE];
+ if (dir) {
+ int j = 0;
+ for (int i = 0; i < v.length; i++) {
+ v[i] = t.projectDirection(new Vector3d(vertices[j], vertices[j + 1], vertices[j + 2]));
+ j += G2DElementsBuffer.ELEMENT_SIZE;
+ }
+ } else {
+ int j = 0;
+ for (int i = 0; i < v.length; i++) {
+ v[i] = t.project(new Vector3d(vertices[j], vertices[j + 1], vertices[j + 2]));
+ j += G2DElementsBuffer.ELEMENT_SIZE;
+ }
+ }
+
+ return v;
+ }
+
+ /**
+ * Convert an array of float into an array of Vector3d objects
+ * @param vertices an array of float containing (vertices.length / G2DElementsBuffer.ELEMENT_SIZE) vectors coordinates
+ * @return an array of Vector3d containg the vertices
+ */
+ private static final Vector3d[] getMultiVectors(final float[] vertices) {
+ Vector3d[] v = new Vector3d[vertices.length / G2DElementsBuffer.ELEMENT_SIZE];
+ int j = 0;
+ for (int i = 0; i < v.length; i++) {
+ v[i] = new Vector3d(vertices[j], vertices[j + 1], vertices[j + 2]);
+ j += G2DElementsBuffer.ELEMENT_SIZE;
+ }
+
+ return v;
+ }
+
+ /**
+ * Convert a float array into a Color array
+ * @param colors a float array
+ * @return an array of Color
+ */
+ private static final Color[] getMultiColors(final float[] colors) {
+ Color[] c = new Color[colors.length / G2DElementsBuffer.ELEMENT_SIZE];
+ int j = 0;
+ Color prev = Color.BLACK;
+ for (int i = 0; i < c.length; i++) {
+ c[i] = new Color(colors[j], colors[j + 1], colors[j + 2], colors[j + 3]);
+ if (prev.equals(c[i])) {
+ c[i] = prev;
+ }
+ prev = c[i];
+ j += G2DElementsBuffer.ELEMENT_SIZE;
+ }
+
+ return c;
+ }
+
+ /**
+ * Perform per-vertex lighting
+ */
+ private Color[] applyLighting(FloatBuffer vertices, FloatBuffer normals, IntBuffer index, Color[] colors, G2DLightManager lightManager) {
+
+ if (!lightManager.isLightningEnable() || vertices == null || normals == null
+ || index == null || colors == null) {
+ return colors;
+ }
+
+ Material mat = lightManager.getMaterial();
+ if (mat == null) {
+ return colors;
+ }
+
+ float[] vertexTransf = lightManager.getVertexTransform();
+ float[] normalTransf = lightManager.getNormalTransform();
+ //for transformed vertices camera is at origin.
+ Vector3f camera = new Vector3f(0.f, 0.f , 0.f);
+ Vector3f[] vertexArray = LightHelper.getIndexedVector3f(vertices, index, G2DElementsBuffer.ELEMENT_SIZE, vertexTransf);
+ Vector3f[] normalArray = LightHelper.getIndexedVector3f(normals, index, G2DElementsBuffer.ELEMENT_SIZE, normalTransf);
+
+ for (int i = 0; i < normalArray.length; ++i) {
+ normalArray[i] = normalArray[i].getNormalized();
+ }
+
+
+ Color[] outColors = new Color[colors.length];
+ boolean first = true;
+ for (int i = 0; i < lightManager.getLightNumber(); ++i) {
+ G2DLight l = (G2DLight)lightManager.getLight(i);
+
+ if (l == null || !l.isEnable()) {
+ continue;
+ }
+
+ outColors = LightHelper.applyLight(l, mat, camera, vertexArray, normalArray, colors, outColors, vertexTransf, !first);
+ first = false;
+ }
+ return outColors;
+ }
+}
diff --git a/modules/scirenderer/src/org/scilab/forge/scirenderer/implementation/g2d/motor/PolyLine.java b/modules/scirenderer/src/org/scilab/forge/scirenderer/implementation/g2d/motor/PolyLine.java
new file mode 100755
index 000000000..095e65bb6
--- /dev/null
+++ b/modules/scirenderer/src/org/scilab/forge/scirenderer/implementation/g2d/motor/PolyLine.java
@@ -0,0 +1,317 @@
+/*
+ * Scilab ( http://www.scilab.org/ ) - This file is part of Scilab
+ * Copyright (C) 2013 - Scilab Enterprises - Calixte Denizet
+ *
+ * This file must be used under the terms of the CeCILL.
+ * This source file is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at
+ * http://www.cecill.info/licences/Licence_CeCILL_V2.1-en.txt
+ */
+
+package org.scilab.forge.scirenderer.implementation.g2d.motor;
+
+import java.awt.Color;
+import java.awt.Shape;
+import java.awt.Stroke;
+import java.awt.geom.Line2D;
+import java.awt.geom.Path2D;
+import java.awt.Graphics2D;
+import java.util.ArrayList;
+import java.util.List;
+
+import org.scilab.forge.scirenderer.tranformations.Vector3d;
+import org.scilab.forge.scirenderer.tranformations.Vector4d;
+
+/**
+ * Class to represent a polyline object. This is used only in 2D (in 3D, a line could begin
+ * on front of a face and could end behind it).
+ * This allows to draw a polyline like a polyline ! and not as a set of segments.
+ * Notice that a PolyLine is NOT a convex object... but in 2D it does not matter, algorithms
+ * which use the convexity are not applyed.
+ *
+ * @author Calixte DENIZET
+ */
+public class PolyLine extends ConvexObject {
+
+ private boolean monochromatic;
+ private G2DStroke stroke;
+ protected double[] clip = new double[] {Double.NaN, Double.NaN, Double.NaN, Double.NaN};
+
+ /**
+ * Default constructor
+ * @param vertices the polyline vertices
+ * @param colors the vertices color
+ * @param stroke the stroke to used
+ */
+ public PolyLine(Vector3d[] vertices, Color[] colors, G2DStroke stroke) throws InvalidPolygonException {
+ super(vertices, colors);
+ if (vertices.length <= 1) {
+ throw new InvalidPolygonException("A polyline cannot have one or zero point");
+ }
+
+ this.monochromatic = isMonochromatic(colors);
+ this.stroke = stroke;
+ }
+
+ /**
+ * Get a set of polylines. The Nan of Inf vectors are removed and so the polyline is splitted.
+ * @param vertices the polyline vertices
+ * @param colors the vertices color
+ * @param stroke the stroke to used
+ * @param loop if true a looping polyline is created
+ * @return a set of polylines
+ */
+ public static List<PolyLine> getPolyLines(Vector3d[] vertices, Color[] colors, G2DStroke stroke, boolean loop) {
+ if (loop) {
+ Vector3d[] v = new Vector3d[vertices.length + 1];
+ Color[] c = new Color[vertices.length + 1];
+ for (int i = 0; i < vertices.length; i++) {
+ v[i] = vertices[i];
+ c[i] = colors[i];
+ }
+ v[vertices.length] = v[0];
+ c[vertices.length] = c[0];
+ vertices = v;
+ colors = c;
+ }
+
+ int pos = 0;
+ List<PolyLine> list = new ArrayList<PolyLine>(1);
+ while ((pos = trimLeft(vertices, pos)) != -1) {
+ final int second = findNanOrInf(vertices, pos + 1);
+ final int len = second - pos;
+ final Vector3d[] newVertices = new Vector3d[len];
+ final Color[] newColors = new Color[len];
+ for (int i = 0; i < len; i++) {
+ newVertices[i] = vertices[pos + i];
+ newColors[i] = colors[pos + i];
+ }
+ pos = second + 1;
+ try {
+ list.add(new PolyLine(newVertices, newColors, stroke));
+ } catch (InvalidPolygonException e) { }
+ }
+
+ return list;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public List<ConvexObject> breakObject(Vector4d v) {
+ final double[] vv = v.getData();
+ final List<ConvexObject> list = new ArrayList<ConvexObject>(1);
+
+ // Since PolyLine are only used in 2D it is useless to check when z != 0
+ if (vv[2] == 0) {
+ final Vector3d np = new Vector3d(vv);
+ ConvexObject.makeClip(clip, vv);
+
+ int pos = 0;
+ boolean prev = false;
+
+ for (int i = 0; i < vertices.length; i++) {
+ final boolean b = isBehind(vertices[i], np, vv[3]);
+ if (b && !prev) {
+ pos = i;
+ prev = true;
+ } else if (!b && prev) {
+ prev = false;
+ try {
+ list.add(cut(pos, i, np, vv[3]));
+ } catch (InvalidPolygonException e) { }
+ }
+ }
+
+ if (prev) {
+ try {
+ list.add(cut(pos, vertices.length, np, vv[3]));
+ } catch (InvalidPolygonException e) { }
+ }
+ } else {
+ list.add(this);
+ }
+
+ return list;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public List<ConvexObject> breakObject(ConvexObject o) {
+ return null;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ protected boolean isDegenerate() {
+ return false;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ protected boolean isNanOrInf() {
+ return false;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public Vector3d getNormal() {
+ // Never used
+ return null;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ protected boolean isPlanar() {
+ // Never used
+ return true;
+ }
+
+ /**
+ * Cut a polyline on a clipping plane
+ * @param first the first vertex position
+ * @param second the second vertex position
+ * @param np the normal vector of the clipping plane
+ * @param C the constant part of the hyperplane
+ * @return a cutted PolyLine
+ */
+ private PolyLine cut(int first, int second, Vector3d np, double C) throws InvalidPolygonException {
+ final boolean cutAtBegin = first != 0;
+ final boolean cutAtEnd = second != vertices.length;
+
+ if (!cutAtBegin && !cutAtEnd) {
+ return this;
+ }
+
+ if (cutAtBegin && cutAtEnd) {
+ final int len = second - first + 2;
+
+ Vector3d[] newVertices = new Vector3d[len];
+ Color[] newColors = new Color[len];
+
+ for (int i = 1; i < len - 1; i++) {
+ newVertices[i] = vertices[first + i - 1];
+ newColors[i] = getColor(first + i - 1);
+ }
+
+ double c = (C + vertices[first].scalar(np)) / vertices[first].minus(vertices[first - 1]).scalar(np);
+ newVertices[0] = Vector3d.getBarycenter(vertices[first - 1], vertices[first], c, 1 - c);
+ newColors[0] = getColorsBarycenter(getColor(first - 1), getColor(first), c, 1 - c);
+
+ c = (C + vertices[second].scalar(np)) / vertices[second].minus(vertices[second - 1]).scalar(np);
+ newVertices[len - 1] = Vector3d.getBarycenter(vertices[second - 1], vertices[second], c, 1 - c);
+ newColors[len - 1] = getColorsBarycenter(getColor(second - 1), getColor(second), c, 1 - c);
+
+ return new PolyLine(newVertices, newColors, this.stroke);
+ }
+
+ if (cutAtBegin) {
+ final double c = (C + vertices[first].scalar(np)) / vertices[first].minus(vertices[first - 1]).scalar(np);
+ final int len = second - first + 1;
+
+ Vector3d[] newVertices = new Vector3d[len];
+ Color[] newColors = new Color[len];
+
+ for (int i = 1; i < len; i++) {
+ newVertices[i] = vertices[first + i - 1];
+ newColors[i] = getColor(first + i - 1);
+ }
+
+ newVertices[0] = Vector3d.getBarycenter(vertices[first - 1], vertices[first], c, 1 - c);
+ newColors[0] = getColorsBarycenter(getColor(first - 1), getColor(first), c, 1 - c);
+
+ return new PolyLine(newVertices, newColors, this.stroke);
+ } else {
+ final double c = (C + vertices[second].scalar(np)) / vertices[second].minus(vertices[second - 1]).scalar(np);
+ final int len = second - first + 1;
+
+ Vector3d[] newVertices = new Vector3d[len];
+ Color[] newColors = new Color[len];
+
+ for (int i = 0; i < len - 1; i++) {
+ newVertices[i] = vertices[first + i];
+ newColors[i] = getColor(first + i);
+ }
+
+ newVertices[len - 1] = Vector3d.getBarycenter(vertices[second - 1], vertices[second], c, 1 - c);
+ newColors[len - 1] = getColorsBarycenter(getColor(second - 1), getColor(second), c, 1 - c);
+ return new PolyLine(newVertices, newColors, this.stroke);
+ }
+ }
+
+ @Override
+ public void draw(Graphics2D g2d) {
+ Stroke oldStroke = g2d.getStroke();
+ Shape oldClip = g2d.getClip();
+
+ Shape newClip = ConvexObject.getClip(clip);
+ if (newClip != null) {
+ g2d.clip(newClip);
+ }
+
+ if (monochromatic) {
+ g2d.setColor(getColor(0));
+ g2d.setStroke(stroke);
+ g2d.draw(getProjectedPolyLine());
+ } else {
+ // on peut surement faire mieux ici
+ // avec un LinearGradientPaint
+ Vector3d start = vertices[0];
+ Color color = getColor(0);
+ double cumLen = 0;
+ float[] dashArray = stroke.getDashArray();
+ float lwidth = stroke.getLineWidth();
+ for (int i = 1; i < vertices.length; i++) {
+ Stroke nstroke = new G2DStroke(lwidth, dashArray, (float) cumLen);
+ g2d.setStroke(nstroke);
+ g2d.setColor(color);
+ g2d.draw(new Line2D.Double(start.getX(), start.getY(), vertices[i].getX(), vertices[i].getY()));
+ cumLen += Math.hypot(start.getX() - vertices[i].getX(), start.getY() - vertices[i].getY());
+ }
+ }
+
+ if (newClip != null) {
+ g2d.setClip(oldClip);
+ }
+
+ g2d.setStroke(oldStroke);
+ }
+
+ /**
+ * Get first non Nan (or Inf) vector position
+ * @param v the array to trim
+ * @param start the starting position
+ * @return index of the first non Nan vector or -1 if not found
+ */
+ private static int trimLeft(Vector3d[] v, int start) {
+ for (int i = start; i < v.length; i++) {
+ if (!isNanOrInf(v[i])) {
+ return i;
+ }
+ }
+
+ return -1;
+ }
+
+ /**
+ * Get first Nan (or Inf) vector position
+ * @param v the array to trim
+ * @param start the starting position
+ * @return index of the first Nan vector
+ */
+ private static int findNanOrInf(Vector3d[] v, int start) {
+ for (int i = start; i < v.length; i++) {
+ if (isNanOrInf(v[i])) {
+ return i;
+ }
+ }
+
+ return v.length;
+ }
+}
diff --git a/modules/scirenderer/src/org/scilab/forge/scirenderer/implementation/g2d/motor/Scene.java b/modules/scirenderer/src/org/scilab/forge/scirenderer/implementation/g2d/motor/Scene.java
new file mode 100755
index 000000000..06d429b81
--- /dev/null
+++ b/modules/scirenderer/src/org/scilab/forge/scirenderer/implementation/g2d/motor/Scene.java
@@ -0,0 +1,250 @@
+/*
+ * Scilab ( http://www.scilab.org/ ) - This file is part of Scilab
+ * Copyright (C) 2012 - Scilab Enterprises - Calixte Denizet
+ *
+ * This file must be used under the terms of the CeCILL.
+ * This source file is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at
+ * http://www.cecill.info/licences/Licence_CeCILL_V2.1-en.txt
+ */
+
+package org.scilab.forge.scirenderer.implementation.g2d.motor;
+
+import java.awt.Graphics2D;
+import java.util.ArrayList;
+import java.util.Comparator;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+import java.util.Stack;
+import java.util.TreeSet;
+
+import org.scilab.forge.scirenderer.clipping.ClippingPlane;
+
+final class Scene {
+
+ private static Set<Scene> faces2d = new TreeSet<Scene>(new Comparator<Scene>() {
+ public int compare(Scene o1, Scene o2) {
+ if (o1.object.vertices[0].getZ() == o2.object.vertices[0].getZ()) {
+ return o1.object.getPrecedence() - o2.object.getPrecedence();
+ }
+
+ return (int) Math.signum(o2.object.vertices[0].getZ() - o1.object.vertices[0].getZ());
+ }
+
+ public boolean equals(Object obj) {
+ return this == obj;
+ }
+ });
+
+ private static List<Scene> faces = new ArrayList<Scene>();
+ private static List<Scene> disabledFaces = new ArrayList<Scene>();
+ private static List<ClippingPlane> clippingPlanes;
+ private static Stack<Scene> stack = new Stack<Scene>();;
+
+ private List<Scene> behind;
+ private List<Scene> onfront;
+ private ConvexObject object;
+ private boolean drawn;
+ private boolean is2d;
+
+ private Scene(final ConvexObject object) {
+ this.object = object;
+ }
+
+ public static final void setClippingPlanes(final List<ClippingPlane> clippingPlanes) {
+ Scene.clippingPlanes = clippingPlanes;
+ }
+
+ private static final List<ConvexObject> breakOnClippingPlane(ConvexObject o) {
+ List<ConvexObject> list = new ArrayList<ConvexObject>(8);
+ List<ConvexObject> tmp = new ArrayList<ConvexObject>(8);
+ list.add(o);
+ if (clippingPlanes != null) {
+ for (ClippingPlane clip : clippingPlanes) {
+ if (clip.isEnable()) {
+ tmp.clear();
+ for (ConvexObject co : list) {
+ List<ConvexObject> l = co.breakObject(clip.getEquation());
+ if (l != null) {
+ tmp.addAll(l);
+ } else {
+ list.clear();
+ return list;
+ }
+ }
+ list.clear();
+ list.addAll(tmp);
+ if (list.isEmpty()) {
+ break;
+ }
+ }
+ }
+ }
+ return list;
+ }
+
+ static final void addToRoot(final boolean is2D, final ConvexObject co) {
+ try {
+ List<ConvexObject> broken = breakOnClippingPlane(co);
+ for (ConvexObject object : broken) {
+ add(is2D, object);
+ }
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ }
+
+ private static final void add(final boolean is2D, final ConvexObject object) {
+ synchronized (faces) {
+ Scene st = new Scene(object);
+ if (is2D) {
+ st.is2d = true;
+ faces2d.add(st);
+ } else {
+ Set<Scene> toRemove = new HashSet<Scene>();
+ List<ConvexObject> toAdd = null;
+
+ for (Scene face : faces) {
+ if (face.object instanceof Triangle && object instanceof Segment) {
+ if (((Triangle) face.object).addSegment((Segment) object)) {
+ if (st != null) {
+ toRemove.add(st);
+ st = null;
+ }
+ }
+ } else if (object instanceof Triangle && face.object instanceof Segment) {
+ if (((Triangle) object).addSegment((Segment) face.object)) {
+ toRemove.add(face);
+ }
+ }
+
+ if (st != null) {
+ int r = face.object.isBehind(st.object);
+
+ if (r == 1) {
+ // object is behind face.object
+ addBehind(face, st);
+ addOnFront(st, face);
+ } else if (r == -1) {
+ // face.object is behind object
+ addBehind(st, face);
+ addOnFront(face, st);
+ } else if (r == 2) {
+ // collision
+ toAdd = face.object.breakObject(st.object);
+ if (toAdd != null && !toAdd.isEmpty()) {
+ toRemove.add(face);
+ toRemove.add(st);
+ st = null;
+ break;
+ }
+ }
+ }
+ }
+
+ if (st != null) {
+ faces.add(st);
+ }
+
+ for (Scene s : toRemove) {
+ faces.remove(s);
+ if (s.onfront != null) {
+ for (Scene ss : s.onfront) {
+ ss.behind.remove(s);
+ }
+ }
+ }
+ if (toAdd != null) {
+ for (ConvexObject co : toAdd) {
+ add(false, co);
+ }
+ }
+ }
+ }
+ }
+
+
+ static final void clearDepth() {
+ disabledFaces.addAll(faces);
+ disabledFaces.addAll(faces2d);
+ faces.clear();
+ faces2d.clear();
+ }
+
+ static final void drawRoot(final Graphics2D g2d) {
+ synchronized (faces) {
+ for (Scene face : disabledFaces) {
+ face.draw(g2d);
+ }
+
+ for (Scene face : disabledFaces) {
+ face.drawn = false;
+ }
+
+ for (Scene face : faces) {
+ face.draw(g2d);
+ }
+
+ for (Scene face : faces2d) {
+ face.draw(g2d);
+ }
+
+ // code to help debug
+ /*for (Scene face : faces) {
+ face.drawn = false;
+ }
+
+ for (Scene face : faces) {
+ if (face.object.marked) {
+ face.object.draw(g2d);
+ }
+ }*/
+ }
+ }
+
+ static final void clear() {
+ disabledFaces.clear();
+ faces.clear();
+ faces2d.clear();
+ stack.clear();
+ }
+
+ static final void clearAll() {
+ clear();
+ clippingPlanes.clear();
+ }
+
+ private final void draw(final Graphics2D g2d) {
+ if (stack.contains(this)) {
+ this.object.addArea(stack.peek().object);
+ return;
+ }
+ if (!drawn) {
+ stack.push(this);
+ drawn = true;
+ if (behind != null && !behind.isEmpty()) {
+ for (Scene face : behind) {
+ face.draw(g2d);
+ }
+ }
+ object.draw(g2d);
+ stack.pop();
+ }
+ }
+
+ private static final void addBehind(Scene face, Scene s) {
+ if (face.behind == null) {
+ face.behind = new ArrayList<Scene>();
+ }
+ face.behind.add(s);
+ }
+
+ private static final void addOnFront(Scene face, Scene s) {
+ if (face.onfront == null) {
+ face.onfront = new ArrayList<Scene>();
+ }
+ face.onfront.add(s);
+ }
+}
diff --git a/modules/scirenderer/src/org/scilab/forge/scirenderer/implementation/g2d/motor/Segment.java b/modules/scirenderer/src/org/scilab/forge/scirenderer/implementation/g2d/motor/Segment.java
new file mode 100755
index 000000000..4c924a01b
--- /dev/null
+++ b/modules/scirenderer/src/org/scilab/forge/scirenderer/implementation/g2d/motor/Segment.java
@@ -0,0 +1,247 @@
+/*
+ * Scilab ( http://www.scilab.org/ ) - This file is part of Scilab
+ * Copyright (C) 2012 - Scilab Enterprises - Calixte Denizet
+ *
+ * This file must be used under the terms of the CeCILL.
+ * This source file is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at
+ * http://www.cecill.info/licences/Licence_CeCILL_V2.1-en.txt
+ */
+
+package org.scilab.forge.scirenderer.implementation.g2d.motor;
+
+import java.awt.Color;
+import java.awt.Graphics2D;
+import java.awt.Shape;
+import java.awt.Stroke;
+import java.awt.geom.Path2D;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
+import org.scilab.forge.scirenderer.tranformations.Vector3d;
+import org.scilab.forge.scirenderer.tranformations.Vector4d;
+
+/**
+ * Segment object (for info, when modify rendering check for PolyLine too).
+ *
+ * @author Calixte DENIZET
+ */
+public class Segment extends ConvexObject implements Comparable<Segment> {
+
+ private int hash = -1;
+ protected G2DStroke stroke;
+ protected List<ConvexObject> segmentOn;
+ protected boolean is2D;
+ protected double[] clip = new double[] {Double.NaN, Double.NaN, Double.NaN, Double.NaN};
+
+ public Segment(Vector3d[] vertices, Color[] colors, G2DStroke stroke, boolean is2D) throws InvalidPolygonException {
+ super(vertices, colors);
+ if (vertices.length != 2) {
+ throw new InvalidPolygonException("Invalid segment: must have 2 vertices.");
+ }
+ this.stroke = stroke;
+ this.is2D = is2D;
+ }
+
+ public Segment(Vector3d[] vertices, Color[] colors) throws InvalidPolygonException {
+ this(vertices, colors, null, false);
+ }
+
+ public void setStroke(G2DStroke stroke) {
+ this.stroke = stroke;
+ }
+
+ public double getLength() {
+ return vertices[0].minus(vertices[1]).getNorm();
+ }
+
+ public static double getLength(Vector3d[] vertices) {
+ return vertices[0].minus(vertices[1]).getNorm();
+ }
+
+ public void addConvexObject(ConvexObject co) {
+ if (segmentOn == null) {
+ segmentOn = new ArrayList<ConvexObject>(2);
+ }
+ segmentOn.add(co);
+ }
+
+ public void removeConvexObject(ConvexObject co) {
+ if (segmentOn != null) {
+ segmentOn.remove(co);
+ }
+ }
+
+ public void replaceSegment(List<Segment> segs) {
+ if (segmentOn != null) {
+ for (ConvexObject co : segmentOn) {
+ Triangle t = (Triangle) co;
+ t.replaceSegment(this, segs);
+ }
+ }
+ }
+
+ public boolean isIn2D() {
+ return isNull(vertices[0].getZ()) && isNull(vertices[1].getZ());
+ }
+
+ public boolean isInFront() {
+ return isEqual(vertices[0].getZ(), -0.5) && isEqual(vertices[1].getZ(), -0.5);
+ }
+
+ @Override
+ public int compareTo(Segment o) {
+ if (equals(o)) {
+ return 0;
+ }
+
+ return getPrecedence() - o.getPrecedence();
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (o instanceof Segment) {
+ Segment s = (Segment) o;
+ return (s.vertices[0].equals(vertices[0]) && s.vertices[1].equals(vertices[1]) && s.getColor(0).equals(getColor(0)) && s.getColor(1).equals(getColor(1))) || (s.vertices[1].equals(vertices[0]) && s.vertices[0].equals(vertices[1]) && s.getColor(1).equals(getColor(0)) && s.getColor(0).equals(getColor(1)));
+ }
+
+ return false;
+ }
+
+ @Override
+ public int isBehind(ConvexObject o) {
+ if (o instanceof Triangle && ((Triangle) o).isSegmentAcross(this)) {
+ return 1;
+ }
+
+ return super.isBehind(o);
+ }
+
+ @Override
+ public List<ConvexObject> breakObject(ConvexObject o) {
+ if (o instanceof Triangle) {
+ return ((Triangle) o).breakObject(this);
+ } else if (o instanceof SpritedRectangle) {
+ return ((SpritedRectangle) o).breakObject(this);
+ }
+
+ return null;
+ }
+
+ @Override
+ public List<ConvexObject> breakObject(Vector4d v) {
+ double[] vv = v.getData();
+
+ if (is2D && vv[2] == 0) {
+ ConvexObject.makeClip(clip, vv);
+ }
+ getNormal();
+ Vector3d np = new Vector3d(vv);
+ boolean a = isBehind(vertices[0], np, vv[3]);
+ boolean b = isBehind(vertices[1], np, vv[3]);
+
+ if (a && b) {
+ List<ConvexObject> list = new ArrayList<ConvexObject>(1);
+ list.add(this);
+ return list;
+ }
+
+ if (!a && !b) {
+ return null;
+ }
+
+ double c = (vv[3] + vertices[1].scalar(np)) / v0.scalar(np);
+ Vector3d p = Vector3d.getBarycenter(vertices[0], vertices[1], c, 1 - c);
+ Color color = getColorsBarycenter(getColor(0), getColor(1), c, 1 - c);
+ Segment s;
+
+ try {
+ if (a) {
+ s = new Segment(new Vector3d[] {vertices[0], p}, new Color[] {getColor(0), color}, this.stroke, this.is2D);
+ } else {
+ s = new Segment(new Vector3d[] {p, vertices[1]}, new Color[] {color, getColor(1)}, this.stroke, this.is2D);
+ }
+
+ List<ConvexObject> list = new ArrayList<ConvexObject>(1);
+ list.add(s);
+
+ return list;
+ } catch (InvalidPolygonException e) { }
+
+ return null;
+ }
+
+ public List<Segment> breakObject(Vector3d p, Vector3d u, Vector3d n) {
+ getNormal();
+ double c = vertices[1].minus(p).scalar(n) / v0.scalar(n);
+ if (c > 0 && !isNull(c) && c < 1 && !isEqual(c, 1)) {
+ List<Segment> list = new ArrayList<Segment>(2);
+ Vector3d q = Vector3d.getBarycenter(vertices[0], vertices[1], c, 1 - c);
+ Color color = getColorsBarycenter(getColor(0), getColor(1), c, 1 - c);
+ try {
+ list.add(new Segment(new Vector3d[] {vertices[0], q}, new Color[] {getColor(0), color}, stroke, this.is2D));
+ list.add(new Segment(new Vector3d[] {q, vertices[1]}, new Color[] {color, getColor(1)}, stroke, this.is2D));
+
+ return list;
+ } catch (InvalidPolygonException e) { }
+ } else {
+ List<Segment> list = new ArrayList<Segment>(1);
+ try {
+ list.add(new Segment(new Vector3d[] {vertices[0], vertices[1]}, new Color[] {getColor(0), getColor(1)}, stroke, this.is2D));
+
+ return list;
+ } catch (InvalidPolygonException e) { }
+ }
+
+ return null;
+ }
+
+ @Override
+ public void draw(Graphics2D g2d) {
+ if (segmentOn == null || segmentOn.isEmpty()) {
+ Path2D polyline = getProjectedPolyLine();
+ g2d.setColor(getColor(0));
+ Stroke oldStroke = g2d.getStroke();
+ if (oldStroke != stroke) {
+ g2d.setStroke(stroke);
+ }
+
+ Shape oldClip = g2d.getClip();
+ Shape newClip = ConvexObject.getClip(clip);
+ if (newClip != null) {
+ g2d.clip(newClip);
+ }
+
+ g2d.draw(polyline);
+
+ if (oldStroke != stroke) {
+ g2d.setStroke(oldStroke);
+ }
+
+ if (newClip != null) {
+ g2d.setClip(oldClip);
+ }
+
+ drawAreas(g2d);
+ }
+ }
+
+ @Override
+ public int hashCode() {
+ if (hash == -1) {
+ if (colors != null) {
+ hash = Arrays.hashCode(vertices) + 19 * Arrays.hashCode(colors);
+ } else {
+ hash = Arrays.hashCode(vertices) + 19 * getColor(0).hashCode();
+ }
+ }
+ return hash;
+ }
+
+ @Override
+ public String toString() {
+ return "Segment " + vertices[0].toString() + " " + vertices[1].toString() + " Precedence: " + getPrecedence();
+ }
+}
diff --git a/modules/scirenderer/src/org/scilab/forge/scirenderer/implementation/g2d/motor/SpritedRectangle.java b/modules/scirenderer/src/org/scilab/forge/scirenderer/implementation/g2d/motor/SpritedRectangle.java
new file mode 100755
index 000000000..472403a11
--- /dev/null
+++ b/modules/scirenderer/src/org/scilab/forge/scirenderer/implementation/g2d/motor/SpritedRectangle.java
@@ -0,0 +1,312 @@
+/*
+ * Scilab ( http://www.scilab.org/ ) - This file is part of Scilab
+ * Copyright (C) 2012 - Scilab Enterprises - Calixte Denizet
+ *
+ * This file must be used under the terms of the CeCILL.
+ * This source file is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at
+ * http://www.cecill.info/licences/Licence_CeCILL_V2.1-en.txt
+ */
+
+package org.scilab.forge.scirenderer.implementation.g2d.motor;
+
+import java.awt.Color;
+import java.awt.Dimension;
+import java.awt.Graphics2D;
+import java.awt.RenderingHints;
+import java.awt.Stroke;
+import java.awt.geom.AffineTransform;
+import java.awt.geom.Path2D;
+import java.awt.image.BufferedImage;
+import java.util.ArrayList;
+import java.util.List;
+
+import org.scilab.forge.scirenderer.implementation.g2d.texture.G2DTextureDrawingTools;
+import org.scilab.forge.scirenderer.texture.Texture;
+import org.scilab.forge.scirenderer.texture.AnchorPosition;
+import org.scilab.forge.scirenderer.tranformations.Transformation;
+import org.scilab.forge.scirenderer.tranformations.Vector3d;
+import org.scilab.forge.scirenderer.tranformations.Vector4d;
+
+/**
+ * @author Calixte DENIZET
+ */
+public class SpritedRectangle extends ConvexObject {
+
+ private static final Color[] COLORS = new Color[] {Color.BLACK, Color.BLACK, Color.BLACK};
+
+ private Texture sprite;
+ private BufferedImage image;
+ private G2DTextureDrawingTools drawingTools;
+ private double rotationAngle;
+ private Texture.Filter filter;
+ private Vector3d position;
+
+ public SpritedRectangle(Vector3d vertex, Texture sprite, AnchorPosition anchor, G2DTextureDrawingTools drawingTools, double rotationAngle) throws InvalidPolygonException {
+ super(getSpriteVertices(vertex, sprite, anchor, rotationAngle), null);
+ this.sprite = sprite;
+ this.drawingTools = drawingTools;
+ this.rotationAngle = rotationAngle;
+ this.position = vertex;
+ }
+
+ public SpritedRectangle(Vector3d vertex, Transformation transf, BufferedImage image, Texture.Filter filter) throws InvalidPolygonException {
+ super(getSpriteVertices(vertex, transf, image), null);
+ this.image = image;
+ this.filter = filter;
+ this.position = vertex;
+ }
+
+ @Override
+ public List<ConvexObject> breakObject(ConvexObject o) {
+ if (o instanceof Triangle) {
+ return breakObject((Triangle) o);
+ } else if (o instanceof Segment) {
+ return breakObject((Segment) o);
+ } else if (o instanceof SpritedRectangle) {
+ return breakObject((SpritedRectangle) o);
+ }
+ return null;
+ }
+
+ public List<ConvexObject> breakObject(Triangle o) {
+ try {
+ Vector3d[] v1 = new Vector3d[] {vertices[0], vertices[1], vertices[2]};
+ Vector3d[] v2 = new Vector3d[] {vertices[0], vertices[2], vertices[3]};
+ Triangle t1 = new Triangle(v1, COLORS);
+ Triangle t2 = new Triangle(v2, COLORS);
+ t1.setSprite(this);
+ t2.setSprite(this);
+ List<ConvexObject> list = new ArrayList<ConvexObject>();
+ if (o.isBehind(t1) == 2) {
+ List<ConvexObject> list2 = o.breakObject(t1);
+ if (list2 != null) {
+ list.addAll(list2);
+ }
+ } else {
+ list.add(t1);
+ }
+ if (o.isBehind(t2) == 2) {
+ List<ConvexObject> list2 = o.breakObject(t2);
+ if (list2 != null) {
+ list.addAll(list2);
+ }
+ } else {
+ list.add(t2);
+ }
+
+ return list;
+ } catch (InvalidPolygonException e) { }
+
+ return null;
+ }
+
+ public List<ConvexObject> breakObject(Segment o) {
+ try {
+ Vector3d[] v = new Vector3d[] {vertices[0], vertices[1], vertices[2]};
+ Triangle t1 = new Triangle(v, COLORS);
+ t1.setSprite(this);
+ v = new Vector3d[] {vertices[0], vertices[2], vertices[3]};
+ Triangle t2 = new Triangle(v, COLORS);
+ t2.setSprite(this);
+ List<ConvexObject> list = t1.breakObject(o);
+ if (list != null) {
+ list.add(t2);
+ return list;
+ }
+
+ list = t2.breakObject(o);
+ if (list != null) {
+ list.add(t1);
+ return list;
+ }
+ } catch (InvalidPolygonException e) { }
+
+ return null;
+ }
+
+ public List<ConvexObject> breakObject(SpritedRectangle o) {
+ try {
+ Vector3d[] v1 = new Vector3d[] {vertices[0], vertices[1], vertices[2]};
+ Vector3d[] v2 = new Vector3d[] {vertices[0], vertices[2], vertices[3]};
+ Triangle t1 = new Triangle(v1, COLORS);
+ Triangle t2 = new Triangle(v2, COLORS);
+ t1.setSprite(this);
+ t2.setSprite(this);
+ List<ConvexObject> list = o.breakObject(t1);
+ if (list == null) {
+ list = o.breakObject(t2);
+ } else {
+ List<ConvexObject> list2 = o.breakObject(t2);
+ if (list2 != null) {
+ list.addAll(list2);
+ }
+ }
+
+ return list;
+ } catch (InvalidPolygonException e) { }
+
+ return null;
+ }
+
+ public List<ConvexObject> breakObject(Vector4d v) {
+ try {
+ double[] vv = v.getData();
+ Vector3d np = new Vector3d(vv);
+ int ret = isBehind(np, vv[3]);
+ if (ret == 1) {
+ List<ConvexObject> list = new ArrayList<ConvexObject>();
+ list.add(this);
+ return list;
+ } else if (ret == -1) {
+ return null;
+ }
+
+ Vector3d[] v1 = new Vector3d[] {vertices[0], vertices[1], vertices[2]};
+ Vector3d[] v2 = new Vector3d[] {vertices[0], vertices[2], vertices[3]};
+ Triangle t1 = new Triangle(v1, COLORS);
+ Triangle t2 = new Triangle(v2, COLORS);
+ t1.setSprite(this);
+ t2.setSprite(this);
+ List<ConvexObject> list = t1.breakObject(v);
+ if (list != null) {
+ List<ConvexObject> list2 = t2.breakObject(v);
+ if (list2 != null) {
+ list.addAll(list2);
+ }
+ return list;
+ } else {
+ return t2.breakObject(v);
+ }
+ } catch (InvalidPolygonException e) { }
+
+ return null;
+ }
+
+ private static Vector3d[] getSpriteVertices(Vector3d vertex, Transformation transf, BufferedImage image) {
+ int w = image.getWidth();
+ int h = image.getHeight();
+ double x = vertex.getX();
+ double y = vertex.getY();
+ double z = vertex.getZ();
+
+ return new Vector3d[] {transf.project(new Vector3d(x, y, z)), transf.project(new Vector3d(x + w, y, z)), transf.project(new Vector3d(x + w, y + h, z)), transf.project(new Vector3d(x, y + h, z))};
+ }
+
+ private static Vector3d[] getSpriteVertices(Vector3d vertex, Texture sprite, AnchorPosition anchor) {
+ Dimension d = sprite.getDataProvider().getTextureSize();
+ double spriteWidth = d.getWidth();
+ double spriteHeight = d.getHeight();
+ double deltaX = 0;
+ double deltaY = 0;
+
+ switch (anchor) {
+ case LEFT:
+ deltaX = spriteWidth / 2;
+ break;
+ case LOWER_LEFT:
+ deltaX = spriteWidth / 2;
+ deltaY = spriteHeight / 2;
+ break;
+ case UPPER_LEFT:
+ deltaX = spriteWidth / 2;
+ deltaY = -spriteHeight / 2;
+ break;
+ case UP:
+ deltaY = -spriteHeight / 2;
+ break;
+ case CENTER:
+ break;
+ case DOWN:
+ deltaY = spriteHeight / 2;
+ break;
+ case RIGHT:
+ deltaX = -spriteWidth / 2;
+ break;
+ case LOWER_RIGHT:
+ deltaX = -spriteWidth / 2;
+ deltaY = spriteHeight / 2;
+ break;
+ case UPPER_RIGHT:
+ deltaX = -spriteWidth / 2;
+ deltaY = -spriteHeight / 2;
+ break;
+ default:
+ }
+
+ double x = deltaX;
+ double y = -deltaY;
+ double z = vertex.getZ();
+
+ return new Vector3d[] {new Vector3d(x - spriteWidth / 2, y - spriteHeight / 2, z),
+ new Vector3d(x - spriteWidth / 2, y + spriteHeight / 2, z),
+ new Vector3d(x + spriteWidth / 2, y + spriteHeight / 2, z),
+ new Vector3d(x + spriteWidth / 2, y - spriteHeight / 2, z)
+ };
+ }
+
+ private static Vector3d[] getSpriteVertices(Vector3d vertex, Texture sprite, AnchorPosition anchor, double rotationAngle) {
+ Vector3d[] points = getSpriteVertices(vertex, sprite, anchor);
+
+ if (rotationAngle != 0) {
+ final double a = -rotationAngle * Math.PI / 180;
+ final double ca = Math.cos(a);
+ final double sa = Math.sin(a);
+
+ for (int i = 0; i < 4; i++) {
+ points[i] = new Vector3d(vertex.getX() + ca * points[i].getX() - sa * points[i].getY(), vertex.getY() + sa * points[i].getX() + ca * points[i].getY(), vertex.getZ());
+ }
+ } else {
+ for (int i = 0; i < 4; i++) {
+ points[i] = new Vector3d(vertex.getX() + points[i].getX(), vertex.getY() + points[i].getY(), vertex.getZ());
+ }
+ }
+
+ return points;
+ }
+
+ private static Vector3d unrotate(Vector3d v, Vector3d t, double rotationAngle) {
+ v = v.minus(t);
+ final double a = rotationAngle * Math.PI / 180;
+ final double ca = Math.cos(a);
+ final double sa = Math.sin(a);
+
+ return new Vector3d(ca * v.getX() - sa * v.getY(), sa * v.getX() + ca * v.getY(), v.getZ());
+ }
+
+ public Texture getSprite() {
+ return sprite;
+ }
+
+ @Override
+ public void draw(Graphics2D g2d) {
+ if (sprite != null) {
+ Path2D contour = getProjectedContour();
+ AffineTransform oldTransf = g2d.getTransform();
+ Stroke oldStroke = g2d.getStroke();
+
+ if (rotationAngle != 0) {
+ g2d.translate(position.getX(), position.getY());
+ g2d.rotate(-rotationAngle * Math.PI / 180);
+ Vector3d v = unrotate(vertices[0], position, rotationAngle);
+ g2d.translate(v.getX(), v.getY());
+ } else {
+ g2d.translate(vertices[0].getX(), vertices[0].getY());
+ }
+
+ drawingTools.accept(sprite);
+ g2d.setTransform(oldTransf);
+ g2d.setStroke(oldStroke);
+ } else {
+ Object key = filter == Texture.Filter.LINEAR ? RenderingHints.VALUE_INTERPOLATION_BILINEAR : RenderingHints.VALUE_INTERPOLATION_NEAREST_NEIGHBOR;
+ DrawTools.drawParallelogramTexture(g2d, image, new double[] {0, 1, 1, 0}, new double[] {0, 0, 1, 1},
+ new double[] {vertices[3].getX(), vertices[2].getX(), vertices[1].getX(), vertices[0].getX()},
+ new double[] {vertices[3].getY(), vertices[2].getY(), vertices[1].getY(), vertices[0].getY()}, key);
+ }
+ }
+
+ public String toString() {
+ return "SpritedRectangle: " + vertices[0].toString() + " " + vertices[1].toString() + " " + vertices[2].toString() + " " + vertices[3].toString() + "\nPrecedence: " + precedence;
+ }
+}
diff --git a/modules/scirenderer/src/org/scilab/forge/scirenderer/implementation/g2d/motor/Triangle.java b/modules/scirenderer/src/org/scilab/forge/scirenderer/implementation/g2d/motor/Triangle.java
new file mode 100755
index 000000000..d79b40737
--- /dev/null
+++ b/modules/scirenderer/src/org/scilab/forge/scirenderer/implementation/g2d/motor/Triangle.java
@@ -0,0 +1,593 @@
+/*
+ * Scilab ( http://www.scilab.org/ ) - This file is part of Scilab
+ * Copyright (C) 2012 - Scilab Enterprises - Calixte Denizet
+ *
+ * This file must be used under the terms of the CeCILL.
+ * This source file is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at
+ * http://www.cecill.info/licences/Licence_CeCILL_V2.1-en.txt
+ */
+
+package org.scilab.forge.scirenderer.implementation.g2d.motor;
+
+import java.awt.BasicStroke;
+import java.awt.Color;
+import java.awt.Graphics2D;
+import java.awt.RenderingHints;
+import java.awt.Shape;
+import java.awt.Stroke;
+import java.awt.geom.Area;
+import java.awt.geom.Path2D;
+import java.awt.image.BufferedImage;
+import java.util.ArrayList;
+import java.util.List;
+
+import org.scilab.forge.scirenderer.texture.Texture;
+import org.scilab.forge.scirenderer.tranformations.Vector3d;
+import org.scilab.forge.scirenderer.tranformations.Vector4d;
+
+/**
+ * @author Calixte DENIZET
+ */
+public class Triangle extends ConvexObject {
+
+ private static final Color[] COLORS = new Color[] {Color.BLACK, Color.BLACK, Color.BLACK};
+ private static final Stroke stroke = new BasicStroke(1f, BasicStroke.CAP_BUTT, BasicStroke.JOIN_BEVEL);
+ private static final Stroke EMPTYSTROKE = new BasicStroke(0f, BasicStroke.CAP_BUTT, BasicStroke.JOIN_BEVEL);
+
+ private SpritedRectangle sprite;
+ private BufferedImage image;
+ private Vector3d[] textureCoords;
+ private Texture.Filter filter;
+
+ protected List<Segment> segments;
+
+ public Triangle(Vector3d[] vertices, Color[] colors, Vector3d normal) throws InvalidPolygonException {
+ super(vertices, colors);
+ if (vertices.length != 3) {
+ throw new InvalidPolygonException("Invalid triangle: must have 3 vertices.");
+ }
+ }
+
+ public Triangle(Vector3d[] vertices, Color[] colors) throws InvalidPolygonException {
+ this(vertices, colors, null);
+ }
+
+ public Triangle(Vector3d[] vertices, Vector3d[] textureCoords, BufferedImage image, Texture.Filter filter) throws InvalidPolygonException {
+ this(vertices, COLORS, null);
+ this.textureCoords = textureCoords;
+ this.image = image;
+ this.filter = filter;
+ }
+
+ @Override
+ public int isBehind(ConvexObject o) {
+ if (o instanceof Segment && isSegmentAcross((Segment) o)) {
+ return -1;
+ }
+
+ return super.isBehind(o);
+ }
+
+ public boolean isIn2D() {
+ return vertices[0].getZ() == 0 && vertices[1].getZ() == 0 && vertices[2].getZ() == 0;
+ }
+
+ public boolean addSegment(Segment s) {
+ if (isSegmentInside(s)) {
+ if (segments == null) {
+ segments = new ArrayList<Segment>(3);
+ }
+ if (segments.contains(s)) {
+ segments.remove(s);
+ s.removeConvexObject(this);
+ }
+ segments.add(s);
+ s.addConvexObject(this);
+
+ return true;
+ }
+
+ return false;
+ }
+
+ public boolean pointOnVertices(Vector3d p) {
+ return p.equals(vertices[0]) || p.equals(vertices[1]) || p.equals(vertices[2]);
+ }
+
+ public void removeSegment(Segment s) {
+ if (segments != null) {
+ segments.remove(s);
+ s.removeConvexObject(this);
+ }
+ }
+
+ public void replaceSegment(Segment s, List<Segment> segs) {
+ segments.remove(s);
+ //s.removeConvexObject(this);
+ for (Segment ss : segs) {
+ if (segments.contains(ss)) {
+ segments.remove(ss);
+ ss.removeConvexObject(this);
+ }
+ segments.add(ss);
+ ss.addConvexObject(this);
+ }
+ }
+
+ @Override
+ public List<ConvexObject> breakObject(ConvexObject o) {
+ if (o instanceof Triangle) {
+ return breakObject((Triangle) o);
+ } else if (o instanceof Segment) {
+ return breakObject((Segment) o);
+ } else if (o instanceof SpritedRectangle) {
+ return ((SpritedRectangle) o).breakObject(this);
+ }
+
+ return null;
+ }
+
+ public List<ConvexObject> breakObject(Triangle o) {
+ Vector3d n = Vector3d.product(getNormal(), o.getNormal());
+ n = n.times(1 / n.getNorm2());
+ Vector3d u = Vector3d.product(o.v0v1, n);
+ Vector3d v = Vector3d.product(n, this.v0v1);
+ Vector3d p = Vector3d.getBarycenter(u, v, this.v0v1.scalar(this.vertices[0]), o.v0v1.scalar(o.vertices[0]));
+
+ List<ConvexObject> list1 = breakTriangleOnLine(o, p, this.v0v1);
+ List<ConvexObject> list2 = breakTriangleOnLine(this, p, o.v0v1);
+
+ list1.addAll(list2);
+
+ return list1;
+ }
+
+ public List<ConvexObject> breakObject(Segment o) {
+ double c = this.getSegmentIntersection(o);
+ if (Double.isNaN(c)) {
+ return null;
+ }
+
+ List<ConvexObject> list = new ArrayList<ConvexObject>(5);
+ Vector3d p = Vector3d.getBarycenter(o.vertices[0], o.vertices[1], c, 1 - c);
+ Color cc = getColorsBarycenter(o.getColor(0), o.getColor(1), c, 1 - c);
+
+ try {
+ list.add(new Segment(new Vector3d[] {o.vertices[0], p}, new Color[] {o.getColor(0), cc}, o.stroke, o.is2D));
+ list.add(new Segment(new Vector3d[] {p, o.vertices[1]}, new Color[] {cc, o.getColor(1)}, o.stroke, o.is2D));
+ } catch (InvalidPolygonException e) { }
+
+ List<ConvexObject> list1 = breakTriangleOnLine(this, p, Vector3d.product(getNormal(), vertices[0].minus(p)));
+ list.addAll(list1);
+
+ return list;
+ }
+
+ protected void setSprite(SpritedRectangle sprite) {
+ this.sprite = sprite;
+ }
+
+ protected SpritedRectangle getSprite() {
+ return sprite;
+ }
+
+ @Override
+ public void draw(Graphics2D g2d) {
+ if (sprite != null) {
+ Shape oldClip = g2d.getClip();
+ Path2D contour = getProjectedContour();
+ Area area = new Area(contour);
+ // Trick to paint the triangle and its outline
+ //area.add(new Area(stroke.createStrokedShape(contour)));
+ g2d.clip(area);//getProjectedContour());
+ sprite.draw(g2d);
+ g2d.setClip(oldClip);
+ } else if (image != null) {
+ Object key = filter == Texture.Filter.LINEAR ? RenderingHints.VALUE_INTERPOLATION_BILINEAR : RenderingHints.VALUE_INTERPOLATION_NEAREST_NEIGHBOR;
+ DrawTools.drawTriangleTexture(g2d, image, new double[] {textureCoords[0].getX(), textureCoords[1].getX(), textureCoords[2].getX()}, new double[] {textureCoords[0].getY(), textureCoords[1].getY(), textureCoords[2].getY()}, new double[] {vertices[0].getX(), vertices[1].getX(), vertices[2].getX()}, new double[] {vertices[0].getY(), vertices[1].getY(), vertices[2].getY()}, key);
+ } else if (isMonochromatic()) {
+ // AA generates artifacts on the triangles borders whent they slightlyt overlap
+ // So we disable it just ot fill the triangle
+ Object prevAA = g2d.getRenderingHint(RenderingHints.KEY_ANTIALIASING);
+ g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_OFF);
+ Path2D contour = getProjectedContour();
+ //Area area = new Area(contour);
+ // Trick to paint the triangle and its outline
+ // TODO: the newly created Area contains in fact two areas
+ // it should be better to have one area where its border
+ // is the external outline of the contour...
+ // (it would reduce eps/ps/pdf/svg file size)
+ // fill(area) is very very slow... (for a grayplot 500x500, fill(area) is 10 times slower than fill(contour))...
+ //area.add(new Area(stroke.createStrokedShape(contour)));
+ if (g2d.getStroke() != EMPTYSTROKE) {
+ g2d.setStroke(EMPTYSTROKE);
+ }
+ g2d.setColor(getColor(0));
+ g2d.fill(contour);
+ g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, prevAA);
+ } else {
+ DrawTools.fillGouraud(g2d, this);
+ }
+
+ if (segments != null) {
+ for (Segment s : segments) {
+ s.removeConvexObject(this);
+ s.draw(g2d);
+ }
+ }
+
+ drawAreas(g2d);
+ }
+
+ @Override
+ public List<ConvexObject> breakObject(Vector4d v) {
+ double[] vv = v.getData();
+ Vector3d np = new Vector3d(vv);
+ int ret = isBehind(np, vv[3]);
+ if (ret == 1) {
+ List<ConvexObject> list = new ArrayList<ConvexObject>(1);
+ list.add(this);
+ return list;
+ } else if (ret == -1) {
+ return null;
+ }
+
+ Vector3d n = Vector3d.product(getNormal(), np);
+ n = n.times(1 / n.getNorm2());
+ Vector3d u = Vector3d.product(np, n);
+ Vector3d w = Vector3d.product(n, this.v0v1);
+ Vector3d p = Vector3d.getBarycenter(u, w, this.v0v1.scalar(this.vertices[0]), -vv[3]);
+
+ List<ConvexObject> list1 = breakTriangleOnLine(this, p, np);
+ List<ConvexObject> list = new ArrayList<ConvexObject>(3);
+ for (ConvexObject o : list1) {
+ if (o.isBehind(np, vv[3]) == 1) {
+ list.add(o);
+ }
+ }
+
+ return list;
+ }
+
+ protected boolean isPointInside(final Vector3d v) {
+ return isPointInside(v, true);
+ }
+
+ protected boolean isPointInside(final Vector3d v, final boolean checkCoplanarity) {
+ Vector3d v2 = v.minus(vertices[0]);
+ getNormal();
+ if (checkCoplanarity && !isNull(v2.scalar(v0v1))) {
+ return false;
+ }
+
+ Vector3d v0v1v2 = Vector3d.product(v0v1, v2);
+ double a = -v0v1v2.scalar(v1);
+ if (a < 0 || isNull(a)) {
+ return false;
+ }
+
+ double b = v0v1v2.scalar(v0);
+ if (b < 0 || isNull(b)) {
+ return false;
+ }
+
+ return a + b < nv0v1 || isEqual(a + b, nv0v1);
+ }
+
+ protected boolean isCoplanar(final Segment s) {
+ double sc = vertices[0].scalar(getNormal());
+ return isEqual(sc, s.vertices[0].scalar(v0v1)) && isEqual(sc, s.vertices[1].scalar(v0v1));
+ }
+
+ protected boolean isCoplanar(final Triangle t) {
+ double sc = vertices[0].scalar(getNormal());
+ return isEqual(sc, t.vertices[0].scalar(v0v1)) && isEqual(sc, t.vertices[1].scalar(v0v1)) && isEqual(sc, t.vertices[2].scalar(v0v1));
+ }
+
+ protected boolean isSegmentAcross(final Segment s) {
+ if (!isCoplanar(s)) {
+ // the segment and the triangle are not coplanar
+ return false;
+ }
+
+ return check2DTrueIntersection(s);
+ }
+
+ protected boolean isSegmentInside(final Segment s) {
+ if (!isCoplanar(s)) {
+ // the segment and the triangle are not coplanar
+ return false;
+ }
+
+ // Since there is a good probability that a segment is triangle border we check that
+ if ((s.vertices[0].equals(vertices[0]) || s.vertices[0].equals(vertices[1]) || s.vertices[0].equals(vertices[2]))
+ && (s.vertices[1].equals(vertices[0]) || s.vertices[1].equals(vertices[1]) || s.vertices[1].equals(vertices[2]))) {
+ return true;
+ }
+
+ return isPointInside(s.vertices[0], false) || isPointInside(s.vertices[1], false) || check2DIntersection(s);
+ }
+
+ protected boolean isSegmentIntersects(final Segment s) {
+ Vector3d v3 = s.vertices[0].minus(vertices[0]);
+ Vector3d v4 = s.vertices[1].minus(vertices[0]);
+ double c = v3.scalar(getNormal());
+
+ if (Math.signum(c) == Math.signum(v4.scalar(v0v1))) {
+ return false;
+ }
+
+ Vector3d v2 = s.vertices[0].minus(s.vertices[1]);
+ Vector3d v1v2 = Vector3d.product(v1, v2);
+ double a = v3.scalar(v1v2);
+ double b = Vector3d.det(v3, v2, v0);
+ double detv0v1v2 = v0.scalar(v1v2);
+ double sign = Math.signum(detv0v1v2);
+
+ return Math.signum(a) == sign && Math.signum(b) == sign && Math.signum(c) == sign && a + b <= detv0v1v2 && c <= detv0v1v2;
+ }
+
+ protected double getSegmentIntersection(final Segment s) {
+ Vector3d v = s.vertices[1].minus(vertices[0]);
+ double c = v.scalar(getNormal()) / s.v0.scalar(getNormal());
+
+ if (isNegativeOrNull(c) || isGreaterOrEqual(c, 1)) {
+ return Double.NaN;
+ }
+
+ Vector3d p = Vector3d.getBarycenter(s.vertices[0], s.vertices[1], c, 1 - c);
+ if (isPointInside(p, false)) {
+ return c;
+ }
+
+ return Double.NaN;
+ }
+
+ protected static List<ConvexObject> breakSegmentOnTriangle(final Triangle t, final Segment s) {
+ double c = t.getSegmentIntersection(s);
+ if (Double.isNaN(c)) {
+ return null;
+ }
+
+ List<ConvexObject> list = new ArrayList<ConvexObject>(2);
+ Vector3d p = Vector3d.getBarycenter(s.vertices[0], s.vertices[1], c, 1 - c);
+ Color cc = getColorsBarycenter(s.getColor(0), s.getColor(1), c, 1 - c);
+
+ try {
+ list.add(new Segment(new Vector3d[] {s.vertices[0], p}, new Color[] {s.getColor(0), cc}, s.stroke, s.is2D));
+ list.add(new Segment(new Vector3d[] {p, s.vertices[1]}, new Color[] {cc, s.getColor(1)}, s.stroke, s.is2D));
+ } catch (InvalidPolygonException e) { }
+
+
+ return list;
+ }
+
+ /**
+ * Break a triangle according to its intersection with a line containing p in the plane of the triangle and orthogonal to n
+ * The triangle and the line are supposed to be coplanar.
+ * @param t the triangle to break
+ * @param p a point of the line
+ * @param n a vector
+ * @return a list of triangles
+ */
+ protected static List<ConvexObject> breakTriangleOnLine(Triangle t, Vector3d p, Vector3d n) {
+ t.getNormal();
+ // aP0+(1-a)P1
+ double a = t.vertices[1].minus(p).scalar(n) / t.v0.scalar(n);
+ // bP0+(1-b)P2
+ double b = t.vertices[2].minus(p).scalar(n) / t.v1.scalar(n);
+ // cP1+(1-c)P2
+ Vector3d v2 = t.vertices[2].minus(t.vertices[1]);
+ double c = t.vertices[2].minus(p).scalar(n) / v2.scalar(n);
+
+ List<ConvexObject> list = new ArrayList<ConvexObject>(3);
+ int i = -1;
+ int j = -1;
+ int k = -1;
+ double weight = -1;
+ if (isNull(a)) {
+ // We are on P1
+ i = 1;
+ j = 2;
+ k = 0;
+ weight = b;
+ }
+
+ if (isNull(a - 1)) {
+ // We are on P0
+ if (weight != -1) {
+ list.add(t);
+ return list;
+ } else {
+ i = 0;
+ j = 1;
+ k = 2;
+ weight = c;
+ }
+ }
+
+ if (isNull(b)) {
+ // We are on P2
+ if (weight != -1) {
+ list.add(t);
+ return list;
+ } else {
+ i = 2;
+ j = 0;
+ k = 1;
+ weight = a;
+ }
+ }
+
+ if (i != -1) {
+ if (weight >= 0 && weight <= 1) {
+ // We break into two triangles
+ Vector3d vb = Vector3d.getBarycenter(t.vertices[j], t.vertices[k], weight, 1 - weight);
+ Color cb = getColorsBarycenter(t.getColor(j), t.getColor(k), weight, 1 - weight);
+ Vector3d[] vertices1 = new Vector3d[] {t.vertices[i], t.vertices[j], vb};
+ Vector3d[] vertices2 = new Vector3d[] {t.vertices[i], vb, t.vertices[k]};
+ Color[] colors1 = new Color[] {t.getColor(i), t.getColor(j), cb};
+ Color[] colors2 = new Color[] {t.getColor(i), cb, t.getColor(k)};
+
+ Vector3d[] tvertices1 = null;
+ Vector3d[] tvertices2 = null;
+ if (t.textureCoords != null) {
+ Vector3d tvb = Vector3d.getBarycenter(t.textureCoords[j], t.textureCoords[k], weight, 1 - weight);
+ tvertices1 = new Vector3d[] {t.textureCoords[i], t.textureCoords[j], tvb};
+ tvertices2 = new Vector3d[] {t.textureCoords[i], tvb, t.textureCoords[k]};
+ }
+
+ try {
+ Triangle t1 = new Triangle(vertices1, colors1, null);
+ t1.setSprite(t.getSprite());
+ list.add(t1);
+ Triangle t2 = new Triangle(vertices2, colors2, null);
+ t2.setSprite(t.getSprite());
+ list.add(t2);
+ if (t.textureCoords != null) {
+ t1.textureCoords = tvertices1;
+ t2.textureCoords = tvertices2;
+ t1.image = t2.image = t.image;
+ t1.filter = t2.filter = t.filter;
+ }
+ } catch (InvalidPolygonException e) { }
+
+ addSegments(list, t, p, Vector3d.product(t.v0v1, n), n);
+
+ return list;
+ } else {
+ list.add(t);
+ return list;
+ }
+ }
+
+ Color cu, cv;
+ Vector3d u, v;
+ Vector3d tu = null, tv = null;
+ // t has not been broken, so continue...
+ if (a < 0 || a > 1) {
+ i = 2;
+ j = 0;
+ k = 1;
+ u = Vector3d.getBarycenter(t.vertices[1], t.vertices[2], c, 1 - c);
+ v = Vector3d.getBarycenter(t.vertices[0], t.vertices[2], b, 1 - b);
+ cu = getColorsBarycenter(t.getColor(1), t.getColor(2), c, 1 - c);
+ cv = getColorsBarycenter(t.getColor(0), t.getColor(2), b, 1 - b);
+ if (t.textureCoords != null) {
+ tu = Vector3d.getBarycenter(t.textureCoords[1], t.textureCoords[2], c, 1 - c);
+ tv = Vector3d.getBarycenter(t.textureCoords[0], t.textureCoords[2], b, 1 - b);
+ }
+ } else if (b < 0 || b > 1) {
+ i = 1;
+ j = 2;
+ k = 0;
+ u = Vector3d.getBarycenter(t.vertices[0], t.vertices[1], a, 1 - a);
+ v = Vector3d.getBarycenter(t.vertices[1], t.vertices[2], c, 1 - c);
+ cu = getColorsBarycenter(t.getColor(0), t.getColor(1), a, 1 - a);
+ cv = getColorsBarycenter(t.getColor(1), t.getColor(2), c, 1 - c);
+ if (t.textureCoords != null) {
+ tu = Vector3d.getBarycenter(t.textureCoords[0], t.textureCoords[1], a, 1 - a);
+ tv = Vector3d.getBarycenter(t.textureCoords[1], t.textureCoords[2], c, 1 - c);
+ }
+ } else {
+ i = 0;
+ j = 1;
+ k = 2;
+ u = Vector3d.getBarycenter(t.vertices[0], t.vertices[2], b, 1 - b);
+ v = Vector3d.getBarycenter(t.vertices[0], t.vertices[1], a, 1 - a);
+ cu = getColorsBarycenter(t.getColor(0), t.getColor(2), b, 1 - b);
+ cv = getColorsBarycenter(t.getColor(0), t.getColor(1), a, 1 - a);
+ if (t.textureCoords != null) {
+ tu = Vector3d.getBarycenter(t.textureCoords[0], t.textureCoords[2], b, 1 - b);
+ tv = Vector3d.getBarycenter(t.textureCoords[0], t.textureCoords[1], a, 1 - a);
+ }
+ }
+
+ Vector3d[] vertices1 = new Vector3d[] {u, t.vertices[i], v};
+ Color[] colors1 = new Color[] {cu, t.getColor(i), cv};
+ Vector3d[] vertices2 = new Vector3d[] {u, v, t.vertices[j]};
+ Color[] colors2 = new Color[] {cu, cv, t.getColor(j)};
+ Vector3d[] vertices3 = new Vector3d[] {u, t.vertices[j], t.vertices[k]};
+ Color[] colors3 = new Color[] {cu, t.getColor(j), t.getColor(k)};
+
+ Vector3d[] tvertices1 = null;
+ Vector3d[] tvertices2 = null;
+ Vector3d[] tvertices3 = null;
+ if (t.textureCoords != null) {
+ tvertices1 = new Vector3d[] {tu, t.textureCoords[i], tv};
+ tvertices2 = new Vector3d[] {tu, tv, t.textureCoords[j]};
+ tvertices3 = new Vector3d[] {tu, t.textureCoords[j], t.textureCoords[k]};
+ }
+
+ try {
+ Triangle t1 = new Triangle(vertices1, colors1, null);
+ t1.setSprite(t.getSprite());
+ list.add(t1);
+ Triangle t2 = new Triangle(vertices2, colors2, null);
+ t2.setSprite(t.getSprite());
+ list.add(t2);
+ Triangle t3 = new Triangle(vertices3, colors3, null);
+ t3.setSprite(t.getSprite());
+ list.add(t3);
+ if (t.textureCoords != null) {
+ t1.textureCoords = tvertices1;
+ t2.textureCoords = tvertices2;
+ t3.textureCoords = tvertices3;
+ t1.image = t2.image = t3.image = t.image;
+ t1.filter = t2.filter = t3.filter = t.filter;
+ }
+ } catch (InvalidPolygonException e) { }
+
+ addSegments(list, t, p, Vector3d.product(t.v0v1, n), n);
+
+ return list;
+ }
+
+ private static final void addSegments(List<ConvexObject> list, Triangle t, Vector3d p, Vector3d u, Vector3d n) {
+ if (t.segments != null) {
+ List<Segment> segs = new ArrayList<Segment>();
+ for (Segment s : t.segments) {
+ s.removeConvexObject(t);
+ List<Segment> l = s.breakObject(p, u, n);
+ if (l != null && !l.isEmpty()) {
+ segs.addAll(l);
+ s.replaceSegment(l);
+ }
+ }
+ t.textureCoords = null;
+
+ for (Segment s : segs) {
+ for (ConvexObject tri : list) {
+ ((Triangle) tri).addSegment(s);
+ }
+ }
+ }
+ }
+
+ /**
+ * Get the broken triangles in following the intersection of the planes containing t1 and t2.
+ * The planes containing t1 and t2 are supposed to be secant.
+ * @param t1 the first triangle
+ * @param t2 the second triangle
+ * @return an array of length 2 containing the resulting triangles for t1 and t2.
+ */
+ protected static List<ConvexObject> breakIntersectingTriangles(Triangle t1, Triangle t2) {
+ Vector3d n = Vector3d.product(t1.getNormal(), t2.getNormal());
+ n = n.times(1 / n.getNorm2());
+ Vector3d u = Vector3d.product(t2.v0v1, n);
+ Vector3d v = Vector3d.product(n, t1.v0v1);
+ Vector3d p = Vector3d.getBarycenter(u, v, t1.v0v1.scalar(t1.vertices[0]), t2.v0v1.scalar(t2.vertices[0]));
+
+ List<ConvexObject> list1 = breakTriangleOnLine(t1, p, t2.v0v1);
+ List<ConvexObject> list2 = breakTriangleOnLine(t2, p, t1.v0v1);
+ list1.addAll(list2);
+
+ return list1;
+ }
+
+ public String toString() {
+ return "Triangle: " + vertices[0].toString() + " " + vertices[1].toString() + " " + vertices[2].toString() + "\nColor: " + getColor(0) + "\nPrecedence: " + precedence;
+ }
+}
diff --git a/modules/scirenderer/src/org/scilab/forge/scirenderer/implementation/g2d/renderer/G2DRenderer.java b/modules/scirenderer/src/org/scilab/forge/scirenderer/implementation/g2d/renderer/G2DRenderer.java
new file mode 100755
index 000000000..e3bda655c
--- /dev/null
+++ b/modules/scirenderer/src/org/scilab/forge/scirenderer/implementation/g2d/renderer/G2DRenderer.java
@@ -0,0 +1,58 @@
+/*
+ * Scilab ( http://www.scilab.org/ ) - This file is part of Scilab
+ * Copyright (C) 2012 - Scilab Enterprises - Calixre DENIZET
+ *
+ * This file must be used under the terms of the CeCILL.
+ * This source file is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at
+ * http://www.cecill.info/licences/Licence_CeCILL_V2.1-en.txt
+ */
+
+package org.scilab.forge.scirenderer.implementation.g2d.renderer;
+
+import org.scilab.forge.scirenderer.Drawer;
+import org.scilab.forge.scirenderer.DrawingTools;
+import org.scilab.forge.scirenderer.renderer.Renderer;
+
+/**
+ * @author Calixte DENIZET
+ */
+public class G2DRenderer implements Renderer {
+
+ /**
+ * The current drawer.
+ */
+ private Drawer drawer;
+
+ /**
+ * Default constructor.
+ * The constructor is package : only {@link G2DRendererManager} can instantiate this object.
+ */
+ G2DRenderer() { }
+
+ @Override
+ public void setDrawer(Drawer drawer) {
+ this.drawer = drawer;
+ }
+
+ @Override
+ public Drawer getDrawer() {
+ return drawer;
+ }
+
+ @Override
+ public void reload() {
+ // todo : on met qque chose ici ou pas ?
+ }
+
+ /**
+ * Perform a draw to the given canvas.
+ * @param drawingTools the given drawing tools.
+ */
+ public void draw(DrawingTools drawingTools) {
+ if (drawer != null) {
+ drawer.draw(drawingTools);
+ }
+ }
+}
diff --git a/modules/scirenderer/src/org/scilab/forge/scirenderer/implementation/g2d/renderer/G2DRendererManager.java b/modules/scirenderer/src/org/scilab/forge/scirenderer/implementation/g2d/renderer/G2DRendererManager.java
new file mode 100755
index 000000000..b31ed5c2a
--- /dev/null
+++ b/modules/scirenderer/src/org/scilab/forge/scirenderer/implementation/g2d/renderer/G2DRendererManager.java
@@ -0,0 +1,48 @@
+/*
+ * Scilab ( http://www.scilab.org/ ) - This file is part of Scilab
+ * Copyright (C) 2012 - Scilab Enterprises - Calixte DENIZET
+ *
+ * This file must be used under the terms of the CeCILL.
+ * This source file is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at
+ * http://www.cecill.info/licences/Licence_CeCILL_V2.1-en.txt
+ */
+
+package org.scilab.forge.scirenderer.implementation.g2d.renderer;
+
+import org.scilab.forge.scirenderer.DrawingTools;
+import org.scilab.forge.scirenderer.renderer.Renderer;
+import org.scilab.forge.scirenderer.renderer.RendererManager;
+
+/**
+ * @author Calixte DENIZET
+ */
+public class G2DRendererManager implements RendererManager {
+
+ /**
+ * Default constructor.
+ */
+ public G2DRendererManager() {
+ }
+
+ @Override
+ public Renderer createRenderer() {
+ G2DRenderer newRenderer = new G2DRenderer();
+ return newRenderer;
+ }
+
+ @Override
+ public void dispose(Renderer renderer) { }
+
+ /**
+ * Perform a draw with the given renderer to the given canvas..
+ * @param drawingTools the given drawing tools.
+ * @param renderer the given renderer.
+ */
+ public void draw(DrawingTools drawingTools, Renderer renderer) {
+ if (renderer instanceof G2DRenderer) {
+ ((G2DRenderer) renderer).draw(drawingTools);
+ }
+ }
+}
diff --git a/modules/scirenderer/src/org/scilab/forge/scirenderer/implementation/g2d/texture/G2DTextureDrawingTools.java b/modules/scirenderer/src/org/scilab/forge/scirenderer/implementation/g2d/texture/G2DTextureDrawingTools.java
new file mode 100755
index 000000000..3ae9a6a84
--- /dev/null
+++ b/modules/scirenderer/src/org/scilab/forge/scirenderer/implementation/g2d/texture/G2DTextureDrawingTools.java
@@ -0,0 +1,207 @@
+/*
+ * Scilab ( http://www.scilab.org/ ) - This file is part of Scilab
+ * Copyright (C) 2009-2011 - DIGITEO - Pierre Lando
+ *
+ * This file must be used under the terms of the CeCILL.
+ * This source file is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at
+ * http://www.cecill.info/licences/Licence_CeCILL_V2.1-en.txt
+ */
+
+package org.scilab.forge.scirenderer.implementation.g2d.texture;
+
+import org.scilab.forge.scirenderer.implementation.g2d.motor.G2DStroke;
+import org.scilab.forge.scirenderer.implementation.g2d.texture.G2DTextureManager;
+import org.scilab.forge.scirenderer.shapes.appearance.Appearance;
+import org.scilab.forge.scirenderer.shapes.appearance.Color;
+import org.scilab.forge.scirenderer.texture.Texture;
+import org.scilab.forge.scirenderer.texture.TextureDrawer;
+import org.scilab.forge.scirenderer.texture.TextureDrawingTools;
+import org.scilab.forge.scirenderer.texture.TextEntity;
+
+import javax.swing.Icon;
+import javax.swing.JLabel;
+import java.awt.Dimension;
+import java.awt.Graphics2D;
+import java.awt.RenderingHints;
+import java.awt.font.TextLayout;
+import java.awt.geom.Ellipse2D;
+import java.awt.geom.Rectangle2D;
+
+/**
+ *
+ * Implementation of {@link TextureDrawingTools}.
+ * This implementation create a {@link TextureBufferedImage} an fill it with sprite drawing.
+ *
+ * @author Pierre Lando
+ */
+public class G2DTextureDrawingTools implements TextureDrawingTools {
+
+ private Graphics2D g2d;
+ private int width;
+ private int height;
+
+ /**
+ * Default constructor.
+ * @param width the image width.
+ * @param height the image height.
+ * @param useSquareTexture true if square texture is needed.
+ */
+ public G2DTextureDrawingTools(Graphics2D g2d) {
+ this.g2d = g2d;
+ }
+
+ public void setGraphics(Graphics2D g2d) {
+ this.g2d = g2d;
+ }
+
+ public void accept(Texture texture) {
+ G2DTextureManager.G2DTexture t = (G2DTextureManager.G2DTexture) texture;
+ TextureDrawer drawer = t.getDrawer();
+ Dimension d = drawer.getTextureSize();
+ this.width = (int) d.getWidth();
+ this.height = (int) d.getHeight();
+ accept(drawer, this.width, this.height);
+ }
+
+ /**
+ * Ask this image to accept a sprite drawer.
+ * This image will contain the drawing of the given drawer.
+ * @param spriteDrawer the given sprite drawer.
+ */
+ public void accept(TextureDrawer textureDrawer, int width, int height) {
+ // Change center coordinate to (0, 0).
+ if (textureDrawer.getOriginPosition() == TextureDrawer.OriginPosition.CENTER) {
+ g2d.translate(width / 2.0, height / 2.0);
+ }
+
+ boolean aa = g2d.getRenderingHint(RenderingHints.KEY_ANTIALIASING) == RenderingHints.VALUE_ANTIALIAS_ON;
+ if (!aa) {
+ g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
+ }
+ textureDrawer.draw(this);
+
+ if (!aa) {
+ g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_OFF);
+ }
+ }
+
+ @Override
+ public void drawPlus(int size, Appearance appearance) {
+ if (size > 1) {
+ int r = size / 2;
+ int[] coords1 = new int[] { -r, 0, r, 0};
+ int[] coords2 = new int[] {0, -r, 0, r};
+
+ drawPolyline(coords1, appearance);
+ drawPolyline(coords2, appearance);
+ } else {
+ fillDisc(0, 0, 1, appearance.getLineColor());
+ }
+ }
+
+ @Override
+ public void drawPolyline(int[] coordinates, Appearance appearance) {
+ if (coordinates.length == 2) {
+
+ }
+
+ int nbPoint = coordinates.length / 2;
+
+ int[] xCoordinates = new int[nbPoint];
+ int[] yCoordinates = new int[nbPoint];
+
+ int k = 0;
+ for (int i = 0; i < coordinates.length; i += 2) {
+ xCoordinates[k] = coordinates[i];
+ yCoordinates[k] = coordinates[i + 1];
+ k++;
+ }
+
+ g2d.setColor(appearance.getLineColor());
+ g2d.setStroke(G2DStroke.getStroke(appearance, 0));
+
+ g2d.drawPolyline(xCoordinates, yCoordinates, nbPoint);
+ }
+
+ @Override
+ public void fillPolygon(int[] coordinates, Appearance appearance) {
+ int nbPoint = coordinates.length / 2;
+
+ int[] xCoordinates = new int[nbPoint];
+ int[] yCoordinates = new int[nbPoint];
+
+ int k = 0;
+ for (int i = 0; i < coordinates.length; i += 2) {
+ xCoordinates[k] = coordinates[i];
+ yCoordinates[k] = coordinates[i + 1];
+ k++;
+ }
+
+ if (appearance.getFillColor().getAlphaAsFloat() != 0) {
+ g2d.setColor(appearance.getFillColor());
+ g2d.fillPolygon(xCoordinates, yCoordinates, nbPoint);
+ }
+
+ if (!appearance.getLineColor().equals(appearance.getFillColor())) {
+ int usedLength = coordinates.length - (coordinates.length % 2);
+ int[] borderCoordinate = new int[usedLength + 2];
+ System.arraycopy(coordinates, 0, borderCoordinate, 0, usedLength);
+ borderCoordinate[usedLength] = coordinates[0];
+ borderCoordinate[usedLength + 1] = coordinates[1];
+
+ drawPolyline(borderCoordinate, appearance);
+ }
+ }
+
+ @Override
+ public void drawCircle(int x, int y, int diameter, Appearance appearance) {
+ g2d.setColor(appearance.getLineColor());
+ g2d.setStroke(G2DStroke.getStroke(appearance, 0));
+ double r = ((double) diameter) / 2;
+ g2d.draw(new Ellipse2D.Double(x - r, y - r, diameter, diameter));
+ }
+
+ @Override
+ public void fillDisc(int x, int y, int diameter, Color color) {
+ if (color.getAlphaAsFloat() != 0) {
+ g2d.setColor(color);
+ double r = ((double) diameter) / 2;
+ g2d.fill(new Ellipse2D.Double(x - r, y - r, diameter, diameter));
+ }
+ }
+
+ @Override
+ public void draw(TextEntity textEntity, int x, int y) {
+ if (textEntity != null && textEntity.isValid()) {
+ if (textEntity.isTextAntiAliased()) {
+ g2d.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_ON);
+ } else {
+ g2d.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_OFF);
+ }
+
+ if (textEntity.isTextUseFractionalMetrics()) {
+ g2d.setRenderingHint(RenderingHints.KEY_FRACTIONALMETRICS, RenderingHints.VALUE_FRACTIONALMETRICS_ON);
+ } else {
+ g2d.setRenderingHint(RenderingHints.KEY_FRACTIONALMETRICS, RenderingHints.VALUE_FRACTIONALMETRICS_OFF);
+ }
+ g2d.setColor(textEntity.getTextColor());
+ TextLayout textLayout = new TextLayout(textEntity.getText(), textEntity.getFont(), g2d.getFontRenderContext());
+ Rectangle2D bounds = textLayout.getBounds();
+ g2d.setFont(textEntity.getFont());
+ g2d.drawString(textEntity.getText(), (float) (x - bounds.getX()), y + textLayout.getAscent());
+ }
+ }
+
+ @Override
+ public void draw(Icon icon, int x, int y) {
+ icon.paintIcon(new JLabel(), g2d, x, y);
+ }
+
+ @Override
+ public void clear(Color color) {
+ g2d.setColor(color);
+ g2d.fillRect(0, 0, width, height);
+ }
+}
diff --git a/modules/scirenderer/src/org/scilab/forge/scirenderer/implementation/g2d/texture/G2DTextureManager.java b/modules/scirenderer/src/org/scilab/forge/scirenderer/implementation/g2d/texture/G2DTextureManager.java
new file mode 100755
index 000000000..2fb92510b
--- /dev/null
+++ b/modules/scirenderer/src/org/scilab/forge/scirenderer/implementation/g2d/texture/G2DTextureManager.java
@@ -0,0 +1,513 @@
+/*
+ * Scilab ( http://www.scilab.org/ ) - This file is part of Scilab
+ * Copyright (C) 2012 - Scilab Enterprises - Calixte DENIZET
+ *
+ * This file must be used under the terms of the CeCILL.
+ * This source file is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at
+ * http://www.cecill.info/licences/Licence_CeCILL_V2.1-en.txt
+ */
+
+package org.scilab.forge.scirenderer.implementation.g2d.texture;
+
+import org.scilab.forge.scirenderer.SciRendererException;
+import org.scilab.forge.scirenderer.implementation.g2d.G2DCanvas;
+import org.scilab.forge.scirenderer.implementation.g2d.G2DDrawingTools;
+import org.scilab.forge.scirenderer.texture.AbstractTexture;
+import org.scilab.forge.scirenderer.texture.Texture;
+import org.scilab.forge.scirenderer.texture.TextureDrawer;
+import org.scilab.forge.scirenderer.texture.TextureManager;
+import org.scilab.forge.scirenderer.texture.TextureDataProvider.ImageType;
+
+import java.awt.Dimension;
+import java.awt.image.BufferedImage;
+import java.nio.ByteBuffer;
+import java.nio.ByteOrder;
+import java.nio.FloatBuffer;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * @author Calixte DENIZET
+ */
+public class G2DTextureManager implements TextureManager {
+
+ private static Map<ImageBuffer, ImageBuffer> images = new HashMap<ImageBuffer, ImageBuffer>();
+
+ public G2DTextureManager(G2DCanvas canvas) { }
+
+ public static void clear() {
+ images.clear();
+ }
+
+ /**
+ * Draw the given texture.
+ * @param drawingTools used drawing tools.
+ * @param texture the texture too drawn.
+ * @throws org.scilab.forge.scirenderer.SciRendererException if the texture is invalid.
+ */
+ public void draw(G2DDrawingTools drawingTools, Texture texture) throws SciRendererException {
+ if (texture instanceof G2DTexture) {
+ ((G2DTexture) texture).draw(drawingTools);
+ }
+ }
+
+ @Override
+ public Texture createTexture() {
+ return new G2DTexture();
+ }
+
+ @Override
+ public void dispose(Collection<Texture> textures) {
+ for (Texture texture : textures) {
+ dispose(texture);
+ }
+ }
+
+ @Override
+ public void dispose(Texture texture) {
+ if (texture instanceof G2DTexture) {
+ ((G2DTexture) texture).dispose();
+ }
+ }
+
+ private static final int toColorComp(final float f) {
+ return (f < 0) ? 0 : ((f > 1) ? 0xFF : ((int) (f * 255.0f)));
+ }
+
+ /**
+ * Inner class for {@link Texture} implementation.
+ */
+ public class G2DTexture extends AbstractTexture implements Texture {
+
+ private ImageBuffer image;
+ private TextureDrawer drawer;
+
+ /**
+ * Default constructor.
+ */
+ public G2DTexture() { }
+
+ public void dispose() {
+ images.remove(image);
+ }
+
+ @Override
+ public void setDrawer(TextureDrawer drawer) {
+ this.drawer = drawer;
+ super.setDrawer(drawer);
+ }
+
+ public TextureDrawer getDrawer() {
+ return drawer;
+ }
+
+ public void draw(G2DDrawingTools drawingTools) {
+ drawingTools.getMotor3D().drawTexture(drawingTools, getImage(), this);
+ }
+
+ public BufferedImage getImage() {
+ if (image == null) {
+ Dimension textureSize = getDataProvider().getTextureSize();
+ ByteBuffer buffer = getDataProvider().getData();
+ ImageType type = getDataProvider().getImageType();
+ int imageType = BufferedImage.TYPE_INT_RGB;
+ int[] ibuffer = null;
+ final ByteOrder order = ByteOrder.nativeOrder();
+
+ switch (type) {
+ case RGB: {
+ imageType = BufferedImage.TYPE_INT_RGB;
+ ibuffer = new int[buffer.capacity() / 3];
+ int k = 0;
+ for (int i = 0; i < buffer.capacity(); i += 3) {
+ ibuffer[k++] = ((buffer.get(i) & 0xFF) << 16) | ((buffer.get(i + 1) & 0xFF) << 8) | (buffer.get(i + 2) & 0xFF);
+ }
+ break;
+ }
+ case RGB_RGBA: {
+ imageType = BufferedImage.TYPE_INT_RGB;
+ ibuffer = new int[buffer.capacity() / 4];
+ int k = 0;
+ if (order == ByteOrder.LITTLE_ENDIAN) {
+ for (int i = 0; i < buffer.capacity(); i += 4) {
+ ibuffer[k++] = ((buffer.get(i + 3) & 0xFF) << 16) | ((buffer.get(i + 2) & 0xFF) << 8) | (buffer.get(i + 1) & 0xFF);
+ }
+ } else {
+ for (int i = 0; i < buffer.capacity(); i += 4) {
+ ibuffer[k++] = ((buffer.get(i) & 0xFF) << 16) | ((buffer.get(i + 1) & 0xFF) << 8) | (buffer.get(i + 2) & 0xFF);
+ }
+ }
+ break;
+ }
+ case BGR: {
+ imageType = BufferedImage.TYPE_INT_BGR;
+ ibuffer = new int[buffer.capacity() / 3];
+ int k = 0;
+ for (int i = 0; i < buffer.capacity(); i += 3) {
+ ibuffer[k++] = ((buffer.get(i) & 0xFF) << 16) | ((buffer.get(i + 1) & 0xFF) << 8) | (buffer.get(i + 2) & 0xFF);
+ }
+ break;
+ }
+ case GRAY: {
+ imageType = BufferedImage.TYPE_INT_RGB;
+ ibuffer = new int[buffer.capacity()];
+ for (int i = 0; i < buffer.capacity(); i++) {
+ final int c = buffer.get(i) & 0xFF;
+ ibuffer[i] = (c << 16) | (c << 8) | c;
+ }
+ break;
+ }
+ case GRAY_16: {
+ imageType = BufferedImage.TYPE_INT_RGB;
+ ibuffer = new int[buffer.capacity() / 2];
+ int k = 0;
+ if (order == ByteOrder.LITTLE_ENDIAN) {
+ for (int i = 0; i < buffer.capacity(); i += 2) {
+ final int c = (((buffer.get(i + 1) & 0xFF) << 8) | (buffer.get(i) & 0xFF)) / 257;
+ ibuffer[k++] = (c << 16) | (c << 8) | c;
+ }
+ } else {
+ for (int i = 0; i < buffer.capacity(); i += 2) {
+ final int c = (((buffer.get(i) & 0xFF) << 8) | (buffer.get(i + 1) & 0xFF)) / 257;
+ ibuffer[k++] = (c << 16) | (c << 8) | c;
+ }
+ }
+ break;
+ }
+ case RGBA: {
+ imageType = BufferedImage.TYPE_INT_ARGB;
+ ibuffer = new int[buffer.capacity() / 4];
+ if (order == ByteOrder.LITTLE_ENDIAN) {
+ int k = 0;
+ for (int i = 0; i < buffer.capacity(); i += 4) {
+ ibuffer[k++] = ((buffer.get(i) & 0xFF) << 24) | ((buffer.get(i + 3) & 0xFF) << 16) | ((buffer.get(i + 2) & 0xFF) << 8) | (buffer.get(i + 1) & 0xFF);
+ }
+ } else {
+ int k = 0;
+ for (int i = 0; i < buffer.capacity(); i += 4) {
+ ibuffer[k++] = ((buffer.get(i + 3) & 0xFF) << 24) | ((buffer.get(i) & 0xFF) << 16) | ((buffer.get(i + 1) & 0xFF) << 8) | (buffer.get(i + 2) & 0xFF);
+ }
+ }
+ break;
+ }
+ case RGBA_REV: {
+ imageType = BufferedImage.TYPE_INT_ARGB;
+ ibuffer = new int[buffer.capacity() / 4];
+ if (order == ByteOrder.BIG_ENDIAN) {
+ int k = 0;
+ for (int i = 0; i < buffer.capacity(); i += 4) {
+ ibuffer[k++] = ((buffer.get(i) & 0xFF) << 24) | ((buffer.get(i + 3) & 0xFF) << 16) | ((buffer.get(i + 2) & 0xFF) << 8) | (buffer.get(i + 1) & 0xFF);
+ }
+ } else {
+ int k = 0;
+ for (int i = 0; i < buffer.capacity(); i += 4) {
+ ibuffer[k++] = ((buffer.get(i + 3) & 0xFF) << 24) | ((buffer.get(i) & 0xFF) << 16) | ((buffer.get(i + 1) & 0xFF) << 8) | (buffer.get(i + 2) & 0xFF);
+ }
+ }
+ break;
+ }
+ case ABGR: {
+ imageType = BufferedImage.TYPE_INT_ARGB;
+ ibuffer = new int[buffer.capacity() / 4];
+ int k = 0;
+ for (int i = 0; i < buffer.capacity(); i += 4) {
+ ibuffer[k++] = ((buffer.get(i) & 0xFF) << 24) | ((buffer.get(i + 3) & 0xFF) << 16) | ((buffer.get(i + 2) & 0xFF) << 8) | (buffer.get(i + 1) & 0xFF);
+ }
+ break;
+ }
+ case RGB_332: {
+ imageType = BufferedImage.TYPE_INT_RGB;
+ ibuffer = new int[buffer.capacity()];
+ for (int i = 0; i < buffer.capacity(); i++) {
+ final int c = buffer.get(i) & 0xFF;
+ ibuffer[i] = ((((c >> 5) & 0x7) * 255 / 7) << 16) | ((((c >> 2) & 0x7) * 255 / 7) << 8) | ((c & 0x3) * 255 / 3);
+ }
+ break;
+ }
+ case RED: {
+ imageType = BufferedImage.TYPE_INT_RGB;
+ ibuffer = new int[buffer.capacity()];
+ for (int i = 0; i < buffer.capacity(); i++) {
+ ibuffer[i] = (buffer.get(i) & 0xFF) << 16;
+ }
+ break;
+ }
+ case GREEN: {
+ imageType = BufferedImage.TYPE_INT_RGB;
+ ibuffer = new int[buffer.capacity()];
+ for (int i = 0; i < buffer.capacity(); i++) {
+ ibuffer[i] = (buffer.get(i) & 0xFF) << 8;
+ }
+ break;
+ }
+ case BLUE: {
+ imageType = BufferedImage.TYPE_INT_RGB;
+ ibuffer = new int[buffer.capacity()];
+ for (int i = 0; i < buffer.capacity(); i++) {
+ ibuffer[i] = (buffer.get(i) & 0xFF);
+ }
+ break;
+ }
+ case INTENSITY: {
+ imageType = BufferedImage.TYPE_INT_ARGB;
+ ibuffer = new int[buffer.capacity()];
+ for (int i = 0; i < buffer.capacity(); i++) {
+ final int c = buffer.get(i) & 0xFF;
+ ibuffer[i] = (c << 24) | (c << 16) | (c << 8) | c;
+ }
+ break;
+ }
+ case RGBA_4444: {
+ imageType = BufferedImage.TYPE_INT_ARGB;
+ ibuffer = new int[buffer.capacity() / 2];
+ int k = 0;
+ if (order == ByteOrder.LITTLE_ENDIAN) {
+ for (int i = 0; i < buffer.capacity(); i += 2) {
+ int c = buffer.get(i) & 0xFF;
+ final int B = ((c >> 4) & 0xF) * 0x11;
+ final int A = (c & 0xF) * 0x11;
+ c = buffer.get(i + 1) & 0xFF;
+ final int R = ((c >> 4) & 0xF) * 0x11;
+ final int G = (c & 0xF) * 0x11;
+ ibuffer[k++] = (A << 24) | (R << 16) | (G << 8) | B;
+ }
+ } else {
+ for (int i = 0; i < buffer.capacity(); i += 2) {
+ int c = buffer.get(i + 1) & 0xFF;
+ final int B = ((c >> 4) & 0xF) * 0x2F;
+ final int A = (c & 0xF) * 0x2F;
+ c = buffer.get(i) & 0xFF;
+ final int R = ((c >> 4) & 0xF) * 0x2F;
+ final int G = (c & 0xF) * 0x2F;
+ ibuffer[k++] = (A << 24) | (R << 16) | (G << 8) | B;
+ }
+ }
+ break;
+ }
+ case RGBA_5551: {
+ imageType = BufferedImage.TYPE_INT_ARGB;
+ ibuffer = new int[buffer.capacity() / 2];
+ int k = 0;
+ if (order == ByteOrder.LITTLE_ENDIAN) {
+ for (int i = 0; i < buffer.capacity(); i += 2) {
+ int c = buffer.get(i) & 0xFF;
+ final int B = (((c >> 1) & 0x1F) * 0xFF) / 0x1F;
+ final int A = (c & 0x1) * 0xFF;
+ int G = (c >> 6) & 0x3;
+ c = buffer.get(i + 1) & 0xFF;
+ final int R = (((c >> 3) & 0x1F) * 0xFF) / 0x1F;
+ G = (((c & 0x7) << 2 | G) * 0xFF) / 0x1F;
+ ibuffer[k++] = (A << 24) | (R << 16) | (G << 8) | B;
+ }
+ } else {
+ for (int i = 0; i < buffer.capacity(); i += 2) {
+ int c = buffer.get(i + 1) & 0xFF;
+ final int B = (((c >> 1) & 0x1F) * 0xFF) / 0x1F;
+ final int A = (c & 0x1) * 0xFF;
+ int G = (c >> 6) & 0x3;
+ c = buffer.get(i) & 0xFF;
+ final int R = (((c >> 3) & 0x1F) * 0xFF) / 0x1F;
+ G = (((c & 0x7) << 2 | G) * 0xFF) / 0x1F;
+ ibuffer[k++] = (A << 24) | (R << 16) | (G << 8) | B;
+ }
+ }
+ break;
+ }
+ case RGB_FLOAT: {
+ imageType = BufferedImage.TYPE_INT_RGB;
+ FloatBuffer fbuffer = buffer.asFloatBuffer();
+ ibuffer = new int[fbuffer.capacity() / 3];
+ int k = 0;
+ for (int i = 0; i < fbuffer.capacity(); i += 3) {
+ ibuffer[k++] = (toColorComp(fbuffer.get(i)) << 16) | (toColorComp(buffer.get(i + 1)) << 8) | toColorComp(buffer.get(i + 2));
+ }
+ break;
+ }
+ case RGBA_FLOAT: {
+ imageType = BufferedImage.TYPE_INT_ARGB;
+ buffer.order(order);
+ FloatBuffer fbuffer = buffer.asFloatBuffer();
+ ibuffer = new int[fbuffer.capacity() / 4];
+ int k = 0;
+ for (int i = 0; i < fbuffer.capacity(); i += 4) {
+ ibuffer[k++] = (toColorComp(fbuffer.get(i + 3)) << 24) | (toColorComp(fbuffer.get(i)) << 16) | (toColorComp(fbuffer.get(i + 1)) << 8) | toColorComp(fbuffer.get(i + 2));
+ }
+ break;
+ }
+ case GRAY_FLOAT: {
+ imageType = BufferedImage.TYPE_INT_RGB;
+ buffer.order(order);
+ FloatBuffer fbuffer = buffer.asFloatBuffer();
+ ibuffer = new int[fbuffer.capacity()];
+ for (int i = 0; i < fbuffer.capacity(); i++) {
+ final int c = toColorComp(fbuffer.get(i));
+ ibuffer[i] = (c << 16) | (c << 8) | c;
+ }
+ break;
+ }
+ case RED_16: {
+ imageType = BufferedImage.TYPE_INT_RGB;
+ ibuffer = new int[buffer.capacity() / 2];
+ int k = 0;
+ if (order == ByteOrder.LITTLE_ENDIAN) {
+ for (int i = 0; i < buffer.capacity(); i += 2) {
+ final int c = (((buffer.get(i + 1) & 0xFF) << 8) | (buffer.get(i) & 0xFF)) / 257;
+ ibuffer[k++] = c << 16;
+ }
+ } else {
+ for (int i = 0; i < buffer.capacity(); i += 2) {
+ final int c = (((buffer.get(i) & 0xFF) << 8) | (buffer.get(i + 1) & 0xFF)) / 257;
+ ibuffer[k++] = c << 16;
+ }
+ }
+ break;
+ }
+ case GREEN_16: {
+ imageType = BufferedImage.TYPE_INT_RGB;
+ ibuffer = new int[buffer.capacity() / 2];
+ int k = 0;
+ if (order == ByteOrder.LITTLE_ENDIAN) {
+ for (int i = 0; i < buffer.capacity(); i += 2) {
+ final int c = (((buffer.get(i + 1) & 0xFF) << 8) | (buffer.get(i) & 0xFF)) / 257;
+ ibuffer[k++] = c << 8;
+ }
+ } else {
+ for (int i = 0; i < buffer.capacity(); i += 2) {
+ final int c = (((buffer.get(i) & 0xFF) << 8) | (buffer.get(i + 1) & 0xFF)) / 257;
+ ibuffer[k++] = c << 8;
+ }
+ }
+ break;
+ }
+ case BLUE_16: {
+ imageType = BufferedImage.TYPE_INT_RGB;
+ ibuffer = new int[buffer.capacity() / 2];
+ int k = 0;
+ if (order == ByteOrder.LITTLE_ENDIAN) {
+ for (int i = 0; i < buffer.capacity(); i += 2) {
+ final int c = (((buffer.get(i + 1) & 0xFF) << 8) | (buffer.get(i) & 0xFF)) / 257;
+ ibuffer[k++] = c;
+ }
+ } else {
+ for (int i = 0; i < buffer.capacity(); i += 2) {
+ final int c = (((buffer.get(i) & 0xFF) << 8) | (buffer.get(i + 1) & 0xFF)) / 257;
+ ibuffer[k++] = c;
+ }
+ }
+ break;
+ }
+ case RED_FLOAT: {
+ imageType = BufferedImage.TYPE_INT_RGB;
+ buffer.order(order);
+ FloatBuffer fbuffer = buffer.asFloatBuffer();
+ ibuffer = new int[fbuffer.capacity()];
+ for (int i = 0; i < fbuffer.capacity(); i++) {
+ ibuffer[i] = toColorComp(fbuffer.get(i)) << 16;
+ }
+ break;
+ }
+ case GREEN_FLOAT: {
+ imageType = BufferedImage.TYPE_INT_RGB;
+ buffer.order(order);
+ FloatBuffer fbuffer = buffer.asFloatBuffer();
+ ibuffer = new int[fbuffer.capacity()];
+ for (int i = 0; i < fbuffer.capacity(); i++) {
+ ibuffer[i] = toColorComp(fbuffer.get(i)) << 8;
+ }
+ break;
+ }
+ case BLUE_FLOAT: {
+ imageType = BufferedImage.TYPE_INT_RGB;
+ buffer.order(order);
+ FloatBuffer fbuffer = buffer.asFloatBuffer();
+ ibuffer = new int[fbuffer.capacity()];
+ for (int i = 0; i < fbuffer.capacity(); i++) {
+ ibuffer[i] = toColorComp(fbuffer.get(i));
+ }
+ break;
+ }
+ case RGBA_BYTE: {
+ imageType = BufferedImage.TYPE_INT_ARGB;
+ ibuffer = new int[buffer.capacity() / 4];
+ int k = 0;
+ for (int i = 0; i < buffer.capacity(); i += 4) {
+ ibuffer[k++] = ((buffer.get(i + 3) & 0xFF) << 24) | ((buffer.get(i) & 0xFF) << 16) | ((buffer.get(i + 1) & 0xFF) << 8) | (buffer.get(i + 2) & 0xFF);
+ }
+ break;
+ }
+ }
+
+ ImageBuffer ib1;
+ if (getDataProvider().isRowMajorOrder()) {
+ ib1 = new ImageBuffer(imageType, ibuffer, (int) textureSize.getWidth(), (int) textureSize.getHeight());
+ } else {
+ int[] tibuffer = new int[ibuffer.length];
+ final int w = (int) textureSize.getWidth();
+ final int h = (int) textureSize.getHeight();
+ int k = 0;
+ for (int i = 0; i < h; i++) {
+ for (int j = 0; j < w; j++) {
+ tibuffer[k++] = ibuffer[i + j * h];
+ }
+ }
+ ib1 = new ImageBuffer(imageType, tibuffer, w, h);
+ }
+
+ ImageBuffer ib2 = images.get(ib1);
+ if (ib2 == null) {
+ images.put(ib1, ib1);
+ ib2 = ib1;
+ }
+
+ image = ib2;
+ }
+
+ return image.getImage();
+ }
+ }
+
+ private static class ImageBuffer {
+
+ private int[] buffer;
+ private int hash;
+ private int width;
+ private int height;
+ private BufferedImage image;
+ private int type;
+
+ ImageBuffer(int type, int[] buffer, int width, int height) {
+ this.type = type;
+ this.buffer = buffer;
+ this.hash = Arrays.hashCode(buffer) * 31 + type;
+ this.width = width;
+ this.height = height;
+ }
+
+ BufferedImage getImage() {
+ if (image == null) {
+ image = new BufferedImage(width, height, type);
+ image.setRGB(0, 0, width, height, buffer, 0, width);
+ }
+
+ return image;
+ }
+
+ @Override
+ public int hashCode() {
+ return hash;
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (o instanceof ImageBuffer) {
+ ImageBuffer mfb = (ImageBuffer) o;
+ return type == mfb.type && Arrays.equals(buffer, mfb.buffer);
+ }
+ return false;
+ }
+ }
+}
diff --git a/modules/scirenderer/src/org/scilab/forge/scirenderer/implementation/jogl/HardwareFailException.java b/modules/scirenderer/src/org/scilab/forge/scirenderer/implementation/jogl/HardwareFailException.java
new file mode 100755
index 000000000..7fb69d99e
--- /dev/null
+++ b/modules/scirenderer/src/org/scilab/forge/scirenderer/implementation/jogl/HardwareFailException.java
@@ -0,0 +1,30 @@
+/*
+ * Scilab ( http://www.scilab.org/ ) - This file is part of Scilab
+ * Copyright (C) 2009-2011 - DIGITEO - Pierre Lando
+ *
+ * This file must be used under the terms of the CeCILL.
+ * This source file is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at
+ * http://www.cecill.info/licences/Licence_CeCILL_V2.1-en.txt
+ */
+
+package org.scilab.forge.scirenderer.implementation.jogl;
+
+/**
+ *
+ * An exception to throw when hardware is to bad.
+ *
+ * @author Pierre Lando
+ */
+@SuppressWarnings(value = { "serial" })
+public class HardwareFailException extends Exception {
+
+ /**
+ * Default constructor.
+ * @param message the message associated with this exception.
+ */
+ public HardwareFailException(String message) {
+ super(message);
+ }
+}
diff --git a/modules/scirenderer/src/org/scilab/forge/scirenderer/implementation/jogl/JoGLCanvas.java b/modules/scirenderer/src/org/scilab/forge/scirenderer/implementation/jogl/JoGLCanvas.java
new file mode 100755
index 000000000..f0484023c
--- /dev/null
+++ b/modules/scirenderer/src/org/scilab/forge/scirenderer/implementation/jogl/JoGLCanvas.java
@@ -0,0 +1,440 @@
+/*
+ * Scilab ( http://www.scilab.org/ ) - This file is part of Scilab
+ * Copyright (C) 2009-2011 - DIGITEO - Pierre Lando
+ *
+ * This file must be used under the terms of the CeCILL.
+ * This source file is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at
+ * http://www.cecill.info/licences/Licence_CeCILL_V2.1-en.txt
+ */
+
+package org.scilab.forge.scirenderer.implementation.jogl;
+
+import java.awt.Dimension;
+import java.awt.image.BufferedImage;
+import java.lang.reflect.InvocationTargetException;
+import java.util.concurrent.Semaphore;
+
+import javax.media.opengl.DebugGL2;
+import javax.media.opengl.GL2;
+import javax.media.opengl.GLAutoDrawable;
+import javax.media.opengl.GLCapabilities;
+import javax.media.opengl.GLContext;
+import javax.media.opengl.GLDrawableFactory;
+import javax.media.opengl.GLEventListener;
+import javax.media.opengl.GLException;
+import javax.media.opengl.GLOffscreenAutoDrawable;
+import javax.media.opengl.GLProfile;
+import javax.swing.SwingUtilities;
+
+import org.scilab.forge.scirenderer.Canvas;
+import org.scilab.forge.scirenderer.Drawer;
+import org.scilab.forge.scirenderer.implementation.jogl.buffers.JoGLBuffersManager;
+import org.scilab.forge.scirenderer.implementation.jogl.picking.JoGLPickingManager;
+import org.scilab.forge.scirenderer.implementation.jogl.renderer.JoGLRendererManager;
+import org.scilab.forge.scirenderer.implementation.jogl.texture.JoGLTextureManager;
+import org.scilab.forge.scirenderer.picking.PickingManager;
+
+import com.jogamp.opengl.util.awt.AWTGLReadBufferUtil;
+
+/**
+ * JoGL implementation of a Canvas.
+ *
+ * @author Pierre Lando
+ */
+public final class JoGLCanvas implements Canvas, GLEventListener {
+
+ private static final double[][][] ANTI_ALIASING_JITTER = {
+ {{0.0, 0.0}},
+ {{0.5, 0.5}, {0.5, -0.5}},
+ {
+ { -0.25, -0.5}, {0.25, 0.5}, {0.75, -0.5}, {0.25, 0.5}
+ },
+ {
+ {0.125, -0.125}, { -0.875, 0.875}, { -0.375, 0.375}, {0.375, 0.625},
+ {0.625, -0.625}, {0.875, 0.125}, { -0.125, -0.875}, { -0.625, -0.375}
+ },
+ {
+ { -0.25, -0.125}, {0.25, -0.875}, {0.75, -0.625}, { -0.75, -0.875},
+ { -0.25, 0.375}, {0.75, -0.125}, {0.25, 0.125}, { -0.25, 0.875},
+ {0.25, -0.375}, { -0.75, 0.125}, { -0.75, 0.625}, { -0.25, -0.625},
+ {0.75, 0.875}, {0.75, 0.375}, { -0.75, -0.375}, {0.25, 0.625}
+ }
+ };
+
+ private final GLAutoDrawable autoDrawable;
+
+ private final JoGLDrawingTools drawingTools;
+ private final JoGLParameters parameters;
+ private final JoGLBuffersManager buffersManager;
+ private final JoGLRendererManager rendererManager;
+ private final JoGLPickingManager pickingManager;
+ private final JoGLTextureManager textureManager;
+
+ private final CanvasAnimator canvasAnimator;
+ private boolean isOffscreen;
+ private DebugGL2 debug;
+ private boolean isValid = true;
+ private boolean displayFinished;
+
+
+ /** The current mainDrawer. */
+ private Drawer mainDrawer;
+
+ /** The anti-aliasing level */
+ private int antiAliasingLevel = 0;
+
+ /**
+ * Default constructor.
+ * @param autoDrawable the JoGL autoDrawable this canvas depend on.
+ */
+ JoGLCanvas(GLAutoDrawable autoDrawable) {
+ this.autoDrawable = autoDrawable;
+ parameters = new JoGLParameters();
+ buffersManager = new JoGLBuffersManager();
+ rendererManager = new JoGLRendererManager();
+ drawingTools = new JoGLDrawingTools(this);
+ pickingManager = new JoGLPickingManager(this);
+ textureManager = new JoGLTextureManager(this);
+
+ autoDrawable.addGLEventListener(this);
+ canvasAnimator = new CanvasAnimator(autoDrawable);
+ canvasAnimator.redraw();
+ }
+
+ /**
+ * Constructor for offscreen rendering
+ * @param width the width
+ * @param height the height
+ */
+ JoGLCanvas(int width, int height) {
+ this(getOffscreenDrawable(width, height));
+ isOffscreen = true;
+ }
+
+ public void setDebugMode(boolean debug) {
+ if (debug) {
+ this.debug = new DebugGL2(autoDrawable.getGL().getGL2());
+ } else {
+ this.debug = null;
+ }
+ }
+
+ // Implementation of getter & setter from Canvas.
+
+ @Override
+ public void setMainDrawer(Drawer mainDrawer) {
+ this.mainDrawer = mainDrawer;
+ }
+
+ @Override
+ public Drawer getMainDrawer() {
+ return mainDrawer;
+ }
+
+ @Override
+ public JoGLRendererManager getRendererManager() {
+ return rendererManager;
+ }
+
+ @Override
+ public JoGLBuffersManager getBuffersManager() {
+ return buffersManager;
+ }
+
+ @Override
+ public PickingManager getPickingManager() {
+ return pickingManager;
+ }
+
+ @Override
+ public JoGLTextureManager getTextureManager() {
+ return textureManager;
+ }
+
+ @Override
+ public int getWidth() {
+ return autoDrawable.getSurfaceWidth();
+ }
+
+ @Override
+ public int getHeight() {
+ return autoDrawable.getSurfaceHeight();
+ }
+
+ @Override
+ public Dimension getDimension() {
+ return new Dimension(autoDrawable.getSurfaceWidth(), autoDrawable.getSurfaceHeight());
+ }
+
+ @Override
+ public void redraw() {
+ canvasAnimator.redraw();
+ }
+
+ @Override
+ public void redrawAndWait() {
+ if (SwingUtilities.isEventDispatchThread()) {
+ if (autoDrawable != null) {
+ autoDrawable.display();
+ }
+ return;
+ }
+ try {
+ SwingUtilities.invokeAndWait(new Runnable() {
+ public void run() {
+ autoDrawable.display();
+ }
+ });
+ } catch (Exception e) { }
+ }
+
+ @Override
+ public void waitImage() {
+ canvasAnimator.waitEndOfDrawing();
+ }
+
+ @Override
+ public int getAntiAliasingLevel() {
+ return antiAliasingLevel;
+ }
+
+ @Override
+ public void setAntiAliasingLevel(int antiAliasingLevel) {
+ this.antiAliasingLevel = antiAliasingLevel;
+ }
+
+ // JoGLCanvas specific getter.
+
+ /**
+ * Return the OpenGl context.
+ * @return the OpenGl context.
+ */
+ public GL2 getGl() {
+ if (debug == null) {
+ return autoDrawable.getGL().getGL2();
+ } else {
+ return debug;
+ }
+ }
+
+ /**
+ * Return the rendering parameters.
+ * @return the rendering parameters.
+ */
+ public JoGLParameters getJoGLParameters() {
+ return parameters;
+ }
+
+ /**
+ * Get an image from the autoDrawable
+ * @return an image
+ */
+ public BufferedImage getImage() {
+ return getImage(true);
+ }
+
+ /**
+ * Get an image from the autoDrawable
+ * @return an image
+ */
+ public BufferedImage getImage(final boolean alpha) {
+ while (!canvasAnimator.isDrawFinished() || !displayFinished) {
+ try {
+ Thread.sleep(10);
+ } catch (InterruptedException e) {
+ break;
+ }
+ }
+
+ final BufferedImage[] image = new BufferedImage[1];
+ final GLContext context = autoDrawable.getContext();
+
+ if (SwingUtilities.isEventDispatchThread()) {
+ context.makeCurrent();
+ AWTGLReadBufferUtil buffer = new AWTGLReadBufferUtil(GLProfile.getDefault(), alpha);
+ image[0] = buffer.readPixelsToBufferedImage(getGl(), 0, 0, autoDrawable.getSurfaceWidth(), autoDrawable.getSurfaceHeight(), true);
+ context.release();
+ } else {
+ try {
+ SwingUtilities.invokeAndWait(new Runnable() {
+ public void run() {
+ context.makeCurrent();
+ AWTGLReadBufferUtil buffer = new AWTGLReadBufferUtil(GLProfile.getDefault(), alpha);
+ image[0] = buffer.readPixelsToBufferedImage(getGl(), 0, 0, autoDrawable.getSurfaceWidth(), autoDrawable.getSurfaceHeight(), true);
+ context.release();
+ }
+ });
+ } catch (InterruptedException e) {
+
+ } catch (InvocationTargetException e) {
+ System.err.println(e);
+ e.printStackTrace();
+ }
+ }
+
+ return image[0];
+ }
+
+ /**
+ * Destroy the GLPbuffer
+ */
+ public void destroy() {
+ if (isOffscreen) {
+ ((GLOffscreenAutoDrawable) autoDrawable).destroy();
+ }
+ try {
+ isValid = false;
+ canvasAnimator.finalize();//Thread.dumpStack();
+ } catch (Throwable e) {
+ // TODO: handle exception
+ }
+ }
+
+ /**
+ * Creates a GLPbuffer for an offscreen rendering
+ * @param width the width
+ * @param height the height
+ * @return a GLPbuffer
+ */
+ private static GLAutoDrawable getOffscreenDrawable(int width, int height) {
+ GLDrawableFactory factory = GLDrawableFactory.getDesktopFactory();
+
+ GLCapabilities capabilities = new GLCapabilities(GLProfile.getDefault());
+ capabilities.setPBuffer(true);
+
+ return factory.createOffscreenAutoDrawable(null, capabilities, null, width, height);
+ }
+
+ // Implementation of function from GLEventListener.
+ @Override
+ public void display(GLAutoDrawable glAutoDrawable) {
+ if (isValid) {
+ displayFinished = false;
+ GL2 gl = getGl().getGL2();
+ buffersManager.glSynchronize(gl);
+ rendererManager.glSynchronize(gl);
+ drawingTools.glSynchronize(gl);
+
+ if (mainDrawer != null) {
+ gl.glEnable(GL2.GL_DEPTH_TEST);
+ gl.glDepthFunc(GL2.GL_LEQUAL); // Set to less equal to allow last drawn object to be on the top.
+
+ if ((antiAliasingLevel > 0) && (antiAliasingLevel < 5) && (drawingTools.getGLCapacity().isAccumulationBufferPresent())) {
+ org.scilab.forge.scirenderer.renderer.Renderer renderer = rendererManager.createRenderer();
+ renderer.setDrawer(mainDrawer);
+
+ double[][] jitter = ANTI_ALIASING_JITTER[antiAliasingLevel];
+ Dimension dimension = getDimension();
+ gl.glClear(GL2.GL_ACCUM_BUFFER_BIT);
+ for (double[] aJitter : jitter) {
+ drawingTools.glSynchronize(gl);
+
+ gl.glMatrixMode(GL2.GL_PROJECTION);
+ gl.glLoadIdentity();
+ gl.glTranslated(aJitter[0] / dimension.getWidth(), aJitter[1] / dimension.getHeight(), 0.);
+
+ gl.glClear(GL2.GL_DEPTH_BUFFER_BIT);
+ rendererManager.draw(drawingTools, renderer);
+ //mainDrawer.draw(drawingTools);
+ gl.glReadBuffer(GL2.GL_BACK);
+ gl.glAccum(GL2.GL_ACCUM, 1f / jitter.length);
+ }
+
+ rendererManager.dispose(drawingTools, renderer);
+
+ gl.glDrawBuffer(GL2.GL_BACK);
+ gl.glAccum(GL2.GL_RETURN, 1.0f);
+ } else {
+ gl.glMatrixMode(GL2.GL_PROJECTION);
+ gl.glLoadIdentity();
+ gl.glClear(GL2.GL_DEPTH_BUFFER_BIT);
+ mainDrawer.draw(drawingTools);
+ }
+ }
+
+ pickingManager.glConsume(drawingTools);
+ displayFinished = true;
+ }
+ }
+
+ @Override
+ public void init(GLAutoDrawable glAutoDrawable) {
+ textureManager.glReload();
+ buffersManager.glReload();
+ rendererManager.glReload();
+ }
+
+ @Override
+ public void reshape(GLAutoDrawable glAutoDrawable, int x, int y, int width, int height) {
+ }
+
+ @Override
+ public void dispose(GLAutoDrawable drawable) { }
+
+ /**
+ * this class manage asynchronous scene drawing.
+ */
+ private class CanvasAnimator implements Runnable {
+
+ private final Semaphore semaphore = new Semaphore(1);
+ private final Thread thread;
+ private final GLAutoDrawable autoDrawable;
+ private boolean running = true;
+
+ public CanvasAnimator(GLAutoDrawable autoDrawable) {
+ this.autoDrawable = autoDrawable;
+ this.thread = new Thread(this);
+ thread.start();
+ //System.err.println("[DEBUG] nb threads = "+Thread.activeCount());
+ }
+
+ @Override
+ public void finalize() throws Throwable {
+ running = false;
+ // we increment the semaphore to allow run() to unlock it and to be sure
+ // to go out.
+ semaphore.release();
+ autoDrawable.destroy();
+ super.finalize();
+ }
+
+ public synchronized boolean isDrawFinished() {
+ return semaphore.availablePermits() == 0;
+ }
+
+ /** Ask the animator to perform a draw later. */
+ public synchronized void redraw() {
+ semaphore.release();
+ }
+
+ /** Wait until a drawing has been performed */
+ public void waitEndOfDrawing() {
+ semaphore.drainPermits();
+ }
+
+ @Override
+ public void run() {
+ while (running) {
+ try {
+ semaphore.acquire();
+ semaphore.drainPermits();
+ if (running) {
+ autoDrawable.display();
+ }
+ } catch (InterruptedException e) {
+ if (running) {
+ Thread.currentThread().interrupt();
+ }
+ break;
+ } catch (GLException e) {
+ if (running) {
+ throw e;
+ }
+ break;
+ }
+ }
+ }
+ }
+}
diff --git a/modules/scirenderer/src/org/scilab/forge/scirenderer/implementation/jogl/JoGLCanvasFactory.java b/modules/scirenderer/src/org/scilab/forge/scirenderer/implementation/jogl/JoGLCanvasFactory.java
new file mode 100755
index 000000000..f82ae9208
--- /dev/null
+++ b/modules/scirenderer/src/org/scilab/forge/scirenderer/implementation/jogl/JoGLCanvasFactory.java
@@ -0,0 +1,49 @@
+/*
+ * Scilab ( http://www.scilab.org/ ) - This file is part of Scilab
+ * Copyright (C) 2009-2011 - DIGITEO - Pierre Lando
+ *
+ * This file must be used under the terms of the CeCILL.
+ * This source file is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at
+ * http://www.cecill.info/licences/Licence_CeCILL_V2.1-en.txt
+ */
+
+package org.scilab.forge.scirenderer.implementation.jogl;
+
+import org.scilab.forge.scirenderer.Canvas;
+
+import javax.media.opengl.GLAutoDrawable;
+
+/**
+ * @author Pierre Lando
+ */
+public final class JoGLCanvasFactory {
+
+ /**
+ * Private constructor.
+ * This is an utility class.
+ */
+ private JoGLCanvasFactory() {
+
+ }
+
+ /**
+ * Create a canvas from an auto drawable object.
+ * @param autoDrawable the auto drawable object.
+ * @return a canvas based on the given auto drawable object.
+ */
+ public static Canvas createCanvas(final GLAutoDrawable autoDrawable) {
+ return new JoGLCanvas(autoDrawable);
+ }
+
+ /**
+ * Create a canvas for an offscreen rendering.
+ * @param width the width
+ * @param height the height
+ * @return a canvas.
+ */
+ public static Canvas createCanvas(final int width, final int height) {
+ return new JoGLCanvas(width, height);
+ }
+}
diff --git a/modules/scirenderer/src/org/scilab/forge/scirenderer/implementation/jogl/JoGLCapacity.java b/modules/scirenderer/src/org/scilab/forge/scirenderer/implementation/jogl/JoGLCapacity.java
new file mode 100755
index 000000000..e27be411f
--- /dev/null
+++ b/modules/scirenderer/src/org/scilab/forge/scirenderer/implementation/jogl/JoGLCapacity.java
@@ -0,0 +1,104 @@
+/*
+ * Scilab ( http://www.scilab.org/ ) - This file is part of Scilab
+ * Copyright (C) 2009-2011 - DIGITEO - Pierre Lando
+ *
+ * This file must be used under the terms of the CeCILL.
+ * This source file is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at
+ * http://www.cecill.info/licences/Licence_CeCILL_V2.1-en.txt
+ */
+
+package org.scilab.forge.scirenderer.implementation.jogl;
+
+import javax.media.opengl.GL2;
+
+/**
+ * This class store current OpenGl context capacity.
+ *
+ * @author Pierre Lando
+ */
+public class JoGLCapacity {
+
+ /** The actual aliased point size range. */
+ private final float[] aliasedPointSizeRange = new float[] {0, 0};
+
+ /** The actual light number. */
+ private final int[] lightNumber = new int[] {8};
+
+ /** The actual light number. */
+ private final int[] clippingPlaneNumber = new int[] {6};
+
+ /** Maximum texture size. */
+ private final int[] textureSize = new int[] {64};
+
+ /** Accumulation buffer presence */
+ private boolean accumulationBufferPresent = false;
+
+ /** ABGR extension */
+ private boolean hasABGRExtension = false;
+
+ /**
+ * Default constructor.
+ * The constructor is package because, only {@link JoGLDrawingTools} use this class.
+ */
+ JoGLCapacity() {
+ }
+
+ /**
+ * Reset the OpenGl capacity from the given context.
+ * @param gl the given OpenGl context.
+ */
+ void glReload(GL2 gl) {
+ gl.glGetFloatv(GL2.GL_ALIASED_POINT_SIZE_RANGE, aliasedPointSizeRange, 0);
+ gl.glGetIntegerv(GL2.GL_MAX_CLIP_PLANES, clippingPlaneNumber, 0);
+ gl.glGetIntegerv(GL2.GL_MAX_LIGHTS, lightNumber, 0);
+ gl.glGetIntegerv(GL2.GL_MAX_TEXTURE_SIZE, textureSize, 0);
+
+ int[] nbAccumulationBits = {0, 0, 0};
+ gl.glGetIntegerv(GL2.GL_ACCUM_RED_BITS, nbAccumulationBits, 0);
+ gl.glGetIntegerv(GL2.GL_ACCUM_GREEN_BITS, nbAccumulationBits, 1);
+ gl.glGetIntegerv(GL2.GL_ACCUM_BLUE_BITS, nbAccumulationBits, 2);
+ if (nbAccumulationBits[0] == 0 || nbAccumulationBits[1] == 0 || nbAccumulationBits[2] == 0) {
+ // accumulation buffers not there
+ accumulationBufferPresent = false;
+ } else {
+ accumulationBufferPresent = true;
+ }
+
+ hasABGRExtension = gl.isExtensionAvailable("GL_EXT_abgr");
+ }
+
+ /**
+ * Return the aliased point size range.
+ * The returned array had two elements.
+ * @return the aliased point size range.
+ */
+ public float[] getAliasedPointSizeRange() {
+ return aliasedPointSizeRange.clone();
+ }
+
+ /**
+ * Return the number of available light.
+ * @return the number of available light.
+ */
+ public int getLightNumber() {
+ return lightNumber[0];
+ }
+
+ public int getClippingPlaneNumber() {
+ return clippingPlaneNumber[0];
+ }
+
+ public int getMaximumTextureSize() {
+ return textureSize[0];
+ }
+
+ public boolean isAccumulationBufferPresent() {
+ return accumulationBufferPresent;
+ }
+
+ public boolean isABRExtensionPresent() {
+ return hasABGRExtension;
+ }
+}
diff --git a/modules/scirenderer/src/org/scilab/forge/scirenderer/implementation/jogl/JoGLDrawingTools.java b/modules/scirenderer/src/org/scilab/forge/scirenderer/implementation/jogl/JoGLDrawingTools.java
new file mode 100755
index 000000000..d7b34d3e5
--- /dev/null
+++ b/modules/scirenderer/src/org/scilab/forge/scirenderer/implementation/jogl/JoGLDrawingTools.java
@@ -0,0 +1,188 @@
+/*
+ * Scilab ( http://www.scilab.org/ ) - This file is part of Scilab
+ * Copyright (C) 2009-2011 - DIGITEO - Pierre Lando
+ *
+ * This file must be used under the terms of the CeCILL.
+ * This source file is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at
+ * http://www.cecill.info/licences/Licence_CeCILL_V2.1-en.txt
+ */
+
+package org.scilab.forge.scirenderer.implementation.jogl;
+
+import org.scilab.forge.scirenderer.DrawingTools;
+import org.scilab.forge.scirenderer.SciRendererException;
+import org.scilab.forge.scirenderer.buffers.ElementsBuffer;
+import org.scilab.forge.scirenderer.clipping.ClippingManager;
+import org.scilab.forge.scirenderer.implementation.jogl.clipping.JoGLClippingManager;
+import org.scilab.forge.scirenderer.implementation.jogl.drawer.JoGLShapeDrawer;
+import org.scilab.forge.scirenderer.implementation.jogl.lightning.JoGLLightManager;
+import org.scilab.forge.scirenderer.lightning.LightManager;
+import org.scilab.forge.scirenderer.renderer.Renderer;
+import org.scilab.forge.scirenderer.shapes.appearance.Appearance;
+import org.scilab.forge.scirenderer.shapes.appearance.Color;
+import org.scilab.forge.scirenderer.shapes.geometry.Geometry;
+import org.scilab.forge.scirenderer.texture.AnchorPosition;
+import org.scilab.forge.scirenderer.texture.Texture;
+import org.scilab.forge.scirenderer.tranformations.TransformationManager;
+import org.scilab.forge.scirenderer.tranformations.TransformationManagerImpl;
+import org.scilab.forge.scirenderer.tranformations.TransformationManagerListener;
+import org.scilab.forge.scirenderer.tranformations.Vector3d;
+
+import javax.media.opengl.GL2;
+
+/**
+ *
+ * JoGl implementation of the DrawingTools.
+ *
+ * @author Pierre Lando
+ */
+public class JoGLDrawingTools implements DrawingTools {
+
+ private final JoGLCapacity capacity = new JoGLCapacity();
+ private final TransformationManager transformationManager;
+ private final JoGLLightManager lightManager;
+ private final JoGLClippingManager clippingManager;
+ private final JoGLCanvas canvas;
+ private GL2 gl;
+
+ /**
+ * Default constructor.
+ * @param canvas the canvas where this drawing tools live.
+ */
+ JoGLDrawingTools(JoGLCanvas canvas) {
+ this.transformationManager = new TransformationManagerImpl(canvas);
+ this.lightManager = new JoGLLightManager(this);
+ this.clippingManager = new JoGLClippingManager(this);
+
+ this.canvas = canvas;
+
+ transformationManager.addListener(new TransformationManagerListener() {
+ @Override
+ public void transformationChanged(TransformationManager transformationManager) {
+ gl.glMatrixMode(GL2.GL_MODELVIEW);
+ if (transformationManager.isUsingSceneCoordinate()) {
+ gl.glLoadMatrixd(transformationManager.getTransformation().getMatrix(), 0);
+ } else {
+ gl.glLoadMatrixd(transformationManager.getWindowTransformation().getMatrix(), 0);
+ }
+ }
+ });
+ }
+
+ /**
+ * Synchronise to the given OpenGl context.
+ * @param gl the OpenGL context.
+ */
+ void glSynchronize(GL2 gl) {
+ this.gl = gl;
+ transformationManager.reset();
+ capacity.glReload(gl);
+ lightManager.reload();
+ clippingManager.reload();
+ }
+
+ @Override
+ public JoGLCanvas getCanvas() {
+ return canvas;
+ }
+
+ /**
+ * Return the OpenGl context.
+ * @return the OpenGl context.
+ */
+ public GL2 getGl() {
+ return gl;
+ }
+
+ /**
+ * Return the OpenGl capacity of this canvas.
+ * @return the OpenGl capacity of this canvas.
+ */
+ public JoGLCapacity getGLCapacity() {
+ return capacity;
+ }
+
+ @Override
+ public TransformationManager getTransformationManager() {
+ return transformationManager;
+ }
+
+ @Override
+ public LightManager getLightManager() {
+ return lightManager;
+ }
+
+ @Override
+ public ClippingManager getClippingManager() {
+ return clippingManager;
+ }
+
+ @Override
+ public void clear(Color color) {
+ gl.glClearColor(color.getRedAsFloat(), color.getGreenAsFloat(), color.getBlueAsFloat(), 1.f);
+ gl.glClear(GL2.GL_COLOR_BUFFER_BIT);
+ }
+
+ @Override
+ public void clear(java.awt.Color color) {
+ float[] colorData = color.getRGBColorComponents(null);
+ gl.glClearColor(colorData[0], colorData[1], colorData[2], 1f);
+ gl.glClear(GL2.GL_COLOR_BUFFER_BIT);
+ }
+
+ @Override
+ public void clearDepthBuffer() {
+ gl.glClear(GL2.GL_DEPTH_BUFFER_BIT);
+ }
+
+ @Override
+ public void draw(Renderer renderer) {
+ canvas.getRendererManager().draw(this, renderer);
+ }
+
+ @Override
+ public void draw(Geometry geometry) throws SciRendererException {
+ JoGLShapeDrawer.getDrawer().draw(this, geometry, Appearance.getDefault());
+ }
+
+ @Override
+ public void draw(Geometry geometry, Appearance appearance) throws SciRendererException {
+ JoGLShapeDrawer.getDrawer().draw(this, geometry, appearance);
+ }
+
+ @Override
+ public void draw(Texture texture) throws SciRendererException {
+ canvas.getTextureManager().draw(this, texture);
+ }
+
+ @Override
+ public void draw(Texture texture, AnchorPosition anchor, ElementsBuffer positions) throws SciRendererException {
+ canvas.getTextureManager().draw(this, texture, anchor, positions, 0, 1, 0);
+ }
+
+ @Override
+ public void draw(Texture texture, AnchorPosition anchor, ElementsBuffer positions, int offset, int stride, double rotationAngle) throws SciRendererException {
+ canvas.getTextureManager().draw(this, texture, anchor, positions, offset, stride, rotationAngle);
+ }
+
+ @Override
+ public void draw(Texture texture, AnchorPosition anchor, Vector3d position) throws SciRendererException {
+ canvas.getTextureManager().draw(this, texture, anchor, position, 0);
+ }
+
+ @Override
+ public void draw(Texture texture, AnchorPosition anchor, Vector3d position, double rotationAngle) throws SciRendererException {
+ canvas.getTextureManager().draw(this, texture, anchor, position, rotationAngle);
+ }
+
+ /**
+ * Bind the given texture to the OpenGl context.
+ * @param texture the given texture.
+ * @throws SciRendererException is thrown if the texture is invalid.
+ */
+ public void bind(Texture texture) throws SciRendererException {
+ canvas.getTextureManager().bind(this, texture);
+ }
+}
diff --git a/modules/scirenderer/src/org/scilab/forge/scirenderer/implementation/jogl/JoGLParameters.java b/modules/scirenderer/src/org/scilab/forge/scirenderer/implementation/jogl/JoGLParameters.java
new file mode 100755
index 000000000..86ab16b5f
--- /dev/null
+++ b/modules/scirenderer/src/org/scilab/forge/scirenderer/implementation/jogl/JoGLParameters.java
@@ -0,0 +1,65 @@
+/*
+ * Scilab ( http://www.scilab.org/ ) - This file is part of Scilab
+ * Copyright (C) 2009-2011 - DIGITEO - Pierre Lando
+ *
+ * This file must be used under the terms of the CeCILL.
+ * This source file is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at
+ * http://www.cecill.info/licences/Licence_CeCILL_V2.1-en.txt
+ */
+
+package org.scilab.forge.scirenderer.implementation.jogl;
+
+import javax.media.opengl.GL;
+import javax.media.opengl.glu.GLU;
+
+/**
+ * @author Pierre Lando
+ */
+public class JoGLParameters {
+
+ private static final boolean USE_DISPLAY_LIST = false;
+ private static final boolean USE_POINT_SPRITE = true;
+ private static Boolean USE_VBO;
+
+ /**
+ * Default constructor.
+ * It's package : only JoGLCanvas need this kind of object.
+ */
+ JoGLParameters() {
+ }
+
+ /**
+ * Use display list.
+ * @return true if use display list.
+ */
+ public boolean useDisplayList() {
+ return USE_DISPLAY_LIST;
+ }
+
+ /**
+ * Use VBO.
+ * @return true if use VBO.
+ */
+ public boolean useVBO() {
+ if (USE_VBO == null) {
+ GL gl = GLU.getCurrentGL();
+ USE_VBO = gl.isExtensionAvailable("GL_ARB_vertex_buffer_object")
+ && gl.isFunctionAvailable("glBindBufferARB")
+ && gl.isFunctionAvailable("glGenBuffersARB")
+ && gl.isFunctionAvailable("glBufferDataARB")
+ && gl.isFunctionAvailable("glDeleteBuffersARB");
+ }
+
+ return USE_VBO;
+ }
+
+ /**
+ * Use point sprite.
+ * @return true if use point sprite.
+ */
+ public boolean usePointSprite() {
+ return USE_POINT_SPRITE;
+ }
+}
diff --git a/modules/scirenderer/src/org/scilab/forge/scirenderer/implementation/jogl/buffers/JoGLBuffersManager.java b/modules/scirenderer/src/org/scilab/forge/scirenderer/implementation/jogl/buffers/JoGLBuffersManager.java
new file mode 100755
index 000000000..25a1c1bee
--- /dev/null
+++ b/modules/scirenderer/src/org/scilab/forge/scirenderer/implementation/jogl/buffers/JoGLBuffersManager.java
@@ -0,0 +1,226 @@
+/*
+ * Scilab ( http://www.scilab.org/ ) - This file is part of Scilab
+ * Copyright (C) 2009-2011 - DIGITEO - Pierre Lando
+ *
+ * This file must be used under the terms of the CeCILL.
+ * This source file is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at
+ * http://www.cecill.info/licences/Licence_CeCILL_V2.1-en.txt
+ */
+
+package org.scilab.forge.scirenderer.implementation.jogl.buffers;
+
+import org.scilab.forge.scirenderer.buffers.BuffersManager;
+import org.scilab.forge.scirenderer.buffers.DataBuffer;
+import org.scilab.forge.scirenderer.buffers.ElementsBuffer;
+import org.scilab.forge.scirenderer.buffers.IndicesBuffer;
+
+import javax.media.opengl.GL2;
+import java.util.Collection;
+import java.util.HashSet;
+import java.util.Set;
+import java.util.Stack;
+
+/**
+ * @author Pierre Lando
+ */
+public final class JoGLBuffersManager implements BuffersManager {
+
+ /**
+ * Set off current buffers.
+ */
+ private final Set<JoGLDataBuffer> buffers = new HashSet<JoGLDataBuffer>();
+
+ /**
+ * Set of dead buffers.
+ */
+ private final Stack<JoGLDataBuffer> deadBuffers = new Stack<JoGLDataBuffer>();
+
+ /**
+ * Default constructor.
+ */
+ public JoGLBuffersManager() {
+ }
+
+ @Override
+ public synchronized ElementsBuffer createElementsBuffer() {
+ JoGLElementsBuffer newBuffer = new JoGLElementsBuffer();
+ buffers.add(newBuffer);
+ return newBuffer;
+ }
+
+ @Override
+ public synchronized IndicesBuffer createIndicesBuffer() {
+ JoGLIndicesBuffer newBuffer = new JoGLIndicesBuffer();
+ buffers.add(newBuffer);
+ return newBuffer;
+ }
+
+ @Override
+ public synchronized void dispose(DataBuffer buffer) {
+ JoGLDataBuffer localBuffer = getLocalBuffer(buffer);
+ if (localBuffer != null) {
+ buffers.remove(localBuffer);
+ localBuffer.clear();
+ deadBuffers.push(localBuffer);
+ }
+ }
+
+ @Override
+ public synchronized void dispose(Collection <? extends DataBuffer > buffers) {
+ for (DataBuffer buffer : buffers) {
+ dispose(buffer);
+ }
+ }
+
+ /**
+ * Called when previous OpenGl context is gone.
+ */
+ public synchronized void glReload() {
+ for (JoGLDataBuffer buffer : buffers) {
+ buffer.reload();
+ }
+ }
+
+ /**
+ * Called before rendering for synchronisation.
+ * Clean dead buffers.
+ * @param gl the OpenGl context.
+ */
+ public synchronized void glSynchronize(GL2 gl) {
+ int[] names = new int[deadBuffers.size()];
+ int i = 0;
+ while (!deadBuffers.isEmpty()) {
+ int n = deadBuffers.pop().disposeWithoutDelete(gl);
+ if (n != -1) {
+ names[i++] = n;
+ }
+ }
+
+ if (i != 0) {
+ gl.glDeleteBuffers(i, names, 0);
+ }
+ }
+
+ /**
+ * Bind the given buffer as vertex buffer.
+ * @param gl the OpenGl context where the buffer is bind.
+ * @param buffer the buffer to bind.
+ * @return the number of element actually bind.
+ */
+ public int bindVertexBuffer(GL2 gl, ElementsBuffer buffer) {
+ JoGLElementsBuffer localBuffer = getLocalElementsBuffer(buffer);
+ if (localBuffer != null) {
+ return localBuffer.bindAsVertexBuffer(gl);
+ } else {
+ return 0;
+ }
+ }
+
+ /**
+ * Bind the given buffer as normal buffer.
+ * @param gl the OpenGl context where the buffer is bind.
+ * @param buffer the buffer to bind.
+ * @return the number of element actually bind.
+ */
+ public int bindNormalsBuffer(GL2 gl, ElementsBuffer buffer) {
+ JoGLElementsBuffer localBuffer = getLocalElementsBuffer(buffer);
+ if (localBuffer != null) {
+ return localBuffer.bindAsNormalsBuffer(gl);
+ } else {
+ return 0;
+ }
+ }
+
+ /**
+ * Bind the given buffer as texture coordinate buffer.
+ * @param gl the OpenGl context where the buffer is bind.
+ * @param buffer the buffer to bind.
+ * @return the number of element actually bind.
+ */
+ public int bindTextureCoordinatesBuffer(GL2 gl, ElementsBuffer buffer) {
+ JoGLElementsBuffer localBuffer = getLocalElementsBuffer(buffer);
+ if (localBuffer != null) {
+ return localBuffer.bindAsTextureCoordinatesBuffer(gl);
+ } else {
+ return 0;
+ }
+ }
+
+ /**
+ * Bind the given buffer as color buffer.
+ * @param gl the OpenGl context where the buffer is bind.
+ * @param buffer the buffer to bind.
+ * @return the number of element actually bind.
+ */
+ public int bindColorsBuffer(GL2 gl, ElementsBuffer buffer) {
+ JoGLElementsBuffer localBuffer = getLocalElementsBuffer(buffer);
+ if (localBuffer != null) {
+ return localBuffer.bindAsColorsBuffer(gl);
+ } else {
+ return 0;
+ }
+ }
+
+ /**
+ * Bind the given buffer as indices buffer.
+ * @param gl the OpenGl context where the buffer is bind.
+ * @param buffer the buffer to bind.
+ * @return the number of element actually bind.
+ */
+ public int bindIndicesBuffer(GL2 gl, IndicesBuffer buffer) {
+ JoGLDataBuffer localBuffer = getLocalBuffer(buffer);
+ if (localBuffer != null) {
+ gl.glBindBuffer(GL2.GL_ELEMENT_ARRAY_BUFFER, localBuffer.getGlName(gl));
+ return buffer.getSize();
+ } else {
+ return 0;
+ }
+ }
+
+ /**
+ * This method check buffer to be from here.
+ * @param buffer the given buffer.
+ * @return the JoGL instance of the buffer.
+ */
+ private synchronized JoGLDataBuffer getLocalBuffer(DataBuffer buffer) {
+ if (buffer instanceof JoGLDataBuffer) {
+ JoGLDataBuffer localBuffer = (JoGLDataBuffer) buffer;
+ if (buffers.contains(localBuffer)) {
+ return localBuffer;
+ }
+ }
+ return null;
+ }
+
+ /**
+ * This method check buffer to be from here.
+ * @param buffer the given buffer.
+ * @return the JoGL instance of the buffer.
+ */
+ private synchronized JoGLIndicesBuffer getLocalIndicesBuffer(IndicesBuffer buffer) {
+ if (buffer instanceof JoGLIndicesBuffer) {
+ JoGLIndicesBuffer localBuffer = (JoGLIndicesBuffer) buffer;
+ if (buffers.contains(localBuffer)) {
+ return localBuffer;
+ }
+ }
+ return null;
+ }
+
+ /**
+ * This method check buffer to be from here.
+ * @param buffer the given buffer.
+ * @return the JoGL instance of the buffer.
+ */
+ private synchronized JoGLElementsBuffer getLocalElementsBuffer(ElementsBuffer buffer) {
+ if (buffer instanceof JoGLElementsBuffer) {
+ JoGLElementsBuffer localBuffer = (JoGLElementsBuffer) buffer;
+ if (buffers.contains(localBuffer)) {
+ return localBuffer;
+ }
+ }
+ return null;
+ }
+}
diff --git a/modules/scirenderer/src/org/scilab/forge/scirenderer/implementation/jogl/buffers/JoGLDataBuffer.java b/modules/scirenderer/src/org/scilab/forge/scirenderer/implementation/jogl/buffers/JoGLDataBuffer.java
new file mode 100755
index 000000000..0912785c7
--- /dev/null
+++ b/modules/scirenderer/src/org/scilab/forge/scirenderer/implementation/jogl/buffers/JoGLDataBuffer.java
@@ -0,0 +1,150 @@
+/*
+ * Scilab ( http://www.scilab.org/ ) - This file is part of Scilab
+ * Copyright (C) 2009-2011 - DIGITEO - Pierre Lando
+ *
+ * This file must be used under the terms of the CeCILL.
+ * This source file is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at
+ * http://www.cecill.info/licences/Licence_CeCILL_V2.1-en.txt
+ */
+
+package org.scilab.forge.scirenderer.implementation.jogl.buffers;
+
+import org.scilab.forge.scirenderer.buffers.DataBuffer;
+
+import javax.media.opengl.GL;
+import java.nio.Buffer;
+
+/**
+ * @author Pierre Lando
+ */
+public abstract class JoGLDataBuffer implements DataBuffer {
+
+ /**
+ * True if the data have been uploaded to OpenGl driver.
+ */
+ private boolean dataUploaded;
+
+ /**
+ * The OpenGl name for this buffer.
+ * - null : no name
+ * - an Integer : the name.
+ */
+ private Integer glName;
+
+ /**
+ * Default constructor.
+ * The constructor is package : only {@link JoGLBuffersManager} can instantiate this object.
+ */
+ JoGLDataBuffer() {
+ dataUploaded = false;
+ glName = null;
+ }
+
+ /**
+ * Called to reload a buffer.
+ */
+ public void reload() {
+ glName = null;
+ dataUploaded = false;
+ }
+
+ /**
+ * Called when it's time to kill this buffer.
+ * @param gl the OpenGl context.
+ */
+ public void dispose(GL gl) {
+ if ((glName != null) && gl.glIsBuffer(glName)) {
+ int[] t = new int[] {glName};
+ gl.glDeleteBuffers(1, t, 0);
+ glName = null;
+ dataUploaded = false;
+ }
+ }
+
+ /**
+ * Called when it's time to kill this buffer.
+ * The effective delete is done in JoGLBuffersManager::glSynchronize (to vectorize it).
+ * @param gl the OpenGl context.
+ */
+ public int disposeWithoutDelete(GL gl) {
+ if ((glName != null) && gl.glIsBuffer(glName)) {
+ int n = glName;
+ glName = null;
+ dataUploaded = false;
+
+ return n;
+ }
+
+ return -1;
+ }
+
+ /**
+ * Synchronize this buffer.
+ * @param gl the OpenGl context where synchronization is done.
+ */
+ protected void synchronize(GL gl) {
+ // Check the glName.
+ if ((glName == null) || !(gl.glIsBuffer(glName))) {
+ int[] t = new int[1];
+ gl.glGenBuffers(1, t, 0);
+ glName = t[0];
+ dataUploaded = false;
+ }
+
+ // Upload data to the OpenGl driver.
+ if (!dataUploaded) {
+ gl.glBindBuffer(getGLBindDestination(), glName);
+ gl.glBufferData(getGLBindDestination(), getByteSize(), getByteBuffer(), GL.GL_STATIC_DRAW);
+ gl.glBindBuffer(getGLBindDestination(), 0);
+ dataUploaded = true;
+ }
+ }
+
+ /**
+ * Return the data uploaded status.
+ * @return the data uploaded status.
+ */
+ protected boolean isDataUploaded() {
+ return dataUploaded;
+ }
+
+ /**
+ * Set the data uploaded status.
+ * @param dataUploaded the new data uploaded status.
+ */
+ protected void setDataUploaded(boolean dataUploaded) {
+ this.dataUploaded = dataUploaded;
+ }
+
+ /**
+ * Return the OpenGl name of this buffer.
+ * @param gl the OpenGl context.
+ * @return the OpenGl name of this buffer.
+ */
+ protected Integer getGlName(GL gl) {
+ synchronize(gl);
+ return glName;
+ }
+
+ /**
+ * Return the data as byte buffer.
+ * @return the data as byte buffer.
+ */
+ protected abstract Buffer getByteBuffer();
+
+ /**
+ * Return the OpenGl bind destination.
+ * @return the OpenGl bind destination.
+ */
+ protected abstract int getGLBindDestination();
+
+ /**
+ * Return the size of this buffer in byte.
+ * @return the size of this buffer in byte.
+ */
+ public abstract int getByteSize();
+
+ public abstract void clear();
+}
diff --git a/modules/scirenderer/src/org/scilab/forge/scirenderer/implementation/jogl/buffers/JoGLElementsBuffer.java b/modules/scirenderer/src/org/scilab/forge/scirenderer/implementation/jogl/buffers/JoGLElementsBuffer.java
new file mode 100755
index 000000000..0824b710a
--- /dev/null
+++ b/modules/scirenderer/src/org/scilab/forge/scirenderer/implementation/jogl/buffers/JoGLElementsBuffer.java
@@ -0,0 +1,313 @@
+/*
+ * Scilab ( http://www.scilab.org/ ) - This file is part of Scilab
+ * Copyright (C) 2009-2011 - DIGITEO - Pierre Lando
+ *
+ * This file must be used under the terms of the CeCILL.
+ * This source file is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at
+ * http://www.cecill.info/licences/Licence_CeCILL_V2.1-en.txt
+ */
+
+package org.scilab.forge.scirenderer.implementation.jogl.buffers;
+
+import org.scilab.forge.scirenderer.buffers.ElementsBuffer;
+
+import javax.media.opengl.GL2;
+import java.nio.Buffer;
+import java.nio.FloatBuffer;
+
+/**
+ * @author Pierre Lando
+ */
+@SuppressWarnings(value = { "serial" })
+public class JoGLElementsBuffer extends JoGLDataBuffer implements ElementsBuffer {
+
+ /**
+ * The current size of one element.
+ */
+ public static final int ELEMENT_SIZE = 4;
+
+ /**
+ * The default vertex.
+ */
+ private static final float[] DEFAULT_VERTEX = new float[] {0, 0, 0, 1};
+
+ /**
+ * the data this buffer contain.
+ */
+ private FloatBuffer data;
+ private final Object mutex;
+
+ /**
+ * Default constructor.
+ * The constructor is package : only {@link JoGLBuffersManager} can instantiate this object.
+ */
+ JoGLElementsBuffer() {
+ mutex = new Object();
+ data = null;
+ }
+
+
+ @Override
+ public void setData(float[] newData, int elementSize) {
+ // Check the given vertex size
+ if ((elementSize < 1) || (elementSize > ELEMENT_SIZE)) {
+ throw new BadElementSizeException(elementSize, 1, ELEMENT_SIZE);
+ }
+
+ int verticesNumber = newData.length / elementSize;
+ //FloatBuffer buffer = BufferUtil.newFloatBuffer(ELEMENT_SIZE * verticesNumber);
+ FloatBuffer buffer = FloatBuffer.allocate(ELEMENT_SIZE * verticesNumber);
+ buffer.rewind();
+
+
+ // Fill buffer with given data.
+ // Missing coordinate are filled with the 'DEFAULT_VERTEX' ones.
+ int k = 0;
+ for (int i = 0; i < verticesNumber; i++) {
+ for (int j = 0; j < ELEMENT_SIZE; j++) {
+ if (j < elementSize) {
+ buffer.put(newData[k++]);
+ } else {
+ buffer.put(DEFAULT_VERTEX[j]);
+ }
+ }
+ }
+
+ buffer.rewind();
+ setData(buffer);
+ setDataUploaded(false);
+ }
+
+ @Override
+ public void setData(Float[] newData, int elementSize) {
+
+ // Check the given vertex size
+ if ((elementSize < 1) || (elementSize > ELEMENT_SIZE)) {
+ throw new BadElementSizeException(elementSize, 1, ELEMENT_SIZE);
+ }
+
+ int verticesNumber = newData.length / elementSize;
+ //FloatBuffer buffer = BufferUtil.newFloatBuffer(ELEMENT_SIZE * verticesNumber);
+ FloatBuffer buffer = FloatBuffer.allocate(ELEMENT_SIZE * verticesNumber);
+ buffer.rewind();
+
+
+ // Fill buffer with given data.
+ // Missing coordinate are filled with the 'DEFAULT_VERTEX' ones.
+ int k = 0;
+ for (int i = 0; i < verticesNumber; i++) {
+ for (int j = 0; j < ELEMENT_SIZE; j++) {
+ if (j < elementSize) {
+ buffer.put(newData[k++]);
+ } else {
+ buffer.put(DEFAULT_VERTEX[j]);
+ }
+ }
+ }
+
+ buffer.rewind();
+ setData(buffer);
+ setDataUploaded(false);
+ }
+
+ @Override
+ public void setData(FloatBuffer newData, int elementsSize) {
+ // Check the given vertex size
+ if ((elementsSize < 1) || (elementsSize > ELEMENT_SIZE)) {
+ throw new BadElementSizeException(elementsSize, 1, ELEMENT_SIZE);
+ }
+
+ if (elementsSize == 4) {
+ // No need to complete buffer.
+ if (newData != null) {
+ newData.rewind();
+ }
+ setData(newData);
+ setDataUploaded(false);
+ return;
+ }
+
+ int verticesNumber = newData.limit() / elementsSize;
+ //FloatBuffer buffer = BufferUtil.newFloatBuffer(ELEMENT_SIZE * verticesNumber);
+ FloatBuffer buffer = FloatBuffer.allocate(ELEMENT_SIZE * verticesNumber);
+ buffer.rewind();
+
+ // Fill buffer with given data.
+ // Missing coordinate are filled with the 'DEFAULT_VERTEX' ones.
+ newData.rewind();
+ for (int i = 0; i < verticesNumber; i++) {
+ for (int j = 0; j < ELEMENT_SIZE; j++) {
+ if (j < elementsSize) {
+ buffer.put(newData.get());
+ } else {
+ buffer.put(DEFAULT_VERTEX[j]);
+ }
+ }
+ }
+
+ buffer.rewind();
+ setData(buffer);
+ setDataUploaded(false);
+ }
+
+ @Override
+ public int getSize() {
+ synchronized (mutex) {
+ if (data == null) {
+ return 0;
+ } else {
+ return data.limit() / ELEMENT_SIZE;
+ }
+ }
+ }
+
+ @Override
+ public FloatBuffer getData() {
+ synchronized (mutex) {
+ if (data != null) {
+ return data;
+ } else {
+ return null;
+ }
+ }
+ }
+
+ @Override
+ public int getElementsSize() {
+ return ELEMENT_SIZE;
+ }
+
+ @Override
+ public int getByteSize() {
+ synchronized (mutex) {
+ if (data == null) {
+ return 0;
+ } else {
+ return data.limit() * (Float.SIZE / Byte.SIZE);
+ }
+ }
+ }
+
+ @Override
+ protected Buffer getByteBuffer() {
+ synchronized (mutex) {
+ if (data != null) {
+ data.rewind();
+ }
+ return data;
+ }
+ }
+
+ @Override
+ protected int getGLBindDestination() {
+ return GL2.GL_ARRAY_BUFFER;
+ }
+
+ public int bindAsVertexBuffer(GL2 gl) {
+ synchronized (mutex) {
+ if (getSize() != 0) {
+ gl.glEnableClientState(GL2.GL_VERTEX_ARRAY);
+ gl.glBindBuffer(GL2.GL_ARRAY_BUFFER, getGlName(gl));
+ gl.glVertexPointer(getElementsSize(), GL2.GL_FLOAT, 0, 0);
+ gl.glBindBuffer(GL2.GL_ARRAY_BUFFER, 0);
+ if (data == null) {
+ return 0;
+ } else {
+ return data.limit() * (Float.SIZE / Byte.SIZE);
+ }
+ } else {
+ return 0;
+ }
+ }
+ }
+
+ public int bindAsNormalsBuffer(GL2 gl) {
+ synchronized (mutex) {
+ if (getSize() != 0) {
+ gl.glEnableClientState(GL2.GL_NORMAL_ARRAY);
+ gl.glBindBuffer(GL2.GL_ARRAY_BUFFER, getGlName(gl));
+ gl.glNormalPointer(GL2.GL_FLOAT, getElementsSize() * Float.SIZE / Byte.SIZE, 0);
+ gl.glBindBuffer(GL2.GL_ARRAY_BUFFER, 0);
+ if (data == null) {
+ return 0;
+ } else {
+ return data.limit() * (Float.SIZE / Byte.SIZE);
+ }
+ } else {
+ return 0;
+ }
+ }
+ }
+
+ public int bindAsColorsBuffer(GL2 gl) {
+ synchronized (mutex) {
+ if (getSize() != 0) {
+ gl.glEnableClientState(GL2.GL_COLOR_ARRAY);
+ gl.glBindBuffer(GL2.GL_ARRAY_BUFFER, getGlName(gl));
+ gl.glColorPointer(getElementsSize(), GL2.GL_FLOAT, 0, 0);
+ gl.glBindBuffer(GL2.GL_ARRAY_BUFFER, 0);
+ if (data == null) {
+ return 0;
+ } else {
+ return data.limit() * (Float.SIZE / Byte.SIZE);
+ }
+ } else {
+ return 0;
+ }
+ }
+ }
+
+ public int bindAsTextureCoordinatesBuffer(GL2 gl) {
+ synchronized (mutex) {
+ if (getSize() != 0) {
+ gl.glEnableClientState(GL2.GL_TEXTURE_COORD_ARRAY);
+ gl.glBindBuffer(GL2.GL_ARRAY_BUFFER, getGlName(gl));
+ gl.glTexCoordPointer(getElementsSize(), GL2.GL_FLOAT, 0, 0);
+ gl.glBindBuffer(GL2.GL_ARRAY_BUFFER, 0);
+ if (data == null) {
+ return 0;
+ } else {
+ return data.limit() * (Float.SIZE / Byte.SIZE);
+ }
+ } else {
+ return 0;
+ }
+ }
+ }
+
+ /**
+ * Really set the data.
+ * @param data the new data.
+ */
+ private void setData(FloatBuffer data) {
+ synchronized (mutex) {
+ this.data = data;
+ }
+ }
+
+ /**
+ * A specific runtime exception for bad elements size.
+ */
+ private static class BadElementSizeException extends RuntimeException {
+
+ /**
+ * Default constructor.
+ * @param size the size given for elements.
+ * @param min the minimum possible size.
+ * @param max the upper bound of possible size (excluded of possible size).
+ */
+ public BadElementSizeException(int size, int min, int max) {
+ super("Bad vertex elements size : " + size + ". Should be in [" + min + ", " + (max - 1) + "]");
+ }
+ }
+
+ @Override
+ public void clear() {
+ if (data != null) {
+ data.clear();
+ }
+ data = null;
+ }
+}
diff --git a/modules/scirenderer/src/org/scilab/forge/scirenderer/implementation/jogl/buffers/JoGLIndicesBuffer.java b/modules/scirenderer/src/org/scilab/forge/scirenderer/implementation/jogl/buffers/JoGLIndicesBuffer.java
new file mode 100755
index 000000000..a6678c2bf
--- /dev/null
+++ b/modules/scirenderer/src/org/scilab/forge/scirenderer/implementation/jogl/buffers/JoGLIndicesBuffer.java
@@ -0,0 +1,116 @@
+/*
+ * Scilab ( http://www.scilab.org/ ) - This file is part of Scilab
+ * Copyright (C) 2009-2011 - DIGITEO - Pierre Lando
+ *
+ * This file must be used under the terms of the CeCILL.
+ * This source file is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at
+ * http://www.cecill.info/licences/Licence_CeCILL_V2.1-en.txt
+ */
+
+package org.scilab.forge.scirenderer.implementation.jogl.buffers;
+
+import org.scilab.forge.scirenderer.buffers.IndicesBuffer;
+
+import javax.media.opengl.GL;
+import java.nio.Buffer;
+import java.nio.IntBuffer;
+import java.util.Collection;
+
+/**
+ * @author Pierre Lando
+ */
+public class JoGLIndicesBuffer extends JoGLDataBuffer implements IndicesBuffer {
+
+ /**
+ * the data this buffer contain.
+ */
+ private IntBuffer data;
+
+ /**
+ * Default constructor.
+ * The constructor is package : only {@link JoGLBuffersManager} can instantiate this object.
+ */
+ JoGLIndicesBuffer() {
+ data = null;
+ }
+
+
+ @Override
+ public void setData(int[] indices) {
+ //IntBuffer buffer = BufferUtil.newIntBuffer(indices.length);
+ IntBuffer buffer = IntBuffer.allocate(indices.length);
+ buffer.rewind();
+ buffer.put(indices);
+ buffer.rewind();
+ this.data = buffer;
+ setDataUploaded(false);
+ }
+
+ @Override
+ public void setData(Collection<Integer> indices) {
+ IntBuffer buffer = IntBuffer.allocate(indices.size());
+ buffer.rewind();
+ for (int index : indices) {
+ buffer.put(index);
+ }
+ buffer.rewind();
+ this.data = buffer;
+ setDataUploaded(false);
+ }
+
+ @Override
+ public void setData(IntBuffer indexBuffer) {
+ //IntBuffer buffer = BufferUtil.newIntBuffer(indexBuffer.limit());
+ IntBuffer buffer = IntBuffer.allocate(indexBuffer.limit());
+ buffer.rewind();
+ indexBuffer.rewind();
+ buffer.put(indexBuffer);
+ buffer.rewind();
+ indexBuffer.rewind();
+ this.data = buffer;
+ setDataUploaded(false);
+ }
+
+ @Override
+ public int getSize() {
+ if (data == null) {
+ return 0;
+ } else {
+ return data.limit();
+ }
+ }
+
+ @Override
+ public IntBuffer getData() {
+ return data.asReadOnlyBuffer();
+ }
+
+ @Override
+ public int getByteSize() {
+ if (data == null) {
+ return 0;
+ } else {
+ return data.limit() * (Integer.SIZE / Byte.SIZE);
+ }
+ }
+
+ @Override
+ protected Buffer getByteBuffer() {
+ if (data != null) {
+ data.rewind();
+ }
+ return data;
+ }
+
+ @Override
+ protected int getGLBindDestination() {
+ return GL.GL_ELEMENT_ARRAY_BUFFER;
+ }
+
+ public void clear() {
+ data.clear();
+ data = null;
+ }
+}
diff --git a/modules/scirenderer/src/org/scilab/forge/scirenderer/implementation/jogl/clipping/JoGLClippingManager.java b/modules/scirenderer/src/org/scilab/forge/scirenderer/implementation/jogl/clipping/JoGLClippingManager.java
new file mode 100755
index 000000000..48722c68a
--- /dev/null
+++ b/modules/scirenderer/src/org/scilab/forge/scirenderer/implementation/jogl/clipping/JoGLClippingManager.java
@@ -0,0 +1,78 @@
+/*
+ * Scilab ( http://www.scilab.org/ ) - This file is part of Scilab
+ * Copyright (C) 2009-2011 - DIGITEO - Pierre Lando
+ *
+ * This file must be used under the terms of the CeCILL.
+ * This source file is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at
+ * http://www.cecill.info/licences/Licence_CeCILL_V2.1-en.txt
+ */
+
+package org.scilab.forge.scirenderer.implementation.jogl.clipping;
+
+import org.scilab.forge.scirenderer.clipping.ClippingManager;
+import org.scilab.forge.scirenderer.clipping.ClippingPlane;
+import org.scilab.forge.scirenderer.implementation.jogl.JoGLDrawingTools;
+
+import javax.media.opengl.GL2;
+
+/**
+ * @author Pierre Lando
+ */
+public class JoGLClippingManager implements ClippingManager {
+
+ /**
+ * Used drawing tools.
+ */
+ private final JoGLDrawingTools drawingTools;
+
+ /**
+ * Clipping planes array.
+ */
+ private final JoGLClippingPlane[] clippingPlanes;
+
+ /**
+ * Default constructor.
+ * @param drawingTools used drawing tools.
+ */
+ public JoGLClippingManager(JoGLDrawingTools drawingTools) {
+ this.drawingTools = drawingTools;
+ this.clippingPlanes = new JoGLClippingPlane[getClippingPlaneNumber()];
+ }
+
+ @Override
+ public int getClippingPlaneNumber() {
+ return drawingTools.getGLCapacity().getClippingPlaneNumber();
+ }
+
+ @Override
+ public JoGLClippingPlane getClippingPlane(int i) {
+ if (i < 0 || i >= getClippingPlaneNumber()) {
+ return null;
+ } else {
+ if (clippingPlanes[i] == null) {
+ clippingPlanes[i] = new JoGLClippingPlane(drawingTools.getGl().getGL2(), i);
+ }
+ return clippingPlanes[i];
+ }
+ }
+
+ @Override
+ public void disableClipping() {
+ for (ClippingPlane clippingPlane : clippingPlanes) {
+ if (clippingPlane != null) {
+ clippingPlane.setEnable(false);
+ }
+ }
+ }
+
+ public void reload() {
+ GL2 gl = drawingTools.getGl().getGL2();
+ for (JoGLClippingPlane clippingPlane : clippingPlanes) {
+ if (clippingPlane != null) {
+ clippingPlane.reload(gl);
+ }
+ }
+ }
+}
diff --git a/modules/scirenderer/src/org/scilab/forge/scirenderer/implementation/jogl/clipping/JoGLClippingPlane.java b/modules/scirenderer/src/org/scilab/forge/scirenderer/implementation/jogl/clipping/JoGLClippingPlane.java
new file mode 100755
index 000000000..dc4361b65
--- /dev/null
+++ b/modules/scirenderer/src/org/scilab/forge/scirenderer/implementation/jogl/clipping/JoGLClippingPlane.java
@@ -0,0 +1,123 @@
+/*
+ * Scilab ( http://www.scilab.org/ ) - This file is part of Scilab
+ * Copyright (C) 2009-2011 - DIGITEO - Pierre Lando
+ *
+ * This file must be used under the terms of the CeCILL.
+ * This source file is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at
+ * http://www.cecill.info/licences/Licence_CeCILL_V2.1-en.txt
+ */
+
+package org.scilab.forge.scirenderer.implementation.jogl.clipping;
+
+import org.scilab.forge.scirenderer.clipping.ClippingPlane;
+import org.scilab.forge.scirenderer.implementation.jogl.utils.GLShortCuts;
+import org.scilab.forge.scirenderer.tranformations.Transformation;
+import org.scilab.forge.scirenderer.tranformations.TransformationFactory;
+import org.scilab.forge.scirenderer.tranformations.Vector4d;
+
+import javax.media.opengl.GL2;
+
+/**
+ * @author Pierre Lando
+ */
+public class JoGLClippingPlane implements ClippingPlane {
+
+ /**
+ * GL index of this clipping plane.
+ */
+ private final int index;
+
+ /**
+ * Current GL context.
+ */
+ private GL2 gl;
+
+ /**
+ * Clipping plane enabled status.
+ */
+ private boolean isEnable;
+
+ /**
+ * Clipping plane equation look like: {@code x*a + y*b + z*c + d = 0}.
+ * Where {@code equation} is {@code [a, b, c, d]}.
+ */
+ private Vector4d equation = new Vector4d(0, 0, 0, 0);
+ private Transformation transformation = TransformationFactory.getIdentity();
+
+ /**
+ * Default constructor.
+ * @param gl the OpenGl context.
+ * @param index the id of this clipping plane.
+ */
+ public JoGLClippingPlane(GL2 gl, int index) {
+ this.isEnable = false;
+ this.index = index;
+ reload(gl);
+ }
+
+ @Override
+ public boolean isEnable() {
+ return isEnable;
+ }
+
+ @Override
+ public void setEnable(boolean isEnable) {
+ this.isEnable = isEnable;
+ GLShortCuts.setEnable(gl, GL2.GL_CLIP_PLANE0 + getIndex(), isEnable);
+ }
+
+ @Override
+ public void setEquation(Vector4d v) {
+ equation = v;
+ setGLEquation();
+ }
+
+ @Override
+ public Vector4d getEquation() {
+ return equation;
+ }
+
+ @Override
+ public void setTransformation(Transformation transformation) {
+ this.transformation = transformation;
+ setGLEquation();
+ }
+
+ @Override
+ public Transformation getTransformation() {
+ return transformation;
+ }
+
+ @Override
+ public int getIndex() {
+ return index;
+ }
+
+ /**
+ * Set GL context and synchronise it.
+ * @param gl the current gl context.
+ */
+ void reload(GL2 gl) {
+ this.gl = gl;
+ GLShortCuts.setEnable(gl, GL2.GL_CLIP_PLANE0 + getIndex(), isEnable());
+ setGLEquation();
+ }
+
+ /**
+ * Set the GL equation.
+ */
+ private void setGLEquation() {
+ // We use global coordinate. So we need to load identity.
+ gl.glMatrixMode(GL2.GL_MODELVIEW);
+ gl.glPushMatrix();
+ if (transformation == null) {
+ gl.glLoadIdentity();
+ } else {
+ gl.glLoadMatrixd(transformation.getMatrix(), 0);
+ }
+ gl.glClipPlane(GL2.GL_CLIP_PLANE0 + getIndex(), equation.getData(), 0);
+ gl.glPopMatrix();
+ }
+}
diff --git a/modules/scirenderer/src/org/scilab/forge/scirenderer/implementation/jogl/drawer/JoGLShapeDrawer.java b/modules/scirenderer/src/org/scilab/forge/scirenderer/implementation/jogl/drawer/JoGLShapeDrawer.java
new file mode 100755
index 000000000..87f3099e8
--- /dev/null
+++ b/modules/scirenderer/src/org/scilab/forge/scirenderer/implementation/jogl/drawer/JoGLShapeDrawer.java
@@ -0,0 +1,420 @@
+/*
+ * Scilab ( http://www.scilab.org/ ) - This file is part of Scilab
+ * Copyright (C) 2009-2011 - DIGITEO - Pierre Lando
+ *
+ * This file must be used under the terms of the CeCILL.
+ * This source file is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at
+ * http://www.cecill.info/licences/Licence_CeCILL_V2.1-en.txt
+ */
+
+package org.scilab.forge.scirenderer.implementation.jogl.drawer;
+
+import org.scilab.forge.scirenderer.SciRendererException;
+import org.scilab.forge.scirenderer.buffers.IndicesBuffer;
+import org.scilab.forge.scirenderer.implementation.jogl.JoGLDrawingTools;
+import org.scilab.forge.scirenderer.implementation.jogl.buffers.JoGLBuffersManager;
+import org.scilab.forge.scirenderer.implementation.jogl.buffers.JoGLElementsBuffer;
+import org.scilab.forge.scirenderer.implementation.jogl.utils.GLShortCuts;
+import org.scilab.forge.scirenderer.shapes.appearance.Appearance;
+import org.scilab.forge.scirenderer.shapes.geometry.Geometry;
+import org.scilab.forge.scirenderer.texture.Texture;
+import org.scilab.forge.scirenderer.lightning.LightManager;
+import org.scilab.forge.scirenderer.shapes.appearance.Material;
+
+import javax.media.opengl.GL2;
+import java.nio.FloatBuffer;
+import java.nio.IntBuffer;
+
+/**
+ * Utility class for drawing shapes.
+ * @author Pierre Lando
+ */
+public final class JoGLShapeDrawer {
+
+ private static JoGLShapeDrawer drawer;
+
+ /**
+ * Private constructor : this is an utility class.
+ */
+ private JoGLShapeDrawer() {
+ }
+
+ /**
+ * Singleton getter.
+ * @return the unique {@link JoGLShapeDrawer}.
+ */
+ public static JoGLShapeDrawer getDrawer() {
+ if (drawer == null) {
+ drawer = new JoGLShapeDrawer();
+ }
+ return drawer;
+ }
+
+ /**
+ * Draw a given geometry with given appearance.
+ * @param drawingTools the drawing tools.
+ * @param geometry the geometry.
+ * @param appearance the appearance.
+ * @throws org.scilab.forge.scirenderer.SciRendererException if the draw is not possible.
+ */
+ public void draw(JoGLDrawingTools drawingTools, Geometry geometry, Appearance appearance) throws SciRendererException {
+ GL2 gl = drawingTools.getGl().getGL2();
+ gl.glFrontFace(GL2.GL_CCW);
+ switch (geometry.getFaceCullingMode()) {
+ case CW:
+ gl.glEnable(GL2.GL_CULL_FACE);
+ gl.glCullFace(GL2.GL_FRONT);
+ break;
+ case CCW:
+ gl.glEnable(GL2.GL_CULL_FACE);
+ gl.glCullFace(GL2.GL_BACK);
+ break;
+ case BOTH:
+ gl.glDisable(GL2.GL_CULL_FACE);
+ break;
+ default:
+ gl.glDisable(GL2.GL_CULL_FACE);
+ break;
+ }
+
+ if (drawingTools.getCanvas().getJoGLParameters().useVBO()) {
+ vboDrawing(drawingTools, geometry, appearance);
+ } else {
+ directDrawing(drawingTools, geometry, appearance);
+ }
+
+ GLShortCuts.useLineAppearance(gl, null);
+ gl.glDisable(GL2.GL_CULL_FACE);
+ }
+
+ /**
+ * Perform geometry drawing using VBO.
+ * @param drawingTools the drawing tools.
+ * @param geometry the geometry to draw.
+ * @param appearance the current appearance.
+ * @throws org.scilab.forge.scirenderer.SciRendererException if the draw is not possible.
+ */
+ private void vboDrawing(JoGLDrawingTools drawingTools, Geometry geometry, Appearance appearance) throws SciRendererException {
+ final GL2 gl = drawingTools.getGl().getGL2();
+ final JoGLBuffersManager buffersManager = drawingTools.getCanvas().getBuffersManager();
+ final Texture texture = appearance.getTexture();
+
+ int verticesNumber = buffersManager.bindVertexBuffer(gl, geometry.getVertices());
+ if (verticesNumber == 0) {
+ gl.glDisableClientState(GL2.GL_VERTEX_ARRAY);
+ return;
+ }
+
+ buffersManager.bindNormalsBuffer(gl, geometry.getNormals());
+
+ if (texture != null && geometry.getTextureCoordinates() != null) {
+ synchronized (texture) {
+ if (texture.isValid()) {
+ drawingTools.bind(texture);
+ buffersManager.bindTextureCoordinatesBuffer(gl, geometry.getTextureCoordinates());
+ }
+ }
+ } else {
+ buffersManager.bindColorsBuffer(gl, geometry.getColors());
+ }
+
+ // We use polygon offset for filled geometry if required.
+ if (geometry.getPolygonOffsetMode()) {
+ gl.glEnable(GL2.GL_POLYGON_OFFSET_FILL);
+ gl.glPolygonOffset(1, 1);
+ }
+
+ GLShortCuts.useColor(gl, appearance.getFillColor());
+
+ LightManager lm = drawingTools.getLightManager();
+ boolean lighting = lm.isLightningEnable();
+ if (lighting) {
+ lm.setMaterial(appearance.getMaterial());
+ gl.glEnable(GL2.GL_NORMALIZE);
+ }
+
+ IndicesBuffer indices = geometry.getIndices();
+ if (geometry.getFillDrawingMode() != Geometry.FillDrawingMode.NONE) {
+ if (indices != null) {
+ int indicesSize = buffersManager.bindIndicesBuffer(gl, indices);
+ if (indicesSize > 0) {
+ gl.glDrawElements(getGlMode(geometry.getFillDrawingMode()), indicesSize, GL2.GL_UNSIGNED_INT, 0);
+ gl.glBindBuffer(GL2.GL_ELEMENT_ARRAY_BUFFER, 0);
+ }
+ } else {
+ int count = geometry.getVertices().getSize();
+ if (count > 0) {
+ gl.glDrawArrays(getGlMode(geometry.getFillDrawingMode()), 0, count);
+ }
+ }
+ }
+
+ if (geometry.getPolygonOffsetMode()) {
+ gl.glDisable(GL2.GL_POLYGON_OFFSET_FILL);
+ }
+
+ gl.glDisableClientState(GL2.GL_COLOR_ARRAY);
+ gl.glDisableClientState(GL2.GL_NORMAL_ARRAY);
+ gl.glDisableClientState(GL2.GL_TEXTURE_COORD_ARRAY);
+ gl.glDisable(GL2.GL_TEXTURE_2D);
+ //disable lighting to draw lines
+ lm.setLightningEnable(false);
+ gl.glDisable(GL2.GL_NORMALIZE);
+
+ if (geometry.getLineDrawingMode() != Geometry.LineDrawingMode.NONE) {
+ if (appearance.getLineColor() != null || geometry.getColors() != null) {
+ GLShortCuts.useLineAppearance(gl, appearance);
+ if (appearance.getLineColor() == null) {
+ buffersManager.bindColorsBuffer(gl, geometry.getColors());
+ }
+
+ if (geometry.getWireIndices() != null) {
+ int edgesIndicesSize = buffersManager.bindIndicesBuffer(gl, geometry.getWireIndices());
+ if (edgesIndicesSize > 0) {
+ gl.glDrawElements(getGlMode(geometry.getLineDrawingMode()), edgesIndicesSize, GL2.GL_UNSIGNED_INT, 0);
+ gl.glBindBuffer(GL2.GL_ELEMENT_ARRAY_BUFFER, 0);
+ }
+ } else {
+ int count = geometry.getVertices().getSize();
+ if (count > 0) {
+ gl.glDrawArrays(getGlMode(geometry.getLineDrawingMode()), 0, count);
+ }
+ }
+
+ gl.glDisableClientState(GL2.GL_COLOR_ARRAY);
+ }
+ }
+
+ gl.glDisableClientState(GL2.GL_VERTEX_ARRAY);
+ lm.setLightningEnable(lighting);
+ }
+
+ /**
+ * Perform geometry drawing by direct OpenGl call.
+ * @param drawingTools the drawing tools.
+ * @param geometry the geometry to draw.
+ * @param appearance the used appearance.
+ * @throws org.scilab.forge.scirenderer.SciRendererException if the draw is not possible.
+ */
+ private void directDrawing(
+ JoGLDrawingTools drawingTools, Geometry geometry, Appearance appearance
+ ) throws SciRendererException {
+ final double sfactor;
+ final double tfactor;
+ final float[] fbuffer = new float[4];
+
+ GL2 gl = drawingTools.getGl().getGL2();
+ if (geometry.getVertices() == null) {
+ return;
+ }
+
+ FloatBuffer vertexBuffer = geometry.getVertices().getData();
+ IndicesBuffer indices = geometry.getIndices();
+
+ FloatBuffer colorBuffer;
+ if (geometry.getColors() != null) {
+ colorBuffer = geometry.getColors().getData();
+ } else {
+ colorBuffer = null;
+ }
+
+ FloatBuffer normalBuffer;
+ if (geometry.getNormals() != null) {
+ normalBuffer = geometry.getNormals().getData();
+ } else {
+ normalBuffer = null;
+ }
+
+ Texture texture = appearance.getTexture();
+ FloatBuffer textureCoordinatesBuffer;
+ if (texture != null && geometry.getTextureCoordinates() != null) {
+ synchronized (texture) {
+ drawingTools.bind(texture);
+ textureCoordinatesBuffer = geometry.getTextureCoordinates().getData();
+ sfactor = texture.getSScaleFactor();
+ tfactor = texture.getTScaleFactor();
+ }
+ } else {
+ textureCoordinatesBuffer = null;
+ sfactor = 1;
+ tfactor = 1;
+ }
+
+ final int elementsSize = JoGLElementsBuffer.ELEMENT_SIZE;
+
+ if (geometry.getPolygonOffsetMode()) {
+ gl.glEnable(GL2.GL_POLYGON_OFFSET_FILL);
+ gl.glPolygonOffset(1, 1);
+ }
+
+ LightManager lm = drawingTools.getLightManager();
+ boolean lighting = lm.isLightningEnable();
+ if (lighting) {
+ lm.setMaterial(appearance.getMaterial());
+ }
+
+ if (geometry.getFillDrawingMode() != Geometry.FillDrawingMode.NONE) {
+ GLShortCuts.useColor(gl, appearance.getFillColor());
+ gl.glBegin(getGlMode(geometry.getFillDrawingMode()));
+ if (indices != null) {
+ IntBuffer indicesBuffer = indices.getData();
+ indicesBuffer.rewind();
+ for (int i = 0; i < indicesBuffer.limit(); i++) {
+ int index = indicesBuffer.get(i);
+ if ((index * elementsSize) < vertexBuffer.limit()) {
+
+ if (colorBuffer != null) {
+ colorBuffer.position(index * elementsSize);
+ gl.glColor4fv(colorBuffer);
+ }
+
+ if (normalBuffer != null) {
+ normalBuffer.position(index * elementsSize);
+ gl.glNormal3fv(normalBuffer);
+ }
+
+ if (textureCoordinatesBuffer != null) {
+ textureCoordinatesBuffer.position(index * elementsSize);
+ textureCoordinatesBuffer.get(fbuffer);
+
+ gl.glTexCoord4f((float) (sfactor * fbuffer[0]), (float) (tfactor * fbuffer[1]), fbuffer[2], fbuffer[3]);
+ }
+
+ vertexBuffer.position(index * elementsSize);
+ gl.glVertex4fv(vertexBuffer);
+
+ }
+ }
+ } else {
+ vertexBuffer.rewind();
+
+ if (colorBuffer != null) {
+ colorBuffer.rewind();
+ }
+
+ if (normalBuffer != null) {
+ normalBuffer.rewind();
+ }
+
+ for (int i = 0; i < vertexBuffer.limit(); i += elementsSize) {
+ if (colorBuffer != null) {
+ colorBuffer.position(i);
+ gl.glColor4fv(colorBuffer);
+ }
+
+ if (normalBuffer != null) {
+ normalBuffer.position(i);
+ gl.glNormal3fv(normalBuffer);
+ }
+
+ if (textureCoordinatesBuffer != null) {
+ textureCoordinatesBuffer.position(i);
+ gl.glTexCoord4fv(textureCoordinatesBuffer);
+ }
+
+ vertexBuffer.position(i);
+ gl.glVertex4fv(vertexBuffer);
+ }
+ }
+ gl.glEnd();
+ }
+
+ if (geometry.getPolygonOffsetMode()) {
+ gl.glDisable(GL2.GL_POLYGON_OFFSET_FILL);
+ }
+
+ gl.glDisable(GL2.GL_TEXTURE_2D);
+ //disable lighting to draw lines
+ lm.setLightningEnable(false);
+
+ // Draw edges if any.
+ if (geometry.getLineDrawingMode() != Geometry.LineDrawingMode.NONE) {
+ GLShortCuts.useLineAppearance(gl, appearance);
+ if (appearance.getLineColor() != null) {
+ gl.glBegin(getGlMode(geometry.getLineDrawingMode()));
+ if (geometry.getWireIndices() != null) {
+ IntBuffer edgesIndicesBuffer = geometry.getWireIndices().getData();
+ edgesIndicesBuffer.rewind();
+ while (edgesIndicesBuffer.remaining() != 0) {
+ int index = edgesIndicesBuffer.get();
+ if ((index * elementsSize) < vertexBuffer.limit()) {
+ vertexBuffer.position(index * elementsSize);
+ gl.glVertex4fv(vertexBuffer);
+ }
+ }
+ } else {
+ for (int i = 0; i < vertexBuffer.limit(); i += elementsSize) {
+ vertexBuffer.position(i);
+ gl.glVertex4fv(vertexBuffer);
+ }
+ }
+ gl.glEnd();
+ } else if (colorBuffer != null) {
+ gl.glBegin(getGlMode(geometry.getLineDrawingMode()));
+ if (geometry.getWireIndices() != null) {
+ IntBuffer edgesIndicesBuffer = geometry.getWireIndices().getData();
+ edgesIndicesBuffer.rewind();
+ while (edgesIndicesBuffer.remaining() != 0) {
+ int index = edgesIndicesBuffer.get();
+ if ((index * elementsSize) < vertexBuffer.limit()) {
+ colorBuffer.position(index * elementsSize);
+ gl.glColor4fv(colorBuffer);
+
+ vertexBuffer.position(index * elementsSize);
+ gl.glVertex4fv(vertexBuffer);
+
+ }
+ }
+ } else {
+ for (int i = 0; i < vertexBuffer.limit(); i += elementsSize) {
+ colorBuffer.position(i);
+ vertexBuffer.position(i);
+ gl.glColor4fv(colorBuffer);
+ gl.glVertex4fv(vertexBuffer);
+ }
+ }
+ gl.glEnd();
+ }
+ }
+ lm.setLightningEnable(lighting);
+ }
+
+
+ /**
+ * Return the gl drawing mode corresponding to the given {@link Geometry.FillDrawingMode}.
+ * @param drawingMode the given drawing mode..
+ * @return the gl drawing mode corresponding to the given {@link Geometry.FillDrawingMode}.
+ */
+ private int getGlMode(Geometry.FillDrawingMode drawingMode) {
+ switch (drawingMode) {
+ case TRIANGLE_FAN:
+ return GL2.GL_TRIANGLE_FAN;
+ case TRIANGLE_STRIP:
+ return GL2.GL_TRIANGLE_STRIP;
+ case TRIANGLES:
+ return GL2.GL_TRIANGLES;
+ default:
+ return GL2.GL_TRIANGLES;
+ }
+ }
+
+ /**
+ * Return the gl drawing mode corresponding to the given {@link org.scilab.forge.scirenderer.shapes.geometry.Geometry.LineDrawingMode}
+ * @param drawingMode the given drawing mode.
+ * @return the gl drawing mode corresponding to the given {@link org.scilab.forge.scirenderer.shapes.geometry.Geometry.LineDrawingMode}
+ */
+ private int getGlMode(Geometry.LineDrawingMode drawingMode) {
+ switch (drawingMode) {
+ case SEGMENTS:
+ return GL2.GL_LINES;
+ case SEGMENTS_LOOP:
+ return GL2.GL_LINE_LOOP;
+ case SEGMENTS_STRIP:
+ return GL2.GL_LINE_STRIP;
+ default:
+ return GL2.GL_LINES;
+ }
+ }
+}
diff --git a/modules/scirenderer/src/org/scilab/forge/scirenderer/implementation/jogl/lightning/JoGLLight.java b/modules/scirenderer/src/org/scilab/forge/scirenderer/implementation/jogl/lightning/JoGLLight.java
new file mode 100755
index 000000000..2a99c4105
--- /dev/null
+++ b/modules/scirenderer/src/org/scilab/forge/scirenderer/implementation/jogl/lightning/JoGLLight.java
@@ -0,0 +1,188 @@
+/*
+ * Scilab ( http://www.scilab.org/ ) - This file is part of Scilab
+ * Copyright (C) 2009-2011 - DIGITEO - Pierre Lando
+ *
+ * This file must be used under the terms of the CeCILL.
+ * This source file is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at
+ * http://www.cecill.info/licences/Licence_CeCILL_V2.1-en.txt
+ */
+
+package org.scilab.forge.scirenderer.implementation.jogl.lightning;
+
+import javax.media.opengl.GL2;
+
+import org.scilab.forge.scirenderer.implementation.jogl.utils.GLShortCuts;
+import org.scilab.forge.scirenderer.lightning.Light;
+import org.scilab.forge.scirenderer.shapes.appearance.Color;
+import org.scilab.forge.scirenderer.tranformations.Vector3d;
+
+/**
+ * @author Pierre Lando
+ */
+public class JoGLLight implements Light {
+ private final int index;
+ private GL2 gl;
+ private boolean isEnable;
+ private Color ambientColor = new Color(0, 0, 0);
+ private Color diffuseColor = new Color(0, 0, 0);
+ private Color specularColor = new Color(0, 0, 0);
+ private Vector3d position = new Vector3d(0, 0, 0);
+ private Vector3d spotDirection = new Vector3d(0, 0, 1);
+ private Vector3d direction = new Vector3d(0, 0, 0);
+ private float spotAngle = 180;
+ private boolean isDirectional = false;
+
+ /**
+ * Default constructor.
+ * @param gl the gl context.
+ * @param index the light index.
+ */
+ public JoGLLight(GL2 gl, int index) {
+ this.gl = gl;
+ this.index = index;
+ }
+
+ /**
+ * Reload this light.
+ * @param gl the gl context.
+ */
+ public void reload(GL2 gl) {
+ this.gl = gl;
+
+ GLShortCuts.setEnable(gl, GL2.GL_LIGHT0 + index, isEnable);
+ gl.glLightfv(GL2.GL_LIGHT0 + index, GL2.GL_AMBIENT, ambientColor.getRGBComponents(null), 0);
+ gl.glLightfv(GL2.GL_LIGHT0 + index, GL2.GL_DIFFUSE, diffuseColor.getRGBComponents(null), 0);
+ gl.glLightfv(GL2.GL_LIGHT0 + index, GL2.GL_SPECULAR, specularColor.getRGBComponents(null), 0);
+ if (isDirectional) {
+ float[] pos = position.getDataAsFloatArray(4);
+ pos[3] = 0.0f;
+ pos[0] = -pos[0];
+ pos[1] = -pos[1];
+ pos[2] = -pos[2];
+ gl.glLightfv(GL2.GL_LIGHT0 + index, GL2.GL_POSITION, pos, 0);
+ } else {
+ float[] pos = position.getDataAsFloatArray(4);
+ pos[3] = 1.0f;
+ gl.glLightfv(GL2.GL_LIGHT0 + index, GL2.GL_POSITION, pos, 0);
+ }
+ gl.glLightfv(GL2.GL_LIGHT0 + index, GL2.GL_SPOT_DIRECTION, spotDirection.getDataAsFloatArray(4), 0);
+ }
+
+ @Override
+ public boolean isEnable() {
+ return isEnable;
+ }
+
+ @Override
+ public void setEnable(boolean enable) {
+ if (enable != isEnable) {
+ isEnable = enable;
+ GLShortCuts.setEnable(gl, GL2.GL_LIGHT0 + index, isEnable);
+ }
+ }
+
+ @Override
+ public Color getAmbientColor() {
+ return ambientColor;
+ }
+
+ @Override
+ public void setAmbientColor(Color color) {
+ if (color != null) {
+ ambientColor = color;
+ gl.glLightfv(GL2.GL_LIGHT0 + index, GL2.GL_AMBIENT, ambientColor.getRGBComponents(null), 0);
+ }
+ }
+
+ @Override
+ public Color getDiffuseColor() {
+ return diffuseColor;
+ }
+
+ @Override
+ public void setDiffuseColor(Color color) {
+ if (color != null) {
+ diffuseColor = color;
+ gl.glLightfv(GL2.GL_LIGHT0 + index, GL2.GL_DIFFUSE, diffuseColor.getRGBComponents(null), 0);
+ }
+ }
+
+ @Override
+ public Color getSpecularColor() {
+ return specularColor;
+ }
+
+ @Override
+ public void setSpecularColor(Color color) {
+ if (color != null) {
+ specularColor = color;
+ gl.glLightfv(GL2.GL_LIGHT0 + index, GL2.GL_SPECULAR, specularColor.getRGBComponents(null), 0);
+ }
+ }
+
+ @Override
+ public Vector3d getPosition() {
+ return position;
+ }
+
+ @Override
+ public void setPosition(Vector3d position) {
+ if (position != null) {
+ isDirectional = false;
+ this.position = position;
+ float[] pos = position.getDataAsFloatArray(4);
+ pos[3] = 1.0f;
+ gl.glLightfv(GL2.GL_LIGHT0 + index, GL2.GL_POSITION, pos, 0);
+ }
+ }
+
+ public Vector3d getDirection() {
+ return direction;
+ }
+
+ public void setDirection(Vector3d direction) {
+ if (direction != null) {
+ isDirectional = true;
+ this.direction = direction;
+ float[] dir = direction.getDataAsFloatArray(4);
+ dir[3] = 0.0f;
+ dir[0] = -dir[0];
+ dir[1] = -dir[1];
+ dir[2] = -dir[2];
+ gl.glLightfv(GL2.GL_LIGHT0 + index, GL2.GL_POSITION, dir, 0);
+ }
+ }
+
+ @Override
+ public Vector3d getSpotDirection() {
+ return spotDirection;
+ }
+
+ @Override
+ public void setSpotDirection(Vector3d spotDirection) {
+ if (spotDirection != null) {
+ this.spotDirection = spotDirection;
+ gl.glLightfv(GL2.GL_LIGHT0 + index, GL2.GL_SPOT_DIRECTION, spotDirection.getNormalized().getDataAsFloatArray(4), 0);
+ }
+ }
+
+ @Override
+ public float getSpotAngle() {
+ return spotAngle;
+ }
+
+ @Override
+ public void setSpotAngle(float angle) {
+ if (angle != spotAngle) {
+ spotAngle = angle;
+ gl.glLightf(GL2.GL_LIGHT0 + index, GL2.GL_SPOT_CUTOFF, spotAngle);
+ }
+ }
+
+ @Override
+ public int getIndex() {
+ return index;
+ }
+}
diff --git a/modules/scirenderer/src/org/scilab/forge/scirenderer/implementation/jogl/lightning/JoGLLightManager.java b/modules/scirenderer/src/org/scilab/forge/scirenderer/implementation/jogl/lightning/JoGLLightManager.java
new file mode 100755
index 000000000..4621f50fc
--- /dev/null
+++ b/modules/scirenderer/src/org/scilab/forge/scirenderer/implementation/jogl/lightning/JoGLLightManager.java
@@ -0,0 +1,114 @@
+/*
+ * Scilab ( http://www.scilab.org/ ) - This file is part of Scilab
+ * Copyright (C) 2009-2011 - DIGITEO - Pierre Lando
+ *
+ * This file must be used under the terms of the CeCILL.
+ * This source file is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at
+ * http://www.cecill.info/licences/Licence_CeCILL_V2.1-en.txt
+ */
+
+package org.scilab.forge.scirenderer.implementation.jogl.lightning;
+
+import org.scilab.forge.scirenderer.implementation.jogl.JoGLDrawingTools;
+import org.scilab.forge.scirenderer.implementation.jogl.utils.GLShortCuts;
+import org.scilab.forge.scirenderer.lightning.Light;
+import org.scilab.forge.scirenderer.lightning.LightManager;
+import org.scilab.forge.scirenderer.shapes.appearance.Material;
+
+import javax.media.opengl.GL2;
+
+/**
+ * JoGL implementation of {@link LightManager}
+ *
+ * @author Pierre Lando
+ */
+public class JoGLLightManager implements LightManager {
+
+ /**
+ * The drawing tools.
+ */
+ private final JoGLDrawingTools drawingTools;
+
+ /**
+ * The lights.
+ */
+ private final JoGLLight[] lights;
+
+ /**
+ * The current lightning status.
+ */
+ private boolean isLightningEnable = DEFAULT_LIGHTNING_STATUS;
+
+ /**
+ * Default constructor.
+ * @param drawingTools the drawing tools.
+ */
+ public JoGLLightManager(JoGLDrawingTools drawingTools) {
+ this.drawingTools = drawingTools;
+ lights = new JoGLLight[getLightNumber()];
+ }
+
+ @Override
+ public int getLightNumber() {
+ return drawingTools.getGLCapacity().getLightNumber();
+ }
+
+ @Override
+ public Light getLight(int i) {
+ if (i < 0 || i >= getLightNumber()) {
+ return null;
+ } else {
+ if (lights[i] == null) {
+ lights[i] = new JoGLLight(drawingTools.getGl(), i);
+ }
+ return lights[i];
+ }
+ }
+
+ @Override
+ public void setLightningEnable(boolean isLightningEnable) {
+ this.isLightningEnable = isLightningEnable;
+ GLShortCuts.setEnable(drawingTools.getGl().getGL2(), GL2.GL_LIGHTING, isLightningEnable);
+ }
+
+ @Override
+ public boolean isLightningEnable() {
+ return isLightningEnable;
+ }
+
+ @Override
+ public void setMaterial(Material material) {
+ if (material != null) {
+ GLShortCuts.setEnable(drawingTools.getGl().getGL2(), GL2.GL_COLOR_MATERIAL, material.isColorMaterialEnable());
+ float[] black = new float[] {0.0f, 0.0f, 0.0f, 1.0f};
+ drawingTools.getGl().glLightModelfv(GL2.GL_LIGHT_MODEL_AMBIENT, black, 0);
+ drawingTools.getGl().glLightModeli(GL2.GL_LIGHT_MODEL_LOCAL_VIEWER, GL2.GL_FALSE);
+ drawingTools.getGl().glLightModeli(GL2.GL_LIGHT_MODEL_TWO_SIDE, GL2.GL_TRUE);
+
+ if (material.isColorMaterialEnable()) {
+ drawingTools.getGl().glColorMaterial(GL2.GL_FRONT_AND_BACK, GL2.GL_AMBIENT_AND_DIFFUSE);
+ } else {
+ drawingTools.getGl().glMaterialfv(GL2.GL_FRONT_AND_BACK, GL2.GL_AMBIENT, material.getAmbientColor().getComponents(null), 0);
+ drawingTools.getGl().glMaterialfv(GL2.GL_FRONT_AND_BACK, GL2.GL_DIFFUSE, material.getDiffuseColor().getComponents(null), 0);
+ }
+ drawingTools.getGl().glMaterialfv(GL2.GL_FRONT_AND_BACK, GL2.GL_SPECULAR, material.getSpecularColor().getComponents(null), 0);
+ drawingTools.getGl().glMaterialf(GL2.GL_FRONT_AND_BACK, GL2.GL_SHININESS, material.getShininess());
+ float[] f = {0.0f, 0.0f, 0.0f, 0.0f};
+ drawingTools.getGl().glMaterialfv(GL2.GL_FRONT_AND_BACK, GL2.GL_EMISSION, f, 0);
+ }
+ }
+ /**
+ * Reload light.
+ */
+ public void reload() {
+ GL2 gl = drawingTools.getGl().getGL2();
+ GLShortCuts.setEnable(gl, GL2.GL_LIGHTING, isLightningEnable);
+ for (JoGLLight light : lights) {
+ if (light != null && light.isEnable()) {
+ light.reload(gl);
+ }
+ }
+ }
+}
diff --git a/modules/scirenderer/src/org/scilab/forge/scirenderer/implementation/jogl/picking/GLPickingManager.java b/modules/scirenderer/src/org/scilab/forge/scirenderer/implementation/jogl/picking/GLPickingManager.java
new file mode 100755
index 000000000..799c93eff
--- /dev/null
+++ b/modules/scirenderer/src/org/scilab/forge/scirenderer/implementation/jogl/picking/GLPickingManager.java
@@ -0,0 +1,85 @@
+/*
+ * Scilab ( http://www.scilab.org/ ) - This file is part of Scilab
+ * Copyright (C) 2009-2011 - DIGITEO - Pierre Lando
+ *
+ * This file must be used under the terms of the CeCILL.
+ * This source file is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at
+ * http://www.cecill.info/licences/Licence_CeCILL_V2.1-en.txt
+ */
+
+package org.scilab.forge.scirenderer.implementation.jogl.picking;
+
+import javax.media.opengl.GL;
+
+/**
+ * @author Pierre Lando
+ */
+public class GLPickingManager {
+
+ /**
+ * The last used unique color.
+ */
+ private UniqueColor uniqueColor;
+
+ /**
+ * Default constructor.
+ */
+ public GLPickingManager() {
+ }
+
+
+ /**
+ * This class make an unique color from an index.
+ */
+ private class UniqueColor {
+ private final int redSize;
+ private final int greenSize;
+ private final int blueSize;
+ private final GL gl;
+
+ /**
+ * Constructor.
+ * @param gl the used OpenGl context.
+ */
+ public UniqueColor(GL gl) {
+ this.gl = gl;
+ int[] colorBits = new int[3];
+ gl.glGetIntegerv(GL.GL_RED_BITS, colorBits, 0);
+ gl.glGetIntegerv(GL.GL_GREEN_BITS, colorBits, 1);
+ gl.glGetIntegerv(GL.GL_BLUE_BITS, colorBits, 2);
+
+ redSize = 1 << colorBits[0];
+ greenSize = 1 << colorBits[1];
+ blueSize = 1 << colorBits[2];
+ }
+
+ /**
+ * Set the color by index.
+ * @param index given index.
+ */
+ public void setColor(int index) {
+ int i = index;
+ float b = (i % blueSize) / (blueSize - 1f);
+ i = i >> blueSize;
+ float g = (i % greenSize) / (greenSize - 1f);
+ i = i >> greenSize;
+ float r = (i % redSize) / (redSize - 1f);
+
+ //gl.glColor3f(r, g, b);
+ gl.glClearColor(r, g, b, 0);
+ }
+
+ /**
+ * Get index from color.
+ * @param r red component of the color.
+ * @param g green component of the color.
+ * @param b blue component of the color.
+ * @return the index corresponding to the given color.
+ */
+ public int getIndex(float r, float g, float b) {
+ return (int) (((r * (redSize - 1f) + g) * (greenSize - 1f) + b) * (blueSize - 1f));
+ }
+ }
+}
diff --git a/modules/scirenderer/src/org/scilab/forge/scirenderer/implementation/jogl/picking/JoGLPickingManager.java b/modules/scirenderer/src/org/scilab/forge/scirenderer/implementation/jogl/picking/JoGLPickingManager.java
new file mode 100755
index 000000000..aed85219c
--- /dev/null
+++ b/modules/scirenderer/src/org/scilab/forge/scirenderer/implementation/jogl/picking/JoGLPickingManager.java
@@ -0,0 +1,57 @@
+/*
+ * Scilab ( http://www.scilab.org/ ) - This file is part of Scilab
+ * Copyright (C) 2009-2011 - DIGITEO - Pierre Lando
+ *
+ * This file must be used under the terms of the CeCILL.
+ * This source file is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at
+ * http://www.cecill.info/licences/Licence_CeCILL_V2.1-en.txt
+ */
+
+package org.scilab.forge.scirenderer.implementation.jogl.picking;
+
+import org.scilab.forge.scirenderer.implementation.jogl.JoGLCanvas;
+import org.scilab.forge.scirenderer.implementation.jogl.JoGLDrawingTools;
+import org.scilab.forge.scirenderer.picking.PickingManager;
+import org.scilab.forge.scirenderer.picking.PickingTask;
+import org.scilab.forge.scirenderer.picking.PickingTools;
+
+import java.util.Stack;
+
+/**
+ *
+ * JoGL implementation of {@link org.scilab.forge.scirenderer.picking.PickingManager}
+ *
+ * @author Pierre Lando
+ */
+public class JoGLPickingManager implements PickingManager {
+
+ private final Stack<PickingTask> stack = new Stack<PickingTask>();
+ private final JoGLCanvas canvas;
+
+ /**
+ * Default constructor.
+ * @param canvas the canvas where picking is performed.
+ */
+ public JoGLPickingManager(JoGLCanvas canvas) {
+ this.canvas = canvas;
+ }
+
+ @Override
+ public void addPickingTask(PickingTask pickingTask) {
+ stack.push(pickingTask);
+ canvas.redraw();
+ }
+
+ /**
+ * Ask to consume picking task with the given drawing tools.
+ * @param drawingTools the given drawing tools.
+ */
+ public void glConsume(JoGLDrawingTools drawingTools) {
+ PickingTools pickingTools = new JoGLPickingTools(drawingTools);
+ while (!stack.isEmpty()) {
+ stack.pop().perform(pickingTools);
+ }
+ }
+}
diff --git a/modules/scirenderer/src/org/scilab/forge/scirenderer/implementation/jogl/picking/JoGLPickingTools.java b/modules/scirenderer/src/org/scilab/forge/scirenderer/implementation/jogl/picking/JoGLPickingTools.java
new file mode 100755
index 000000000..dbb3dd768
--- /dev/null
+++ b/modules/scirenderer/src/org/scilab/forge/scirenderer/implementation/jogl/picking/JoGLPickingTools.java
@@ -0,0 +1,65 @@
+/*
+ * Scilab ( http://www.scilab.org/ ) - This file is part of Scilab
+ * Copyright (C) 2009-2011 - DIGITEO - Pierre Lando
+ *
+ * This file must be used under the terms of the CeCILL.
+ * This source file is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at
+ * http://www.cecill.info/licences/Licence_CeCILL_V2.1-en.txt
+ */
+
+package org.scilab.forge.scirenderer.implementation.jogl.picking;
+
+import org.scilab.forge.scirenderer.Canvas;
+import org.scilab.forge.scirenderer.implementation.jogl.JoGLDrawingTools;
+import org.scilab.forge.scirenderer.picking.PickingTools;
+import org.scilab.forge.scirenderer.tranformations.Vector3d;
+
+import javax.media.opengl.GL2;
+import java.awt.Point;
+import java.nio.FloatBuffer;
+
+/**
+ *
+ * JoGL implementation of {@link PickingTools}
+ *
+ * @author Pierre Lando
+ */
+public class JoGLPickingTools implements PickingTools {
+
+ private final JoGLDrawingTools drawingTools;
+
+ /**
+ * Default constructor.
+ * @param drawingTools the drawing tools to use.
+ */
+ public JoGLPickingTools(JoGLDrawingTools drawingTools) {
+ this.drawingTools = drawingTools;
+ }
+
+ @Override
+ public Vector3d getUnderlyingPoint(Point windowPosition) {
+ GL2 gl = drawingTools.getGl().getGL2();
+
+ int x = windowPosition.x;
+ int y = drawingTools.getCanvas().getHeight() - windowPosition.y - 1;
+ FloatBuffer buffer = FloatBuffer.allocate(1);
+
+ buffer.rewind();
+ gl.glReadPixels(x, y, 1, 1, GL2.GL_DEPTH_COMPONENT, GL2.GL_FLOAT, buffer);
+ buffer.rewind();
+ float vz = 2f * buffer.get() - 1;
+
+ float vx = 2f * x / drawingTools.getCanvas().getWidth() - 1f;
+ float vy = 2f * y / drawingTools.getCanvas().getHeight() - 1f;
+
+ return new Vector3d(vx, vy, vz);
+ }
+
+ @Override
+ public Canvas getCanvas() {
+ return drawingTools.getCanvas();
+ }
+
+}
diff --git a/modules/scirenderer/src/org/scilab/forge/scirenderer/implementation/jogl/renderer/JoGLRenderer.java b/modules/scirenderer/src/org/scilab/forge/scirenderer/implementation/jogl/renderer/JoGLRenderer.java
new file mode 100755
index 000000000..cc43ada64
--- /dev/null
+++ b/modules/scirenderer/src/org/scilab/forge/scirenderer/implementation/jogl/renderer/JoGLRenderer.java
@@ -0,0 +1,120 @@
+/*
+ * Scilab ( http://www.scilab.org/ ) - This file is part of Scilab
+ * Copyright (C) 2009-2011 - DIGITEO - Pierre Lando
+ *
+ * This file must be used under the terms of the CeCILL.
+ * This source file is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at
+ * http://www.cecill.info/licences/Licence_CeCILL_V2.1-en.txt
+ */
+
+package org.scilab.forge.scirenderer.implementation.jogl.renderer;
+
+import org.scilab.forge.scirenderer.Drawer;
+import org.scilab.forge.scirenderer.implementation.jogl.JoGLDrawingTools;
+import org.scilab.forge.scirenderer.renderer.Renderer;
+
+import javax.media.opengl.GL2;
+
+/**
+ * @author Pierre Lando
+ */
+public class JoGLRenderer implements Renderer {
+
+ /**
+ * The current drawer.
+ */
+ private Drawer drawer;
+
+ /**
+ * The OpenGl display list name.
+ */
+ private Integer glName;
+
+ /**
+ * Store the display list up to date status.
+ */
+ private boolean upToDate;
+
+ /**
+ * Default constructor.
+ * The constructor is package : only {@link JoGLRendererManager} can instantiate this object.
+ */
+ JoGLRenderer() {
+ upToDate = false;
+ drawer = null;
+ glName = null;
+ }
+
+ @Override
+ public void setDrawer(Drawer drawer) {
+ this.drawer = drawer;
+ upToDate = false;
+ }
+
+ @Override
+ public Drawer getDrawer() {
+ return drawer;
+ }
+
+ @Override
+ public void reload() {
+ glName = null;
+ upToDate = false;
+ }
+
+ /**
+ * Perform a draw to the given canvas.
+ * @param drawingTools the given drawing tools.
+ */
+ public void draw(JoGLDrawingTools drawingTools) {
+ if (drawingTools.getCanvas().getJoGLParameters().useDisplayList()) {
+ synchronize(drawingTools);
+ GL2 gl = drawingTools.getGl().getGL2();
+ gl.glCallList(glName);
+ } else {
+ if (drawer != null) {
+ drawer.draw(drawingTools);
+ }
+ }
+ }
+
+ /**
+ * Synchronize the display list.
+ * @param drawingTools drawing tools.
+ */
+ private void synchronize(JoGLDrawingTools drawingTools) {
+ GL2 gl = drawingTools.getGl().getGL2();
+
+ // Check glName.
+ if ((glName == null) || !(gl.glIsList(glName))) {
+ glName = gl.glGenLists(1);
+ upToDate = false;
+ }
+
+ // Check up to date.
+ if (!upToDate) {
+ gl.glNewList(glName, GL2.GL_COMPILE);
+
+ if (drawer != null) {
+ drawer.draw(drawingTools);
+ }
+
+ gl.glEndList();
+ upToDate = true;
+ }
+ }
+
+ /**
+ * Dispose resources.
+ * @param gl the current OpenGl context.
+ */
+ void dispose(GL2 gl) {
+ if ((glName != null) && gl.glIsList(glName)) {
+ gl.glDeleteLists(glName, 1);
+ glName = null;
+ upToDate = false;
+ }
+ }
+}
diff --git a/modules/scirenderer/src/org/scilab/forge/scirenderer/implementation/jogl/renderer/JoGLRendererManager.java b/modules/scirenderer/src/org/scilab/forge/scirenderer/implementation/jogl/renderer/JoGLRendererManager.java
new file mode 100755
index 000000000..ed10de48e
--- /dev/null
+++ b/modules/scirenderer/src/org/scilab/forge/scirenderer/implementation/jogl/renderer/JoGLRendererManager.java
@@ -0,0 +1,100 @@
+/*
+ * Scilab ( http://www.scilab.org/ ) - This file is part of Scilab
+ * Copyright (C) 2009-2011 - DIGITEO - Pierre Lando
+ *
+ * This file must be used under the terms of the CeCILL.
+ * This source file is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at
+ * http://www.cecill.info/licences/Licence_CeCILL_V2.1-en.txt
+ */
+
+package org.scilab.forge.scirenderer.implementation.jogl.renderer;
+
+import org.scilab.forge.scirenderer.implementation.jogl.JoGLDrawingTools;
+import org.scilab.forge.scirenderer.renderer.Renderer;
+import org.scilab.forge.scirenderer.renderer.RendererManager;
+
+import javax.media.opengl.GL2;
+import java.util.HashSet;
+import java.util.Set;
+import java.util.Stack;
+
+/**
+ * @author Pierre Lando
+ */
+public class JoGLRendererManager implements RendererManager {
+
+ /**
+ * Set of current renderer.
+ */
+ private final Set<JoGLRenderer> rendererSet = new HashSet<JoGLRenderer>();
+
+ /**
+ * Set of dead buffers.
+ */
+ private final Stack<JoGLRenderer> deadRendererSet = new Stack<JoGLRenderer>();
+
+ /**
+ * Default constructor.
+ */
+ public JoGLRendererManager() {
+ }
+
+ @Override
+ public Renderer createRenderer() {
+ JoGLRenderer newRenderer = new JoGLRenderer();
+ rendererSet.add(newRenderer);
+ return newRenderer;
+ }
+
+ @Override
+ public void dispose(Renderer renderer) {
+ if ((renderer != null) && (renderer instanceof JoGLRenderer)) {
+ JoGLRenderer localRenderer = (JoGLRenderer) renderer;
+ rendererSet.remove(localRenderer);
+ deadRendererSet.push(localRenderer);
+ }
+ }
+
+ public void dispose(JoGLDrawingTools drawingTools, Renderer renderer) {
+ if ((renderer != null) && (renderer instanceof JoGLRenderer)) {
+ JoGLRenderer localRenderer = (JoGLRenderer) renderer;
+ localRenderer.dispose(drawingTools.getGl().getGL2());
+ rendererSet.remove(localRenderer);
+ deadRendererSet.push(localRenderer);
+ }
+ }
+
+ /**
+ * Perform a draw with the given renderer to the given canvas..
+ * @param drawingTools the given drawing tools.
+ * @param renderer the given renderer.
+ */
+ public void draw(JoGLDrawingTools drawingTools, Renderer renderer) {
+ if ((renderer != null) && (renderer instanceof JoGLRenderer)) {
+ ((JoGLRenderer) renderer).draw(drawingTools);
+ }
+ }
+
+ /**
+ * Ask all {@link JoGLRenderer} to reload.
+ * This is needed when the OpenGl context has been lost.
+ */
+ public void glReload() {
+ for (JoGLRenderer renderer : rendererSet) {
+ renderer.reload();
+ }
+ }
+
+ /**
+ * Synchronize to OpenGl context.
+ * Mostly consist to dispose dead renderer resources.
+ * @param gl the current OpenGl context.
+ */
+ public void glSynchronize(GL2 gl) {
+ while (!deadRendererSet.isEmpty()) {
+ deadRendererSet.pop().dispose(gl);
+ }
+ }
+}
diff --git a/modules/scirenderer/src/org/scilab/forge/scirenderer/implementation/jogl/texture/JoGLTextureManager.java b/modules/scirenderer/src/org/scilab/forge/scirenderer/implementation/jogl/texture/JoGLTextureManager.java
new file mode 100755
index 000000000..71876e18e
--- /dev/null
+++ b/modules/scirenderer/src/org/scilab/forge/scirenderer/implementation/jogl/texture/JoGLTextureManager.java
@@ -0,0 +1,745 @@
+/*
+ * Scilab ( http://www.scilab.org/ ) - This file is part of Scilab
+ * Copyright (C) 2009-2012 - DIGITEO - Pierre Lando
+ *
+ * This file must be used under the terms of the CeCILL.
+ * This source file is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at
+ * http://www.cecill.info/licences/Licence_CeCILL_V2.1-en.txt
+ */
+
+package org.scilab.forge.scirenderer.implementation.jogl.texture;
+
+import com.jogamp.opengl.util.texture.TextureIO;
+import com.jogamp.opengl.util.texture.TextureCoords;
+
+import org.scilab.forge.scirenderer.SciRendererException;
+import org.scilab.forge.scirenderer.buffers.ElementsBuffer;
+import org.scilab.forge.scirenderer.implementation.jogl.JoGLCanvas;
+import org.scilab.forge.scirenderer.implementation.jogl.JoGLDrawingTools;
+import org.scilab.forge.scirenderer.texture.AbstractTexture;
+import org.scilab.forge.scirenderer.texture.AnchorPosition;
+import org.scilab.forge.scirenderer.texture.Texture;
+import org.scilab.forge.scirenderer.texture.TextureManager;
+import org.scilab.forge.scirenderer.texture.TextureDataProvider;
+import org.scilab.forge.scirenderer.tranformations.Transformation;
+import org.scilab.forge.scirenderer.tranformations.TransformationManager;
+import org.scilab.forge.scirenderer.tranformations.Vector3d;
+
+
+import javax.media.opengl.GL;
+import javax.media.opengl.GL2;
+import javax.media.opengl.GL2ES1;
+import javax.media.opengl.GL2GL3;
+import javax.media.opengl.GLProfile;
+import java.awt.Dimension;
+import java.nio.ByteBuffer;
+import java.nio.FloatBuffer;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.Set;
+
+/**
+ * @author Pierre Lando
+ */
+public class JoGLTextureManager implements TextureManager {
+
+ private final Set<JoGLTexture> allTextures = Collections.synchronizedSet(new HashSet<JoGLTexture>());
+ JoGLCanvas canvas;
+
+ public JoGLTextureManager(JoGLCanvas canvas) {
+ this.canvas = canvas;
+ }
+
+ /**
+ * Texture binder.
+ * Bind the given texture to the given OpenGl context.
+ * @param drawingTools drawing tools.
+ * @param texture given texture.
+ * @throws org.scilab.forge.scirenderer.SciRendererException if the texture can't be bind.
+ */
+ public void bind(JoGLDrawingTools drawingTools, Texture texture) throws SciRendererException {
+ if ((texture instanceof JoGLTexture) && (allTextures.contains((JoGLTexture) texture))) {
+ ((JoGLTexture) texture).bind(drawingTools);
+ }
+ }
+
+ /**
+ * Draw the given texture.
+ * @param drawingTools used drawing tools.
+ * @param texture the texture too drawn.
+ * @throws org.scilab.forge.scirenderer.SciRendererException if the texture is invalid.
+ */
+ public void draw(JoGLDrawingTools drawingTools, Texture texture) throws SciRendererException {
+ if ((texture instanceof JoGLTexture) && (allTextures.contains((JoGLTexture) texture))) {
+ final JoGLTexture jt = (JoGLTexture) texture;
+ if (jt.preDraw(drawingTools)) {
+ jt.draw(drawingTools);
+ jt.postDraw(drawingTools);
+ }
+ }
+ }
+
+ public void draw(JoGLDrawingTools drawingTools, Texture texture, AnchorPosition anchor, ElementsBuffer positions, int offset, int stride, double rotationAngle) throws SciRendererException {
+ if ((texture instanceof JoGLTexture) && (allTextures.contains((JoGLTexture) texture))) {
+ if (positions != null) {
+ FloatBuffer data = positions.getData();
+ if (data != null) {
+ float[] position = {0, 0, 0, 1};
+ final JoGLTexture jt = (JoGLTexture) texture;
+ if (jt.preDraw(drawingTools)) {
+ stride = stride < 1 ? 1 : stride;
+ offset = offset < 0 ? 0 : offset;
+ if (stride == 1) {
+ data.position(4 * offset);
+ while (data.remaining() >= 4) {
+ data.get(position);
+ jt.draw(drawingTools, anchor, new Vector3d(position), rotationAngle);
+ }
+ } else {
+ int mark = 4 * offset;
+ if (mark < data.capacity()) {
+ data.position(mark);
+ while (data.remaining() >= 4) {
+ data.get(position);
+ mark += stride * 4;
+ if (mark < data.capacity()) {
+ data.position(mark);
+ } else {
+ break;
+ }
+ jt.draw(drawingTools, anchor, new Vector3d(position), rotationAngle);
+ }
+ }
+ }
+ jt.postDraw(drawingTools);
+ }
+ }
+ }
+ }
+ }
+
+ public void draw(JoGLDrawingTools drawingTools, Texture texture, AnchorPosition anchor, Vector3d position, double rotationAngle) throws SciRendererException {
+ if ((texture instanceof JoGLTexture) && (allTextures.contains((JoGLTexture) texture))) {
+ final JoGLTexture jt = (JoGLTexture) texture;
+ jt.preDraw(drawingTools);
+ jt.draw(drawingTools, anchor, position, rotationAngle);
+ jt.postDraw(drawingTools);
+ }
+ }
+
+ /** Called when gl context is gone. */
+ public void glReload() {
+ synchronized (allTextures) {
+ for (JoGLTexture texture : allTextures) {
+ texture.glReload();
+ }
+ }
+ }
+
+ @Override
+ public Texture createTexture() {
+ JoGLTexture texture = new JoGLTexture();
+ allTextures.add(texture);
+ return texture;
+ }
+
+ @Override
+ public void dispose(Collection<Texture> textures) {
+ for (Texture texture : textures) {
+ dispose(texture);
+ }
+ }
+
+ @Override
+ public void dispose(Texture texture) {
+ if ((texture instanceof JoGLTexture) && (allTextures.contains((JoGLTexture) texture))) {
+ allTextures.remove((JoGLTexture) texture);
+ ((JoGLTexture) texture).dispose();
+ }
+ }
+
+ /**
+ * Inner class for {@link Texture} implementation.
+ */
+ public class JoGLTexture extends AbstractTexture implements Texture {
+ private com.jogamp.opengl.util.texture.Texture[] textures;
+ private JoGLTextureData[] textureData;
+ private int wCuts;
+ private int hCuts;
+ private double sfactor = 1;
+ private double tfactor = 1;
+ private ByteBuffer buffer;
+ private TextureDataProvider.ImageType previousType;
+ private JoGLDrawingTools drawingTools;
+
+ /**
+ * Default constructor.
+ */
+ public JoGLTexture() {
+ }
+
+ public final boolean isRowMajorOrder() {
+ return getDataProvider().isRowMajorOrder();
+ }
+
+ /**
+ * Bind the texture in the OpenGl context.
+ * @param drawingTools current drawing tools.
+ * @throws SciRendererException if the texture is invalid.
+ */
+ public synchronized void bind(JoGLDrawingTools drawingTools) throws SciRendererException {
+ if (this.drawingTools == null) {
+ this.drawingTools = this.drawingTools;
+ }
+
+ GL2 gl = drawingTools.getGl().getGL2();
+ if (isValid()) {
+ checkData(drawingTools);
+ if (textures.length == 1) {
+ gl.glEnable(GL2.GL_TEXTURE_2D);
+ gl.glEnable(GL2.GL_BLEND);
+ gl.glBlendFunc(GL2.GL_SRC_ALPHA, GL2.GL_ONE_MINUS_SRC_ALPHA);
+ gl.glTexEnvi(GL2.GL_TEXTURE_ENV, GL2.GL_TEXTURE_ENV_MODE, GL2.GL_REPLACE);
+
+ textures[0].setTexParameteri(gl, GL2.GL_TEXTURE_MAG_FILTER, getAsGLFilter(getMagnificationFilter(), false));
+ textures[0].setTexParameteri(gl, GL2.GL_TEXTURE_MIN_FILTER, getAsGLFilter(getMinifyingFilter(), false));
+ if (gl.isNPOTTextureAvailable()) {
+ textures[0].setTexParameteri(gl, GL2.GL_TEXTURE_WRAP_S, getAsGLWrappingMode(getSWrappingMode()));
+ textures[0].setTexParameteri(gl, GL2.GL_TEXTURE_WRAP_T, getAsGLWrappingMode(getTWrappingMode()));
+ } else {
+ textures[0].setTexParameteri(gl, GL2.GL_TEXTURE_WRAP_S, GL2.GL_CLAMP_TO_EDGE);
+ textures[0].setTexParameteri(gl, GL2.GL_TEXTURE_WRAP_T, GL2.GL_CLAMP_TO_EDGE);
+ }
+ textures[0].bind(gl);
+
+ /* sfactor and tfactor are useful to have the correct texture coordinates when the texture
+ was transformed into a power-of-two texture */
+ Dimension textureSize = getDataProvider().getTextureSize();
+ sfactor = (double) textureSize.width / (double) textures[0].getWidth();
+ tfactor = (double) textureSize.height / (double) textures[0].getHeight();
+ } else {
+ throw new SciRendererException("Texture is too large");
+ }
+ } else {
+ throw new SciRendererException("Texture have no data.");
+ }
+ }
+
+ /**
+ * Check if the texture data are up to date.
+ * @param drawingTools the drawing tools.
+ * @throws SciRendererException if the texture is too big.
+ */
+ private synchronized void checkData(JoGLDrawingTools drawingTools) throws SciRendererException {
+ if (isValid() && !upToDate) {
+ GL2 gl = drawingTools.getGl().getGL2();
+
+ Dimension textureSize = getDataProvider().getTextureSize();
+ int maxSize = drawingTools.getGLCapacity().getMaximumTextureSize();
+ wCuts = (int) Math.ceil(textureSize.getWidth() / maxSize);
+ hCuts = (int) Math.ceil(textureSize.getHeight() / maxSize);
+ ByteBuffer newBuffer = getDataProvider().getData();
+ TextureDataProvider.ImageType newType = getDataProvider().getImageType();
+
+ if (newBuffer != null && textureSize.width != 0 && textureSize.height != 0) {
+ boolean hasChanged = false;
+ if (newBuffer != buffer || newType != previousType) {
+ releaseTextures(gl);
+ if (newBuffer != null) {
+ textures = new com.jogamp.opengl.util.texture.Texture[wCuts * hCuts];
+ textureData = new JoGLTextureData[wCuts * hCuts];
+ }
+ buffer = newBuffer;
+ previousType = newType;
+ hasChanged = true;
+ }
+
+ if (newBuffer != null || buffer != null) {
+ if (wCuts == 1 && hCuts == 1) {
+ if (hasChanged) {
+ if (isRowMajorOrder()) {
+ textureData[0] = new JoGLTextureData(gl.getGLProfile(), newType, buffer, textureSize.width, textureSize.height);
+ } else {
+ textureData[0] = new JoGLTextureData(gl.getGLProfile(), newType, buffer, textureSize.height, textureSize.width);
+ }
+ try {
+ textures[0] = TextureIO.newTexture(textureData[0]);
+ } catch (Exception e) {
+ System.err.println(e);
+ }
+ } else {
+ try {
+ textures[0].updateSubImage(gl, textureData[0], 0, 0, 0);
+ } catch (Exception e) {
+ System.err.println(e);
+ }
+ }
+ } else {
+ int k = 0;
+ for (int i = 0; i < wCuts; i++) {
+ for (int j = 0; j < hCuts; j++) {
+ if (hasChanged) {
+ final int x = i * maxSize;
+ final int y = j * maxSize;
+ final int width = getSubTextureSize((i == (wCuts - 1)), textureSize.width, maxSize);
+ final int height = getSubTextureSize((j == (hCuts - 1)), textureSize.height, maxSize);
+ if (isRowMajorOrder()) {
+ textureData[k] = new JoGLTextureData(gl.getGLProfile(), newType, buffer, width, height, x, y, textureSize.width, textureSize.height);
+ } else {
+ textureData[k] = new JoGLTextureData(gl.getGLProfile(), newType, buffer, height, width, y, x, textureSize.height, textureSize.width);
+ }
+ textures[k] = TextureIO.newTexture(textureData[k]);
+ } else {
+ textures[k].updateSubImage(gl, textureData[k], 0, 0, 0);
+ }
+ k++;
+ }
+ }
+ }
+ }
+ }
+ if (textures != null) {
+ upToDate = true;
+ }
+ }
+ }
+
+ private void releaseTextures(GL2 gl) {
+ if (textures != null) {
+ for (com.jogamp.opengl.util.texture.Texture texture : textures) {
+ if (texture != null) {
+ texture.destroy(gl);
+ }
+ }
+ textures = null;
+ }
+
+ if (textureData != null) {
+ for (JoGLTextureData td : textureData) {
+ if (td != null) {
+ td.destroy();
+ }
+ }
+ textureData = null;
+ }
+ }
+
+ public void dispose() {
+ if (drawingTools != null) {
+ releaseTextures(drawingTools.getGl().getGL2());
+ }
+ }
+
+ public boolean preDraw(JoGLDrawingTools drawingTools) throws SciRendererException {
+ checkData(drawingTools);
+
+ if (textures == null) {
+ return false;
+ }
+
+ final GL2 gl = drawingTools.getGl().getGL2();
+
+ gl.glMatrixMode(GL2.GL_TEXTURE);
+ gl.glPushMatrix();
+ gl.glLoadIdentity();
+
+ gl.glMatrixMode(GL2.GL_PROJECTION);
+ gl.glPushMatrix();
+ gl.glLoadIdentity();
+
+ gl.glEnable(GL2.GL_TEXTURE_2D);
+ gl.glEnable(GL2.GL_BLEND);
+
+ // ONE => SRC_ALPHA (fix for bug 13673)
+ gl.glBlendFunc(GL2.GL_SRC_ALPHA, GL2.GL_ONE_MINUS_SRC_ALPHA);
+
+ gl.glEnable(GL2.GL_ALPHA_TEST);
+ gl.glAlphaFunc(GL2.GL_GREATER, 0.0f);
+
+ gl.glPushAttrib(GL2.GL_ALL_ATTRIB_BITS);
+
+ gl.glTexEnvi(GL2.GL_TEXTURE_ENV, GL2.GL_TEXTURE_ENV_MODE, GL2.GL_REPLACE);
+
+ for (int k = 0; k < wCuts * hCuts; k++) {
+ textures[k].enable(gl);
+ textures[k].setTexParameteri(gl, GL2.GL_TEXTURE_MAG_FILTER, getAsGLFilter(getMagnificationFilter(), false));
+ textures[k].setTexParameteri(gl, GL2.GL_TEXTURE_MIN_FILTER, getAsGLFilter(getMinifyingFilter(), false));
+ if (gl.isNPOTTextureAvailable()) {
+ textures[k].setTexParameteri(gl, GL2.GL_TEXTURE_WRAP_S, getAsGLWrappingMode(getSWrappingMode()));
+ textures[k].setTexParameteri(gl, GL2.GL_TEXTURE_WRAP_T, getAsGLWrappingMode(getTWrappingMode()));
+ } else {
+ textures[k].setTexParameteri(gl, GL2.GL_TEXTURE_WRAP_S, GL2.GL_CLAMP_TO_EDGE);
+ textures[k].setTexParameteri(gl, GL2.GL_TEXTURE_WRAP_T, GL2.GL_CLAMP_TO_EDGE);
+ }
+ }
+
+ return true;
+ }
+
+ public void draw(JoGLDrawingTools drawingTools, AnchorPosition anchor, Vector3d position, double rotationAngle) throws SciRendererException {
+ TransformationManager transformationManager = drawingTools.getTransformationManager();
+ Transformation canvasProjection = transformationManager.getCanvasProjection();
+ boolean sceneCoordinate = drawingTools.getTransformationManager().isUsingSceneCoordinate();
+ Dimension dimension = drawingTools.getCanvas().getDimension();
+ Vector3d projected;
+ final GL2 gl = drawingTools.getGl().getGL2();
+
+ if (sceneCoordinate) {
+ projected = canvasProjection.project(position);
+ } else {
+ projected = position;
+ }
+
+ gl.glMatrixMode(GL2.GL_MODELVIEW);
+ gl.glPushMatrix();
+ gl.glLoadIdentity();
+ gl.glOrtho(0, dimension.width, 0, dimension.height, 1, -1);
+
+ if (rotationAngle == 0) {
+ gl.glTranslated(Math.round(projected.getX() + getAnchorDeltaX(anchor)), Math.round(projected.getY() + getAnchorDeltaY(anchor)), projected.getZ());
+ } else {
+ gl.glTranslated(Math.round(projected.getX()), Math.round(projected.getY()), projected.getZ());
+ gl.glRotated(rotationAngle, 0, 0, 1);
+ gl.glTranslated(Math.round(getAnchorDeltaX(anchor)), Math.round(getAnchorDeltaY(anchor)), 0);
+ }
+
+ draw(drawingTools);
+
+ gl.glMatrixMode(GL2.GL_MODELVIEW);
+ gl.glPopMatrix();
+ }
+
+ public void postDraw(JoGLDrawingTools drawingTools) {
+ final GL2 gl = drawingTools.getGl().getGL2();
+
+ for (int k = 0; k < wCuts * hCuts; k++) {
+ textures[k].disable(gl);
+ }
+
+ gl.glPopAttrib();
+ gl.glDisable(GL2.GL_ALPHA_TEST);
+ gl.glDisable(GL2.GL_TEXTURE_2D);
+ gl.glDisable(GL2.GL_BLEND);
+
+ gl.glMatrixMode(GL2.GL_PROJECTION);
+ gl.glPopMatrix();
+
+ gl.glMatrixMode(GL2.GL_TEXTURE);
+ gl.glPopMatrix();
+ }
+
+ /**
+ * Draw the texture in XY plane.
+ * @param drawingTools the drawing tools.
+ * @throws SciRendererException if the texture is invalid.
+ */
+ public void draw(JoGLDrawingTools drawingTools) throws SciRendererException {
+ final int maxSize = drawingTools.getGLCapacity().getMaximumTextureSize();
+ final Dimension textureSize = getDataProvider().getTextureSize();
+ final GL2 gl = drawingTools.getGl().getGL2();
+
+ if (textureSize != null && textures != null) {
+ if (wCuts == 1 && hCuts == 1) {
+ final TextureCoords coords;
+ if (isRowMajorOrder()) {
+ coords = textures[0].getSubImageTexCoords(0, 0, textureSize.width, textureSize.height);
+ } else {
+ coords = textures[0].getSubImageTexCoords(0, 0, textureSize.height, textureSize.width);
+ }
+ textures[0].bind(gl);
+
+ gl.glBegin(GL2.GL_QUADS);
+ gl.glTexCoord2f(coords.left(), coords.bottom());
+ if (isRowMajorOrder()) {
+ gl.glVertex2f(0, 0);
+ } else {
+ gl.glVertex2f(textureSize.width, textureSize.height);
+ }
+ gl.glTexCoord2f(coords.right(), coords.bottom());
+ gl.glVertex2f(textureSize.width, 0);
+ gl.glTexCoord2f(coords.right(), coords.top());
+ if (isRowMajorOrder()) {
+ gl.glVertex2f(textureSize.width, textureSize.height);
+ } else {
+ gl.glVertex2f(0, 0);
+ }
+ gl.glTexCoord2f(coords.left(), coords.top());
+ gl.glVertex2f(0, textureSize.height);
+ gl.glEnd();
+ } else {
+ int k = 0;
+ for (int i = 0; i < wCuts; i++) {
+ for (int j = 0; j < hCuts; j++) {
+ final int x = i * maxSize;
+ final int y = j * maxSize;
+ final int width = getSubTextureSize((i == (wCuts - 1)), textureSize.width, maxSize);
+ final int height = getSubTextureSize((j == (hCuts - 1)), textureSize.height, maxSize);
+
+ // if the texture has been transformed in a power-of-two texture we need to have the correct coords.
+ final TextureCoords coords;
+ if (isRowMajorOrder()) {
+ coords = textures[k].getSubImageTexCoords(0, 0, width, height);
+ } else {
+ coords = textures[k].getSubImageTexCoords(0, 0, height, width);
+ }
+ textures[k].bind(gl);
+
+ gl.glBegin(GL2.GL_QUADS);
+ gl.glTexCoord2f(coords.left(), coords.top());
+ gl.glVertex2f(x, textureSize.height - y);
+ gl.glTexCoord2f(coords.right(), coords.top());
+ if (isRowMajorOrder()) {
+ gl.glVertex2f(x + width, textureSize.height - y);
+ } else {
+ gl.glVertex2f(x, textureSize.height - y - height);
+ }
+ gl.glTexCoord2f(coords.right(), coords.bottom());
+ gl.glVertex2f(x + width, textureSize.height - y - height);
+ gl.glTexCoord2f(coords.left(), coords.bottom());
+ if (isRowMajorOrder()) {
+ gl.glVertex2f(x, textureSize.height - y - height);
+ } else {
+ gl.glVertex2f(x + width, textureSize.height - y);
+ }
+ gl.glEnd();
+
+ k++;
+ }
+ }
+ }
+ }
+ }
+
+ @Override
+ public double getSScaleFactor() {
+ return sfactor;
+ }
+
+ @Override
+ public double getTScaleFactor() {
+ return tfactor;
+ }
+
+ /**
+ * Compute the sub texture size.
+ * @param lastPart true if this is the last part.
+ * @param textureSize the global texture size.
+ * @param maxSize the maximum sub-texture size.
+ * @return the sub texture size.
+ */
+ private int getSubTextureSize(boolean lastPart, int textureSize, int maxSize) {
+ if (lastPart) {
+ int lastSize = textureSize % maxSize;
+ if (lastSize == 0) {
+ return maxSize;
+ } else {
+ return lastSize;
+ }
+ } else {
+ return maxSize;
+ }
+ }
+
+ private int getAsGLWrappingMode(Texture.Wrap wrappingMode) {
+ switch (wrappingMode) {
+ case CLAMP:
+ return GL2.GL_CLAMP_TO_EDGE;
+ case REPEAT:
+ return GL2.GL_REPEAT;
+ default:
+ return GL2.GL_REPEAT;
+ }
+ }
+
+ private int getAsGLFilter(Texture.Filter filter, boolean mipmap) {
+ int returnedValue;
+ if (mipmap) {
+ switch (filter) {
+ case LINEAR:
+ returnedValue = GL2.GL_LINEAR_MIPMAP_LINEAR;
+ break;
+ case NEAREST:
+ returnedValue = GL2.GL_NEAREST_MIPMAP_NEAREST;
+ break;
+ default:
+ returnedValue = GL2.GL_NEAREST;
+ break;
+ }
+ } else {
+ switch (filter) {
+ case LINEAR:
+ returnedValue = GL2.GL_LINEAR;
+ break;
+ case NEAREST:
+ returnedValue = GL2.GL_NEAREST;
+ break;
+ default:
+ returnedValue = GL2.GL_NEAREST;
+ break;
+ }
+ }
+ return returnedValue;
+ }
+
+ /** Called when gl context is gone. */
+ public void glReload() {
+ buffer = null;
+ textures = null;
+ upToDate = false;
+ }
+
+ /**
+ * Return the deltaX to apply to the sprite in regards to the given anchor.
+ * @param anchor the given anchor.
+ * @return the deltaX to apply to the sprite in regards to the given anchor.
+ */
+ protected double getAnchorDeltaX(AnchorPosition anchor) {
+ int spriteWidth = getDataProvider().getTextureSize().width;
+ switch (anchor) {
+ case LEFT:
+ case LOWER_LEFT:
+ case UPPER_LEFT:
+ return 0;
+ case UP:
+ case CENTER:
+ case DOWN:
+ return -spriteWidth / 2f;
+ case RIGHT:
+ case LOWER_RIGHT:
+ case UPPER_RIGHT:
+ return -spriteWidth;
+ default:
+ return 0;
+ }
+ }
+
+ /**
+ * Return the deltaY to apply to the sprite in regards to the given anchor.
+ * @param anchor the given anchor.
+ * @return the deltaY to apply to the sprite in regards to the given anchor.
+ */
+ protected double getAnchorDeltaY(AnchorPosition anchor) {
+ int spriteHeight = getDataProvider().getTextureSize().height;
+ switch (anchor) {
+ case UPPER_LEFT:
+ case UP:
+ case UPPER_RIGHT:
+ return -spriteHeight;
+ case LEFT:
+ case CENTER:
+ case RIGHT:
+ return -spriteHeight / 2f;
+ case LOWER_LEFT:
+ case DOWN:
+ case LOWER_RIGHT:
+ return 0;
+ default:
+ return 0;
+ }
+ }
+ }
+
+ private static class JoGLTextureData extends com.jogamp.opengl.util.texture.TextureData {
+
+ private ByteBuffer data;
+ private int shift;
+
+ public JoGLTextureData(GLProfile glp, int[] infos, ByteBuffer data, int width, int height, int x, int y, int totalWidth, int totalHeight) {
+ super(glp, infos[0], width, height, 0, infos[1], infos[2], false, false, true, null, null);
+ this.data = data;
+ this.shift = ((x == 0 && y == 0) || data.capacity() == 0) ? 0 : (data.capacity() / (totalWidth * totalHeight) * (x + y * totalWidth));
+ this.rowLength = totalWidth;
+ this.alignment = infos[3];
+ }
+
+ public JoGLTextureData(GLProfile glp, TextureDataProvider.ImageType type, ByteBuffer data, int width, int height) {
+ this(glp, getInfos(type), data, width, height, 0, 0, width, height);
+ }
+
+ public JoGLTextureData(GLProfile glp, TextureDataProvider.ImageType type, ByteBuffer data, int width, int height, int x, int y, int totalWidth, int totalHeight) {
+ this(glp, getInfos(type), data, width, height, x, y, totalWidth, totalHeight);
+ }
+
+ public ByteBuffer getBuffer() {
+ if (shift == 0) {
+ return data;
+ } else {
+ data.position(shift);
+ ByteBuffer b = data.slice();
+ data.rewind();
+
+ return b;
+ }
+ }
+
+ public void setData(ByteBuffer data) {
+ this.data = data;
+ }
+
+ public void destroy() {
+ super.destroy();
+ this.data = null;
+ }
+
+ public static int[] getInfos(TextureDataProvider.ImageType type) {
+ switch (type) {
+ case RGB:
+ //internalFormat, pixelFormat, pixelType, alignment
+ return new int[] {GL2.GL_RGB, GL.GL_RGB, GL2.GL_UNSIGNED_BYTE, 1};
+ case RGB_RGBA:
+ return new int[] {GL2.GL_RGB, GL.GL_RGBA, GL2.GL_UNSIGNED_INT_8_8_8_8, 4};
+ case BGR:
+ return new int[] {GL2GL3.GL_RGB, GL2GL3.GL_BGR, GL.GL_UNSIGNED_BYTE, 1};
+ case GRAY:
+ return new int[] {GL.GL_LUMINANCE, GL.GL_LUMINANCE, GL.GL_UNSIGNED_BYTE, 1};
+ case GRAY_16:
+ return new int[] {GL2.GL_LUMINANCE16, GL2.GL_LUMINANCE, GL2.GL_UNSIGNED_SHORT, 2};
+ case RGBA:
+ return new int[] {GL2.GL_RGBA, GL.GL_RGBA, GL2.GL_UNSIGNED_INT_8_8_8_8, 4};
+ case RGBA_REV:
+ return new int[] {GL2.GL_RGBA, GL2.GL_RGBA, GL2.GL_UNSIGNED_INT_8_8_8_8_REV, 4};
+ case ABGR:
+ return new int[] {GL2.GL_RGBA, GL2.GL_ABGR_EXT, GL.GL_UNSIGNED_BYTE, 1};
+ case RGB_332:
+ return new int[] {GL2.GL_R3_G3_B2, GL2.GL_RGB, GL2.GL_UNSIGNED_BYTE_3_3_2, 1};
+ case RED:
+ return new int[] {GL2.GL_RED, GL2.GL_RED, GL2.GL_UNSIGNED_BYTE, 1};
+ case GREEN:
+ return new int[] {GL2.GL_RGB8, GL2.GL_GREEN, GL2.GL_UNSIGNED_BYTE, 1};
+ case BLUE:
+ return new int[] {GL2.GL_RGB8, GL2.GL_BLUE, GL2.GL_UNSIGNED_BYTE, 1};
+ case INTENSITY:
+ return new int[] {GL2.GL_INTENSITY, GL2.GL_LUMINANCE, GL2.GL_UNSIGNED_BYTE, 1};
+ case RGBA_4444:
+ return new int[] {GL2.GL_RGBA4, GL2.GL_RGBA, GL2.GL_UNSIGNED_SHORT_4_4_4_4, 2};
+ case RGBA_5551:
+ return new int[] {GL2.GL_RGB5_A1, GL2.GL_RGBA, GL2.GL_UNSIGNED_SHORT_5_5_5_1, 2};
+ case RGB_FLOAT:
+ return new int[] {GL2ES1.GL_RGB16F, GL2.GL_RGB, GL2.GL_FLOAT, 4};
+ case RGBA_FLOAT:
+ return new int[] {GL2.GL_RGBA16F, GL2.GL_RGBA, GL2.GL_FLOAT, 4};
+ case GRAY_FLOAT:
+ return new int[] {GL2.GL_LUMINANCE16F, GL2.GL_LUMINANCE, GL2.GL_FLOAT, 4};
+ case RED_16:
+ return new int[] {GL2.GL_RGB16, GL2.GL_RED, GL2.GL_UNSIGNED_SHORT, 2};
+ case GREEN_16:
+ return new int[] {GL2.GL_RGB16, GL2.GL_GREEN, GL2.GL_UNSIGNED_SHORT, 2};
+ case BLUE_16:
+ return new int[] {GL2.GL_RGB16, GL2.GL_BLUE, GL2.GL_UNSIGNED_SHORT, 2};
+ case RED_FLOAT:
+ return new int[] {GL2ES1.GL_RGB16F, GL2.GL_RED, GL2.GL_FLOAT, 4};
+ case GREEN_FLOAT:
+ return new int[] {GL2ES1.GL_RGB16F, GL2.GL_GREEN, GL2.GL_FLOAT, 4};
+ case BLUE_FLOAT:
+ return new int[] {GL2ES1.GL_RGB16F, GL2.GL_BLUE, GL2.GL_FLOAT, 4};
+ case RGBA_BYTE:
+ return new int[] {GL2.GL_RGBA, GL2.GL_RGBA, GL2.GL_UNSIGNED_BYTE, 1};
+ }
+
+ return new int[] {GL2.GL_RGB, GL.GL_RGB, GL2.GL_UNSIGNED_BYTE, 1};
+ }
+ }
+}
diff --git a/modules/scirenderer/src/org/scilab/forge/scirenderer/implementation/jogl/utils/G2DShortCuts.java b/modules/scirenderer/src/org/scilab/forge/scirenderer/implementation/jogl/utils/G2DShortCuts.java
new file mode 100755
index 000000000..b9baa6d5c
--- /dev/null
+++ b/modules/scirenderer/src/org/scilab/forge/scirenderer/implementation/jogl/utils/G2DShortCuts.java
@@ -0,0 +1,57 @@
+/*
+ * Scilab ( http://www.scilab.org/ ) - This file is part of Scilab
+ * Copyright (C) 2009-2011 - DIGITEO - Pierre Lando
+ *
+ * This file must be used under the terms of the CeCILL.
+ * This source file is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at
+ * http://www.cecill.info/licences/Licence_CeCILL_V2.1-en.txt
+ */
+
+package org.scilab.forge.scirenderer.implementation.jogl.utils;
+
+import org.scilab.forge.scirenderer.shapes.appearance.Appearance;
+import org.scilab.forge.scirenderer.shapes.appearance.Color;
+
+import java.awt.BasicStroke;
+import java.awt.Graphics2D;
+import java.awt.Stroke;
+
+/**
+ *
+ * Utility class for common {@link java.awt.Graphics2D} calls.
+ *
+ * @author Pierre Lando
+ */
+public final class G2DShortCuts {
+
+ /**
+ * Private constructor: this is an utility class.
+ */
+ private G2DShortCuts() {
+ }
+
+
+
+ /**
+ * Use the given color for drawing.
+ * @param g2d the {@link Graphics2D} where the color will be used.
+ * @param c the given color.
+ */
+ public static void useColor(Graphics2D g2d, Color c) {
+ java.awt.Color color = new java.awt.Color(c.getRed(), c.getGreen(), c.getBlue(), c.getAlpha());
+ g2d.setColor(color);
+ }
+
+ /**
+ * Use the given appearance for drawing lines.
+ * @param g2d the {@link Graphics2D} where the appearance will be used.
+ * @param appearance the given appearance.
+ */
+ public static void useLineAppearance(Graphics2D g2d, Appearance appearance) {
+ // TODO : add line pattern.
+ Stroke stroke = new BasicStroke(appearance.getLineWidth());
+ g2d.setStroke(stroke);
+ }
+}
diff --git a/modules/scirenderer/src/org/scilab/forge/scirenderer/implementation/jogl/utils/GLShortCuts.java b/modules/scirenderer/src/org/scilab/forge/scirenderer/implementation/jogl/utils/GLShortCuts.java
new file mode 100755
index 000000000..7928a7e57
--- /dev/null
+++ b/modules/scirenderer/src/org/scilab/forge/scirenderer/implementation/jogl/utils/GLShortCuts.java
@@ -0,0 +1,110 @@
+/*
+ * Scilab ( http://www.scilab.org/ ) - This file is part of Scilab
+ * Copyright (C) 2009-2011 - DIGITEO - Pierre Lando
+ *
+ * This file must be used under the terms of the CeCILL.
+ * This source file is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at
+ * http://www.cecill.info/licences/Licence_CeCILL_V2.1-en.txt
+ */
+
+package org.scilab.forge.scirenderer.implementation.jogl.utils;
+
+import org.scilab.forge.scirenderer.shapes.appearance.Appearance;
+import org.scilab.forge.scirenderer.shapes.appearance.Color;
+
+import javax.media.opengl.GL2;
+
+/**
+ *
+ * Utility class for common OpenGl calls.
+ *
+ * @author Pierre Lando
+ */
+public final class GLShortCuts {
+
+ private static final short FULL_LINE_PATTERN = (short) 0xFFFF;
+
+
+ /**
+ * Private constructor.
+ * This is an utility class.
+ */
+ private GLShortCuts() {
+ }
+
+
+ /**
+ * Set the OpenGl context line appearance from the given appearance.
+ * If appearance is null, default value are used..
+ * @param gl the OpenGl context.
+ * @param appearance the appearance to use.
+ */
+ public static void useLineAppearance(GL2 gl, Appearance appearance) {
+ Appearance usedAppearance;
+ if (appearance == null) {
+ usedAppearance = new Appearance();
+ } else {
+ usedAppearance = appearance;
+ }
+
+ useColor(gl, usedAppearance.getLineColor());
+ gl.glLineWidth(getClampedLineWidth(gl, usedAppearance.getLineWidth()));
+ short pattern = usedAppearance.getLinePattern();
+ if (pattern != FULL_LINE_PATTERN) {
+ gl.glEnable(GL2.GL_LINE_STIPPLE);
+ gl.glLineStipple((int) usedAppearance.getLineWidth(), pattern);
+ } else {
+ gl.glDisable(GL2.GL_LINE_STIPPLE);
+ }
+ }
+
+ /**
+ * Return given lineWidth clamped to lineWidth range.
+ * @param gl the current gl context.
+ * @param lineWidth given line width.
+ * @return given lineWidth clamped to lineWidth range.
+ */
+ private static float getClampedLineWidth(GL2 gl, float lineWidth) {
+ float[] range = new float[] {1f, 1f};
+ if (gl.glIsEnabled(GL2.GL_LINE_SMOOTH)) {
+ gl.glGetFloatv(GL2.GL_SMOOTH_LINE_WIDTH_RANGE, range, 0);
+ } else {
+ gl.glGetFloatv(GL2.GL_ALIASED_LINE_WIDTH_RANGE, range, 0);
+ }
+
+ if (lineWidth < range[0]) {
+ return range[0];
+ } else if (lineWidth > range[1]) {
+ return range[1];
+ } else {
+ return lineWidth;
+ }
+ }
+
+ /**
+ * Set the OpenGl context color to the given color.
+ * @param gl the OpenGl context.
+ * @param color the color to use.
+ */
+ public static void useColor(GL2 gl, Color color) {
+ if (color != null) {
+ gl.glColor3f(color.getRedAsFloat(), color.getGreenAsFloat(), color.getBlueAsFloat());
+ }
+ }
+
+ /**
+ * Enable or disable GL option.
+ * @param gl the current gl.
+ * @param option the option to change.
+ * @param status the new option status.
+ */
+ public static void setEnable(GL2 gl, int option, boolean status) {
+ if (status) {
+ gl.glEnable(option);
+ } else {
+ gl.glDisable(option);
+ }
+ }
+}
diff --git a/modules/scirenderer/src/org/scilab/forge/scirenderer/lightning/Light.java b/modules/scirenderer/src/org/scilab/forge/scirenderer/lightning/Light.java
new file mode 100755
index 000000000..d42c7a2db
--- /dev/null
+++ b/modules/scirenderer/src/org/scilab/forge/scirenderer/lightning/Light.java
@@ -0,0 +1,126 @@
+/*
+ * Scilab ( http://www.scilab.org/ ) - This file is part of Scilab
+ * Copyright (C) 2009-2011 - DIGITEO - Pierre Lando
+ *
+ * This file must be used under the terms of the CeCILL.
+ * This source file is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at
+ * http://www.cecill.info/licences/Licence_CeCILL_V2.1-en.txt
+ */
+
+package org.scilab.forge.scirenderer.lightning;
+
+import org.scilab.forge.scirenderer.shapes.appearance.Color;
+import org.scilab.forge.scirenderer.tranformations.Vector3d;
+
+/**
+ * The light interface.
+ *
+ * @author Pierre Lando
+ */
+public interface Light {
+
+ /**
+ * Return the status of this light.
+ * @return the status of this light.
+ */
+ boolean isEnable();
+
+ /**
+ * Set the status of this light.
+ * @param enable the new status of this light.
+ */
+ void setEnable(boolean enable);
+
+ /**
+ * Return the ambient color of this light;
+ * @return the ambient color of this light;
+ */
+ Color getAmbientColor();
+
+ /**
+ * Set the ambient color of this light.
+ * @param color the new ambient color of this light.
+ */
+ void setAmbientColor(Color color);
+
+ /**
+ * Return the diffuse color of this light;
+ * @return the diffuse color of this light;
+ */
+ Color getDiffuseColor();
+
+ /**
+ * Set the diffuse color of this light.
+ * @param color the new diffuse color of this light.
+ */
+ void setDiffuseColor(Color color);
+
+ /**
+ * Return the specular color of this light;
+ * @return the specular color of this light;
+ */
+ Color getSpecularColor();
+
+ /**
+ * Set the specular color of this light.
+ * @param color the new specular color of this light.
+ */
+ void setSpecularColor(Color color);
+
+ /**
+ * Return the light position.
+ * @return the light position.
+ */
+ Vector3d getPosition();
+
+ /**
+ * Set the light position.
+ * @param position the new position.
+ */
+ void setPosition(Vector3d position);
+
+ /**
+ * Get the light direction.
+ * @return the light direction.
+ */
+ Vector3d getDirection();
+
+ /**
+ * Set the light direction.
+ * Used only for directional light.
+ * @param position the new position.
+ */
+ void setDirection(Vector3d direction);
+
+ /**
+ * Return the spot direction.
+ * @return the spot direction.
+ */
+ Vector3d getSpotDirection();
+
+ /**
+ * Set the spot direction.
+ * @param spotDirection the new spot direction.
+ */
+ void setSpotDirection(Vector3d spotDirection);
+
+ /**
+ * Return the spot angle.
+ * @return the spot angle.
+ */
+ float getSpotAngle();
+
+ /**
+ * Set the spot angle.
+ * @param angle the new spot angle.
+ */
+ void setSpotAngle(float angle);
+
+ /**
+ * Return the light index.
+ * @return the light index.
+ */
+ int getIndex();
+}
diff --git a/modules/scirenderer/src/org/scilab/forge/scirenderer/lightning/LightManager.java b/modules/scirenderer/src/org/scilab/forge/scirenderer/lightning/LightManager.java
new file mode 100755
index 000000000..0dd294c2b
--- /dev/null
+++ b/modules/scirenderer/src/org/scilab/forge/scirenderer/lightning/LightManager.java
@@ -0,0 +1,61 @@
+/*
+ * Scilab ( http://www.scilab.org/ ) - This file is part of Scilab
+ * Copyright (C) 2009-2011 - DIGITEO - Pierre Lando
+ *
+ * This file must be used under the terms of the CeCILL.
+ * This source file is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at
+ * http://www.cecill.info/licences/Licence_CeCILL_V2.1-en.txt
+ */
+
+package org.scilab.forge.scirenderer.lightning;
+
+import org.scilab.forge.scirenderer.shapes.appearance.Material;
+
+/**
+ * Light manager interface.
+ *
+ * @author Pierre Lando
+ */
+public interface LightManager {
+
+ /**
+ * The default lightning status.
+ */
+ boolean DEFAULT_LIGHTNING_STATUS = false;
+
+ /**
+ * Return the number of available light.
+ * @return the number of available light.
+ */
+ int getLightNumber();
+
+ /**
+ * Return the i-th light.
+ * {@code null} is returned if i is not a valid index.
+ * @param i the given index.
+ * @return the i-th light.
+ */
+ Light getLight(int i);
+
+ /**
+ * Set the lightning status.
+ * Lighting is initially disabled.
+ * When it is enabled, light sources that are enabled contribute to the lighting calculation.
+ * @param isLightningEnable the new lightning status.
+ */
+ void setLightningEnable(boolean isLightningEnable);
+
+ /**
+ * Return the lightning status.
+ * @return the lightning status.
+ */
+ boolean isLightningEnable();
+
+ /**
+ * Set the material properties used for lighting.
+ * @param material the material.
+ */
+ void setMaterial(Material material);
+}
diff --git a/modules/scirenderer/src/org/scilab/forge/scirenderer/picking/PickingManager.java b/modules/scirenderer/src/org/scilab/forge/scirenderer/picking/PickingManager.java
new file mode 100755
index 000000000..2efb6e29b
--- /dev/null
+++ b/modules/scirenderer/src/org/scilab/forge/scirenderer/picking/PickingManager.java
@@ -0,0 +1,27 @@
+/*
+ * Scilab ( http://www.scilab.org/ ) - This file is part of Scilab
+ * Copyright (C) 2009-2011 - DIGITEO - Pierre Lando
+ *
+ * This file must be used under the terms of the CeCILL.
+ * This source file is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at
+ * http://www.cecill.info/licences/Licence_CeCILL_V2.1-en.txt
+ */
+
+package org.scilab.forge.scirenderer.picking;
+
+/**
+ *
+ * Interface for a picking manager.
+ *
+ * @author Pierre Lando
+ */
+public interface PickingManager {
+
+ /**
+ * Add a picking task.
+ * @param pickingTask the new picking task.
+ */
+ void addPickingTask(PickingTask pickingTask);
+}
diff --git a/modules/scirenderer/src/org/scilab/forge/scirenderer/picking/PickingTask.java b/modules/scirenderer/src/org/scilab/forge/scirenderer/picking/PickingTask.java
new file mode 100755
index 000000000..7dacdfa69
--- /dev/null
+++ b/modules/scirenderer/src/org/scilab/forge/scirenderer/picking/PickingTask.java
@@ -0,0 +1,26 @@
+/*
+ * Scilab ( http://www.scilab.org/ ) - This file is part of Scilab
+ * Copyright (C) 2009-2011 - DIGITEO - Pierre Lando
+ *
+ * This file must be used under the terms of the CeCILL.
+ * This source file is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at
+ * http://www.cecill.info/licences/Licence_CeCILL_V2.1-en.txt
+ */
+
+package org.scilab.forge.scirenderer.picking;
+
+/**
+ * Interface for a picking task.
+ *
+ * @author Pierre Lando
+ */
+public interface PickingTask {
+
+ /**
+ * Call to perform the task.
+ * @param pickingTools the picking tools to use.
+ */
+ void perform(PickingTools pickingTools);
+}
diff --git a/modules/scirenderer/src/org/scilab/forge/scirenderer/picking/PickingTools.java b/modules/scirenderer/src/org/scilab/forge/scirenderer/picking/PickingTools.java
new file mode 100755
index 000000000..ee5892042
--- /dev/null
+++ b/modules/scirenderer/src/org/scilab/forge/scirenderer/picking/PickingTools.java
@@ -0,0 +1,38 @@
+/*
+ * Scilab ( http://www.scilab.org/ ) - This file is part of Scilab
+ * Copyright (C) 2009-2011 - DIGITEO - Pierre Lando
+ *
+ * This file must be used under the terms of the CeCILL.
+ * This source file is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at
+ * http://www.cecill.info/licences/Licence_CeCILL_V2.1-en.txt
+ */
+
+package org.scilab.forge.scirenderer.picking;
+
+import java.awt.Point;
+
+import org.scilab.forge.scirenderer.Canvas;
+import org.scilab.forge.scirenderer.tranformations.Vector3d;
+
+/**
+ * Interface for picking tools.
+ *
+ * @author Pierre Lando
+ */
+public interface PickingTools {
+
+ /**
+ * Return the scene coordinate of the pixel under the given windows position.
+ * @param windowPosition the given window position.
+ * @return the scene coordinate of the pixel under the given windows position.
+ */
+ Vector3d getUnderlyingPoint(Point windowPosition);
+
+ /**
+ * Return the canvas.
+ * @return the canvas.
+ */
+ Canvas getCanvas();
+}
diff --git a/modules/scirenderer/src/org/scilab/forge/scirenderer/renderer/Renderer.java b/modules/scirenderer/src/org/scilab/forge/scirenderer/renderer/Renderer.java
new file mode 100755
index 000000000..05a9dca33
--- /dev/null
+++ b/modules/scirenderer/src/org/scilab/forge/scirenderer/renderer/Renderer.java
@@ -0,0 +1,43 @@
+/*
+ * Scilab ( http://www.scilab.org/ ) - This file is part of Scilab
+ * Copyright (C) 2009-2011 - DIGITEO - Pierre Lando
+ *
+ * This file must be used under the terms of the CeCILL.
+ * This source file is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at
+ * http://www.cecill.info/licences/Licence_CeCILL_V2.1-en.txt
+ */
+
+package org.scilab.forge.scirenderer.renderer;
+
+import org.scilab.forge.scirenderer.Drawer;
+
+/**
+ *
+ * Interface for a renderer.
+ *
+ * A renderer is used to improve drawing performance.
+ * If you have an uge static object to draw at each frame, encapsulate his drawer in a renderer improve drawing performance.
+ *
+ * @author Pierre Lando
+ */
+public interface Renderer {
+
+ /**
+ * Set the drawer.
+ * @param drawer the new drawer.
+ */
+ void setDrawer(Drawer drawer);
+
+ /**
+ * Return the drawer.
+ * @return the drawer.
+ */
+ Drawer getDrawer();
+
+ /**
+ * Ask for reload.
+ */
+ void reload();
+}
diff --git a/modules/scirenderer/src/org/scilab/forge/scirenderer/renderer/RendererManager.java b/modules/scirenderer/src/org/scilab/forge/scirenderer/renderer/RendererManager.java
new file mode 100755
index 000000000..fde8ba995
--- /dev/null
+++ b/modules/scirenderer/src/org/scilab/forge/scirenderer/renderer/RendererManager.java
@@ -0,0 +1,33 @@
+/*
+ * Scilab ( http://www.scilab.org/ ) - This file is part of Scilab
+ * Copyright (C) 2009-2011 - DIGITEO - Pierre Lando
+ *
+ * This file must be used under the terms of the CeCILL.
+ * This source file is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at
+ * http://www.cecill.info/licences/Licence_CeCILL_V2.1-en.txt
+ */
+
+package org.scilab.forge.scirenderer.renderer;
+
+/**
+ *
+ * Interface for renderer manager.
+ *
+ * @author Pierre Lando
+ */
+public interface RendererManager {
+
+ /**
+ * Create a new renderer.
+ * @return a new renderer.
+ */
+ Renderer createRenderer();
+
+ /**
+ * Release all resources used by the given renderer.
+ * @param renderer the given renderer.
+ */
+ void dispose(Renderer renderer);
+}
diff --git a/modules/scirenderer/src/org/scilab/forge/scirenderer/ruler/DefaultRulerModel.java b/modules/scirenderer/src/org/scilab/forge/scirenderer/ruler/DefaultRulerModel.java
new file mode 100755
index 000000000..18b94c19f
--- /dev/null
+++ b/modules/scirenderer/src/org/scilab/forge/scirenderer/ruler/DefaultRulerModel.java
@@ -0,0 +1,436 @@
+/*
+ * Scilab ( http://www.scilab.org/ ) - This file is part of Scilab
+ * Copyright (C) 2009-2011 - DIGITEO - Pierre Lando
+ * Copyright (C) 2013 - Scilab Enterprises - Calixte DENIZET
+ *
+ * This file must be used under the terms of the CeCILL.
+ * This source file is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at
+ * http://www.cecill.info/licences/Licence_CeCILL_V2.1-en.txt
+ */
+
+package org.scilab.forge.scirenderer.ruler;
+
+import org.scilab.forge.scirenderer.ruler.graduations.Graduations;
+import org.scilab.forge.scirenderer.ruler.graduations.LinearGraduations;
+import org.scilab.forge.scirenderer.ruler.graduations.LogarithmicGraduations;
+import org.scilab.forge.scirenderer.shapes.appearance.Color;
+import org.scilab.forge.scirenderer.tranformations.Vector3d;
+
+/**
+ * Default ruler model.
+ *
+ * @author Pierre Lando
+ */
+public final class DefaultRulerModel implements RulerModel {
+
+ /**
+ * Value associated with the first point.
+ */
+ private double firstValue = DEFAULT_FIRST_VALUE;
+
+ /**
+ * Value associated with the second point.
+ */
+ private double secondValue = DEFAULT_SECOND_VALUE;
+
+ /**
+ * First point position in world coordinate.
+ */
+ private Vector3d firstPoint = DEFAULT_FIRST_POINT;
+
+ /**
+ * Second point position in world coordinate.
+ */
+ private Vector3d secondPoint = DEFAULT_SECOND_POINT;
+
+ /**
+ * Ticks direction, in world coordinate.
+ */
+ private Vector3d ticksDirection = DEFAULT_TICKS_DIRECTION;
+
+ /**
+ * Ticks length, in pixel.
+ */
+ private int ticksLength = DEFAULT_TICK_LENGTH;
+
+ /**
+ * Sub ticks length, in pixel.
+ */
+ private int subTicksLength = DEFAULT_SUB_TICK_LENGTH;
+
+ /**
+ * Minimal sub-ticks distance.
+ */
+ private double minimalSubTicksDistance = DEFAULT_MINIMAL_SUB_TICKS_DISTANCE;
+
+ /**
+ * Sprite distance to segment, in pixel.
+
+ */
+ private int spriteDistance = DEFAULT_SPRITE_DISTANCE;
+
+ /**
+ * The graduations.
+ */
+ private Graduations graduations;
+
+ /**
+ * Current margin.
+ * The margin is the minimal allowed distance between to sprite of the same ruler.
+ */
+ private double margin = DEFAULT_MARGIN;
+
+ /**
+ * Current line visibility.
+ */
+ private boolean lineVisible = DEFAULT_LINE_VISIBLE;
+
+ /**
+ * Auto-ticks status.
+ */
+ private boolean isAutoTicks = DEFAULT_AUTO_TICKS_STATUS;
+
+ /**
+ * Logarithmic status.
+ */
+ private boolean isLogarithmic = DEFAULT_LOGARITHMIC_STATUS;
+
+ /**
+ * Current color.
+ */
+ private Color color = DEFAULT_COLOR;
+
+ /**
+ * Used graduations when {@link this#isAutoTicks} is false.
+ */
+ private Graduations userGraduation;
+
+ /**
+ * Line width
+ */
+ private double lineWidth = DEFAULT_LINE_WIDTH;
+
+ private int subticksNumber = -1;
+ private String format = "";
+ private double scale;
+ private double translate;
+
+ /**
+ * Default constructor.
+ */
+ public DefaultRulerModel() {
+ }
+
+ @Override
+ public double getFirstValue() {
+ return firstValue;
+ }
+
+ /**
+ * First value setter.
+ * @param firstValue the new first value.
+ */
+ public void setFirstValue(double firstValue) {
+ graduations = null;
+ this.firstValue = (Double.isInfinite(firstValue) ? Double.MAX_VALUE : firstValue);
+ }
+
+ @Override
+ public double getSecondValue() {
+ return secondValue;
+ }
+
+ /**
+ * Second value setter.
+ * @param secondValue the new second value.
+ */
+ public void setSecondValue(double secondValue) {
+ graduations = null;
+ this.secondValue = (Double.isInfinite(secondValue) ? Double.MAX_VALUE : secondValue);
+ }
+
+ /**
+ * Set the first and second value in one call.
+ * @param firstValue the first value.
+ * @param secondValue the second value.
+ */
+ public void setValues(double firstValue, double secondValue) {
+ setFirstValue(firstValue);
+ setSecondValue(secondValue);
+ }
+
+ @Override
+ public Vector3d getFirstPoint() {
+ return firstPoint;
+ }
+
+ /**
+ * First point setter.
+ * @param firstPoint the new first point.
+ */
+ public void setFirstPoint(Vector3d firstPoint) {
+ this.firstPoint = firstPoint;
+ }
+
+ @Override
+ public Vector3d getSecondPoint() {
+ return secondPoint;
+ }
+
+ /**
+ * Second point setter.
+ * @param secondPoint the new second point.
+ */
+ public void setSecondPoint(Vector3d secondPoint) {
+ this.secondPoint = secondPoint;
+ }
+
+ /**
+ * Point setter.
+ * @param firstPoint the new first point.
+ * @param secondPoint the new second point.
+ */
+ public void setPoints(Vector3d firstPoint, Vector3d secondPoint) {
+ this.firstPoint = firstPoint;
+ this.secondPoint = secondPoint;
+ }
+
+ @Override
+ public Vector3d getTicksDirection() {
+ return ticksDirection;
+ }
+
+ /**
+ * Ticks direction setter.
+ * @param ticksDirection the new ticks direction.
+ */
+ public void setTicksDirection(Vector3d ticksDirection) {
+ this.ticksDirection = ticksDirection;
+ }
+
+ @Override
+ public int getTicksLength() {
+ return ticksLength;
+ }
+
+ /**
+ * Ticks length setter.
+ * @param ticksLength the new tick length in pixels.
+ */
+ public void setTicksLength(int ticksLength) {
+ this.ticksLength = ticksLength;
+ }
+
+ @Override
+ public int getSubTicksLength() {
+ return subTicksLength;
+ }
+
+ /**
+ * Sub-ticks length setter.
+ * @param subTicksLength the new sub-tick length in pixels.
+ */
+ public void setSubTicksLength(int subTicksLength) {
+ this.subTicksLength = subTicksLength;
+ }
+
+ @Override
+ public Graduations getGraduations() {
+ if (isAutoTicks) {
+ if (graduations == null) {
+ if (isLogarithmic) {
+ graduations = LogarithmicGraduations.create(getFirstValue(), getSecondValue());
+ } else {
+ graduations = LinearGraduations.create(getFirstValue(), getSecondValue());
+ }
+ }
+ return graduations;
+ } else {
+ return userGraduation;
+ }
+ }
+
+ /**
+ * User graduation setter.
+ * @param graduations the new user-defined graduations.
+ */
+ public void setUserGraduation(Graduations graduations) {
+ this.userGraduation = graduations;
+ }
+
+ @Override
+ public Vector3d getPosition(double value) {
+ if ((firstPoint != null) && (secondPoint != null)) {
+ if (isLogarithmic()) {
+ double valueLog = Math.log10(value);
+ double firstValueLog = Math.log10(firstValue);
+ double secondValueLog = Math.log10(secondValue);
+ double s = (secondValueLog - firstValueLog);
+ double k1 = (valueLog - firstValueLog) / s;
+ double k2 = (secondValueLog - valueLog) / s;
+ return firstPoint.times(k2).plus(secondPoint.times(k1));
+ } else {
+ double s = (secondValue - firstValue);
+ return firstPoint.times((secondValue - value) / s).plus(secondPoint.times((value - firstValue) / s));
+ }
+ } else {
+ return null;
+ }
+ }
+
+ @Override
+ public double getMargin() {
+ return margin;
+ }
+
+ /**
+ * Margin setter.
+ * The margin is minimal distance accepted between ticks labels.
+ * @param margin the new margin value.
+ */
+ public void setMargin(double margin) {
+ this.margin = margin;
+ }
+
+ @Override
+ public boolean isLineVisible() {
+ return lineVisible;
+ }
+
+ /**
+ * Line visibility setter.
+ * @param lineVisible the new line visibility status.
+ */
+ public void setLineVisible(boolean lineVisible) {
+ this.lineVisible = lineVisible;
+ }
+
+ @Override
+ public boolean isAutoTicks() {
+ return isAutoTicks;
+ }
+
+ /**
+ * Auto-ticks parameter setter.
+ * If it set to {@code false}, the user defined graduation will be used.
+ * @param isAutoTicks the new auto-ticks status.
+ */
+ public void setAutoTicks(boolean isAutoTicks) {
+ this.isAutoTicks = isAutoTicks;
+ }
+
+ @Override
+ public boolean isLogarithmic() {
+ return isLogarithmic;
+ }
+
+ /**
+ * Logarithmic or linear setter
+ * @param isLogarithmic the new logarithmic status.
+ */
+ public void setLogarithmic(boolean isLogarithmic) {
+ if (isLogarithmic != this.isLogarithmic) {
+ this.isLogarithmic = isLogarithmic;
+ graduations = null;
+ }
+ }
+
+ @Override
+ public int getSpriteDistance() {
+ return spriteDistance;
+ }
+
+ /**
+ * Sprite distance setter.
+ * @param spriteDistance the new sprite distance to the main ticks in pixel.
+ */
+ public void setSpriteDistance(int spriteDistance) {
+ this.spriteDistance = spriteDistance;
+ }
+
+ @Override
+ public double getMinimalSubTicksDistance() {
+ return minimalSubTicksDistance;
+ }
+
+ /**
+ * Minimal accepted distance between sub-ticks setter.
+ * @param minimalSubTicksDistance the new minimal accepted distance between sub-ticks.
+ */
+ public void setMinimalSubTicksDistance(double minimalSubTicksDistance) {
+ this.minimalSubTicksDistance = minimalSubTicksDistance;
+ }
+
+ @Override
+ public Color getColor() {
+ return color;
+ }
+
+ /**
+ * Ruler color setter.
+ * @param color the new rule color.
+ */
+ public void setColor(Color color) {
+ this.color = color;
+ }
+
+ @Override
+ public double getLineWidth() {
+ return lineWidth;
+ }
+
+ /**
+ * Ruler line width setter
+ * @param lineWidth the new line width
+ */
+ public void setLineWidth(double lineWidth) {
+ this.lineWidth = lineWidth;
+ }
+
+ @Override
+ public int getSubticksNumber() {
+ return subticksNumber;
+ }
+
+ /**
+ * Set number of subticks.
+ * @param N the number of subticks or -1 if the computation is automatic.
+ */
+ public void setSubticksNumber(int N) {
+ this.subticksNumber = N;
+ }
+
+ @Override
+ public String getFormat() {
+ return format;
+ }
+
+ /**
+ * Set the format.
+ * @param format the format as used in String.format.
+ */
+ public void setFormat(String format) {
+ this.format = format;
+ }
+
+ @Override
+ public double getScale() {
+ return scale;
+ }
+
+ @Override
+ public double getTranslate() {
+ return translate;
+ }
+
+ /**
+ * Set the scale-translate factors.
+ * @param .
+ */
+ public void setSTFactors(Double[] factors) {
+ this.scale = factors[0];
+ this.translate = factors[1];
+ }
+}
diff --git a/modules/scirenderer/src/org/scilab/forge/scirenderer/ruler/DefaultRulerSpriteFactory.java b/modules/scirenderer/src/org/scilab/forge/scirenderer/ruler/DefaultRulerSpriteFactory.java
new file mode 100755
index 000000000..ae709107a
--- /dev/null
+++ b/modules/scirenderer/src/org/scilab/forge/scirenderer/ruler/DefaultRulerSpriteFactory.java
@@ -0,0 +1,63 @@
+/*
+ * Scilab ( http://www.scilab.org/ ) - This file is part of Scilab
+ * Copyright (C) 2009-2011 - DIGITEO - Pierre Lando
+ *
+ * This file must be used under the terms of the CeCILL.
+ * This source file is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at
+ * http://www.cecill.info/licences/Licence_CeCILL_V2.1-en.txt
+ */
+
+package org.scilab.forge.scirenderer.ruler;
+
+import org.scilab.forge.scirenderer.shapes.appearance.Color;
+import org.scilab.forge.scirenderer.texture.TextEntity;
+import org.scilab.forge.scirenderer.texture.Texture;
+import org.scilab.forge.scirenderer.texture.TextureDrawer;
+import org.scilab.forge.scirenderer.texture.TextureDrawingTools;
+import org.scilab.forge.scirenderer.texture.TextureManager;
+
+import java.awt.Dimension;
+import java.text.DecimalFormat;
+
+/**
+ * @author Pierre Lando
+ */
+public final class DefaultRulerSpriteFactory implements RulerSpriteFactory {
+
+ /**
+ * Default constructor.
+ */
+ public DefaultRulerSpriteFactory() {
+ }
+
+ @Override
+ public Texture create(double value, DecimalFormat adaptedFormat, TextureManager textureManager) {
+ String text = adaptedFormat.format(value);
+ final TextEntity textEntity = new TextEntity(text);
+ textEntity.setTextColor(new Color(0, 0, 0));
+ textEntity.setTextAntiAliased(false);
+
+ Texture texture = textureManager.createTexture();
+ texture.setDrawer(new TextureDrawer() {
+
+ @Override
+ public void draw(TextureDrawingTools drawingTools) {
+ drawingTools.draw(textEntity, 0, 0);
+ }
+
+ @Override
+ public Dimension getTextureSize() {
+ return textEntity.getSize();
+ }
+
+ @Override
+ public OriginPosition getOriginPosition() {
+ return OriginPosition.UPPER_LEFT;
+ }
+ });
+
+ return texture;
+ }
+}
diff --git a/modules/scirenderer/src/org/scilab/forge/scirenderer/ruler/RulerDrawer.java b/modules/scirenderer/src/org/scilab/forge/scirenderer/ruler/RulerDrawer.java
new file mode 100755
index 000000000..dd7b88b61
--- /dev/null
+++ b/modules/scirenderer/src/org/scilab/forge/scirenderer/ruler/RulerDrawer.java
@@ -0,0 +1,726 @@
+/*
+ * Scilab ( http://www.scilab.org/ ) - This file is part of Scilab
+ * Copyright (C) 2009-2012 - DIGITEO - Pierre Lando
+ * Copyright (C) 2012 - Scilab Enterprises - Bruno JOFRET
+ * Copyright (C) 2013 - Scilab Enterprises - Calixte DENIZET
+ *
+ * This file must be used under the terms of the CeCILL.
+ * This source file is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at
+ * http://www.cecill.info/licences/Licence_CeCILL_V2.1-en.txt
+ */
+
+package org.scilab.forge.scirenderer.ruler;
+
+import java.awt.Dimension;
+import java.awt.geom.Rectangle2D;
+import java.nio.FloatBuffer;
+import java.text.DecimalFormat;
+import java.util.HashMap;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+
+import org.scilab.forge.scirenderer.DrawingTools;
+import org.scilab.forge.scirenderer.SciRendererException;
+import org.scilab.forge.scirenderer.buffers.BuffersManager;
+import org.scilab.forge.scirenderer.buffers.ElementsBuffer;
+import org.scilab.forge.scirenderer.ruler.graduations.Graduations;
+import org.scilab.forge.scirenderer.ruler.graduations.UserDefinedFormat;
+import org.scilab.forge.scirenderer.shapes.appearance.Appearance;
+import org.scilab.forge.scirenderer.shapes.geometry.DefaultGeometry;
+import org.scilab.forge.scirenderer.shapes.geometry.Geometry;
+import org.scilab.forge.scirenderer.texture.AnchorPosition;
+import org.scilab.forge.scirenderer.texture.Texture;
+import org.scilab.forge.scirenderer.texture.TextureManager;
+import org.scilab.forge.scirenderer.tranformations.Transformation;
+import org.scilab.forge.scirenderer.tranformations.Vector3d;
+
+/**
+ * @author Pierre Lando
+ */
+public class RulerDrawer {
+
+ /**
+ * Sprite map.
+ */
+ private final Map<Double, Texture> spriteMap = new ConcurrentHashMap<Double, Texture>();
+
+ /**
+ * The current {@link TextureManager}.
+ */
+ private final TextureManager textureManager;
+
+ /**
+ * The used {@link RulerSpriteFactory}.
+ */
+ private RulerSpriteFactory spriteFactory;
+
+ private OneShotRulerDrawer oneShotRulerDrawer;
+
+ /**
+ * Ruler drawer constructor.
+ * @param textureManager the {@link TextureManager} of the canvas where the ruler will be drawn.
+ */
+ public RulerDrawer(TextureManager textureManager) {
+ this.textureManager = textureManager;
+ this.spriteFactory = new DefaultRulerSpriteFactory();
+ this.oneShotRulerDrawer = new OneShotRulerDrawer();
+ }
+
+ /**
+ * Ruler drawing method.
+ * @param drawingTools the {@link DrawingTools} of the canvas where the ruler will be drawn.
+ * @param model the {@link RulerModel} of the drawn ruler.
+ * @return the {@link RulerDrawingResult} give information about how the ruler have been drawn.
+ */
+ public RulerDrawingResult draw(DrawingTools drawingTools, RulerModel model) {
+ return oneShotRulerDrawer.drawWithResults(drawingTools, model);
+ }
+
+ /**
+ * Get the sprite factory
+ * @return the sprite factory
+ */
+ public RulerSpriteFactory getSpriteFactory() {
+ return this.spriteFactory;
+ }
+
+ /**
+ * Draw the ruler
+ * @param drawingTools the {@link DrawingTools} of the canvas where the ruler will be drawn.
+ */
+ public void draw(DrawingTools drawingTools) {
+ oneShotRulerDrawer.draw(drawingTools);
+ }
+
+ /**
+ * Get the model
+ * @return the ruler model.
+ */
+ public RulerModel getModel() {
+ return oneShotRulerDrawer.rulerModel;
+ }
+
+ /**
+ * Get the subticks values
+ * @return the values.
+ */
+ public List<Double> getSubTicksValue() {
+ return oneShotRulerDrawer.subTicksValue;
+ }
+
+ /**
+ * Get the ticks values
+ * @return the values.
+ */
+ public List<Double> getTicksValue() {
+ return oneShotRulerDrawer.ticksValue;
+ }
+
+ /**
+ * Compute different parameters on a ruler
+ * @param rulerModel the {@link RulerModel} of the drawn ruler.
+ * @param canvasProjection the canvas projection.
+ */
+ public RulerDrawingResult computeRuler(RulerModel model, Transformation canvasProjection) {
+ return oneShotRulerDrawer.computeRuler(model, canvasProjection);
+ }
+
+ /**
+ * Set the current {@link RulerSpriteFactory}.
+ * All existing sprite will be cleared.
+ * This ruler drawer will use the new {@link RulerSpriteFactory}.
+ * @param spriteFactory the new {@link RulerSpriteFactory}.
+ */
+ public void setSpriteFactory(RulerSpriteFactory spriteFactory) {
+ disposeResources();
+ this.spriteFactory = spriteFactory;
+ }
+
+ /**
+ * Dispose all used resources.
+ */
+ public void disposeResources() {
+ textureManager.dispose(spriteMap.values());
+ spriteMap.clear();
+ oneShotRulerDrawer.dispose();
+ }
+
+ public double getDistanceRatio() {
+ return oneShotRulerDrawer.getDistanceRatio();
+ }
+
+ /**
+ * This class actually perform all the rendering of one ruler.
+ */
+ private class OneShotRulerDrawer {
+
+ private Transformation canvasProjection;
+ private RulerModel rulerModel;
+ private Vector3d windowSubTicksDelta;
+ private Vector3d windowTicksDelta;
+
+ /**
+ * Sprite Dimension map. Used as cached values in order not to charge DataProvider.
+ */
+ private Map<Double, Dimension> spriteDimensionMap = new HashMap<Double, Dimension>();
+
+ private List<PositionedSprite> spritesList = new LinkedList<PositionedSprite>();
+
+ /**
+ * The maximum distance corresponding to the actually displayed sprites.
+ */
+ private double maximalSpritesDistance;
+
+ /**
+ * Deepest possible {@see Graduations}
+ */
+ private Graduations graduations;
+
+ private List<Double> subTicksValue;
+ private List<Double> ticksValue;
+ private int density;
+ private double distRatio;
+
+ public OneShotRulerDrawer() { }
+
+ public synchronized void dispose() {
+ spriteDimensionMap.clear();
+ spritesList.clear();
+ if (subTicksValue != null) {
+ subTicksValue.clear();
+ }
+ if (ticksValue != null) {
+ ticksValue.clear();
+ }
+ rulerModel = null;
+ }
+
+ public double getDistanceRatio() {
+ return distRatio;
+ }
+
+ /**
+ * Compute different parameters on a ruler
+ * @param drawingTools the {@link DrawingTools} of the canvas where the ruler will be drawn.
+ * @param rulerModel the {@link RulerModel} of the drawn ruler.
+ * @param canvasProjection the canvas projection.
+ */
+ public synchronized RulerDrawingResult computeRuler(RulerModel rulerModel, Transformation canvasProjection) {
+ // Same code as drawWithResults (without drawing)
+ // Historically, computations were made when drawing and they are made before drawing.
+ // TODO: remove drawWithResults ??
+ this.canvasProjection = canvasProjection;
+ this.rulerModel = rulerModel;
+ subTicksValue = new LinkedList<Double>();
+ ticksValue = new LinkedList<Double>();
+ spritesList = new LinkedList<PositionedSprite>();
+
+ Vector3d windowTicksDirection = canvasProjection.projectDirection(rulerModel.getTicksDirection());
+ windowTicksDirection = windowTicksDirection.setZ(0);
+
+ Vector3d normalizedProjectedTicksDirection = windowTicksDirection.getNormalized();
+ windowSubTicksDelta = normalizedProjectedTicksDirection.times(rulerModel.getSubTicksLength());
+ windowTicksDelta = normalizedProjectedTicksDirection.times(rulerModel.getTicksLength());
+
+ DecimalFormat format;
+ if (rulerModel.isAutoTicks()) {
+ format = computeAutoGraduation();
+ } else {
+ format = computeUserGraduation();
+ }
+ computeTicksData();
+
+ double distRatio = computeTicksDistanceRatio(windowTicksDirection.getNorm());
+
+ return new RulerDrawingResult(format, ticksValue, subTicksValue, density, distRatio, normalizedProjectedTicksDirection);
+ }
+
+ /**
+ * Constructor.
+ * @param drawingTools the {@link DrawingTools} of the canvas where the ruler will be drawn.
+ * @param rulerModel the {@link RulerModel} of the drawn ruler.
+ */
+ public synchronized RulerDrawingResult drawWithResults(DrawingTools drawingTools, RulerModel rulerModel) {
+ this.rulerModel = rulerModel;
+ subTicksValue = new LinkedList<Double>();
+ ticksValue = new LinkedList<Double>();
+ spritesList = new LinkedList<PositionedSprite>();
+ canvasProjection = drawingTools.getTransformationManager().getCanvasProjection();
+
+ Vector3d windowTicksDirection = canvasProjection.projectDirection(rulerModel.getTicksDirection());
+ windowTicksDirection = windowTicksDirection.setZ(0);
+
+ Vector3d normalizedProjectedTicksDirection = windowTicksDirection.getNormalized();
+ windowSubTicksDelta = normalizedProjectedTicksDirection.times(rulerModel.getSubTicksLength());
+ windowTicksDelta = normalizedProjectedTicksDirection.times(rulerModel.getTicksLength());
+
+ DecimalFormat format;
+ if (rulerModel.isAutoTicks()) {
+ format = computeAutoGraduation();
+ } else {
+ format = computeUserGraduation();
+ }
+ computeTicksData();
+
+ draw(drawingTools);
+
+ double distRatio = computeTicksDistanceRatio(windowTicksDirection.getNorm());
+
+ return new RulerDrawingResult(format, ticksValue, subTicksValue, density, distRatio, normalizedProjectedTicksDirection);
+ }
+
+ /**
+ * Compute the ratio between windows ticks norm and the sprite distance.
+ * @param windowTicksNorm the windows tics norm.
+ * @return the ratio between windows ticks norm and the sprite distance.
+ */
+ private double computeTicksDistanceRatio(double windowTicksNorm) {
+ if (windowTicksNorm == 0) {
+ distRatio = 1.0;
+ } else if (maximalSpritesDistance == 0) {
+ distRatio = rulerModel.getSpriteDistance() / windowTicksNorm;
+ } else {
+ distRatio = maximalSpritesDistance / windowTicksNorm;
+ }
+ return distRatio;
+ }
+
+ /**
+ * Actually perform the ruler drawing.
+ * @param drawingTools {@link DrawingTools} used to perform the ruler drawing.
+ */
+ private synchronized void draw(DrawingTools drawingTools) {
+ if (rulerModel == null) {
+ return;
+ }
+
+ BuffersManager bufferManager = drawingTools.getCanvas().getBuffersManager();
+ ElementsBuffer vertices = bufferManager.createElementsBuffer();
+ fillVertices(vertices, rulerModel, ticksValue, subTicksValue, canvasProjection);
+ DefaultGeometry geometry = new DefaultGeometry();
+ geometry.setFillDrawingMode(Geometry.FillDrawingMode.NONE);
+ geometry.setLineDrawingMode(Geometry.LineDrawingMode.SEGMENTS);
+ geometry.setVertices(vertices);
+
+ Appearance appearance = new Appearance();
+ appearance.setLineColor(rulerModel.getColor());
+ appearance.setLineWidth((float) rulerModel.getLineWidth());
+
+ drawingTools.getTransformationManager().useWindowCoordinate();
+ try {
+ for (PositionedSprite positionedSprite : spritesList) {
+ drawingTools.draw(positionedSprite.getSprite(), AnchorPosition.CENTER, positionedSprite.getWindowPosition());
+ }
+ drawingTools.draw(geometry, appearance);
+ } catch (SciRendererException ignored) {
+ }
+ drawingTools.getTransformationManager().useSceneCoordinate();
+ bufferManager.dispose(vertices);
+ }
+
+ /**
+ * Compute the {@link Graduations} used to the ruler drawing in auto-ticks mode..
+ * @return the used decimal format.
+ */
+ private DecimalFormat computeAutoGraduation() {
+ /* The maximum distance corresponding to the actually displayed sprites. */
+ double maxSpritesDistance = 0.0;
+
+ Graduations currentGraduations = rulerModel.getGraduations();
+ Graduations ticksGraduation = currentGraduations;
+ DecimalFormat format = currentGraduations.getFormat();
+ String f = rulerModel.getFormat();
+ if (f != null && !f.isEmpty()) {
+ format = new UserDefinedFormat(format, f, rulerModel.getScale(), rulerModel.getTranslate());
+ }
+
+ boolean canGetMore = true;
+ List<PositionedSprite> newSpritesList = new LinkedList<PositionedSprite>();
+ while (currentGraduations != null) {
+ /* The maximum distance to any of the sprites' farthest sides at a given iteration. */
+ double currentMaximalSpritesDistance = 0;
+
+ newSpritesList.clear();
+ List<Double> ticks = currentGraduations.getNewValues();
+ for (double value : ticks) {
+ Texture sprite = computeSprite(value, format);
+ Vector3d windowPosition = canvasProjection.project(rulerModel.getPosition(value));
+
+ // X != X means NaN so we are not able to project coordinates
+ // return basic format
+ if (windowPosition.getX() != windowPosition.getX()) {
+ return format;
+ }
+
+ Dimension textureSize = computeSpriteDimension(value);
+
+ Vector3d delta = projectCenterToEdge(textureSize, windowTicksDelta);
+ PositionedSprite newSprite = new PositionedSprite(sprite, textureSize, windowPosition.plus(windowTicksDelta.plus(delta)));
+ newSpritesList.add(newSprite);
+ Vector3d farDelta = windowTicksDelta.plus(delta.times(2.0));
+ currentMaximalSpritesDistance = Math.max(currentMaximalSpritesDistance, farDelta.getNorm());
+ }
+
+ if (collide(newSpritesList, rulerModel.getMargin()) || collide(spritesList, newSpritesList, rulerModel.getMargin())) {
+ currentGraduations = currentGraduations.getAlternative();
+ canGetMore = false;
+ } else {
+ maxSpritesDistance = Math.max(maxSpritesDistance, currentMaximalSpritesDistance);
+ spritesList.addAll(newSpritesList);
+ ticksGraduation = currentGraduations;
+ if (canGetMore) {
+ currentGraduations = currentGraduations.getMore();
+ } else {
+ currentGraduations = null;
+ }
+ }
+ }
+
+ this.graduations = ticksGraduation;
+ this.maximalSpritesDistance = maxSpritesDistance;
+
+ return format;
+ }
+
+ /**
+ * Compute the {@link Graduations} used to the ruler drawing in auto-ticks mode..
+ * @return the used decimal format.
+ */
+ private DecimalFormat computeUserGraduation() {
+ /* The maximum distance corresponding to the actually displayed sprites. */
+ double maxSpritesDistance = 0.0;
+ Graduations currentGraduations = rulerModel.getGraduations();
+
+ List<Double> ticks = currentGraduations.getNewValues();
+ DecimalFormat format = currentGraduations.getFormat();
+ for (double value : ticks) {
+ Texture sprite = computeSprite(value, format);
+ if (sprite != null) {
+ Vector3d windowPosition = canvasProjection.project(rulerModel.getPosition(value));
+
+ Vector3d delta = projectCenterToEdge(sprite, windowTicksDelta);
+ spritesList.add(new PositionedSprite(sprite, windowPosition.plus(windowTicksDelta.plus(delta))));
+
+ Vector3d farDelta = windowTicksDelta.plus(delta.times(2.0));
+ maxSpritesDistance = Math.max(maxSpritesDistance, farDelta.getNorm());
+ }
+ }
+
+ this.graduations = currentGraduations;
+ this.maximalSpritesDistance = maxSpritesDistance;
+ return format;
+ }
+
+ /**
+ * Compute the ticks, sub-ticks data and the sub-ticks density.
+ */
+ private void computeTicksData() {
+ if (graduations != null) {
+ ticksValue = graduations.getAllValues();
+ final int N = rulerModel.getSubticksNumber();
+
+ if (N < 0) {
+ Graduations subGraduation = graduations.getSubGraduations();
+ while ((subGraduation != null) && (computeTicksDistance(subGraduation) < rulerModel.getMinimalSubTicksDistance())) {
+ subGraduation = subGraduation.getAlternative();
+ }
+
+ if (subGraduation != null) {
+ subTicksValue = subGraduation.getAllValues();
+ } else {
+ subTicksValue = new LinkedList<Double>();
+ }
+ } else {
+ subTicksValue = graduations.getSubGraduations(N);
+ }
+ density = getDensity();
+ } else {
+ subTicksValue = new LinkedList<Double>();
+ ticksValue = new LinkedList<Double>();
+ density = 0;
+ }
+ }
+
+ private int getDensity() {
+ int N = ticksValue == null ? 0 : ticksValue.size();
+ int M = subTicksValue == null ? 0 : subTicksValue.size();
+
+ if (M <= N || N == 1) {
+ return 0;
+ }
+
+ return (M - N) / (N - 1);
+ }
+
+ /**
+ * Compute and return the minimal screen distance between two successive ticks of the given {@link Graduations}.
+ * If the given {@link Graduations} is <code>null</code>, the returned value is {@link Double#MAX_VALUE}.
+ * @param graduations the given {@link Graduations}.
+ * @return the minimal screen distance between two successive ticks of the given {@link Graduations}.
+ */
+ private double computeTicksDistance(Graduations graduations) {
+ double minimalDistance = Double.MAX_VALUE;
+ if (graduations != null) {
+ Vector3d previousProjection = null;
+ for (double currentValue : graduations.getAllValues()) {
+ Vector3d currentProjection = canvasProjection.project(rulerModel.getPosition(currentValue));
+ if (previousProjection != null) {
+ minimalDistance = Math.min(minimalDistance, currentProjection.minus(previousProjection).getNorm2());
+ }
+ previousProjection = currentProjection;
+ }
+ minimalDistance = Math.sqrt(minimalDistance);
+ }
+ return minimalDistance;
+ }
+
+ /**
+ * Return true if at leas two element of {@see spritesList} collide.
+ * @param spritesList the list of sprite to be tested.
+ * @param margin the collision margin.
+ * @return true if at leas two element of {@see spritesList} collide.
+ */
+ private boolean collide(List<PositionedSprite> spritesList, double margin) {
+ for (int i = 0; i < spritesList.size(); i++) {
+ Rectangle2D bounds = spritesList.get(i).getWindowBounds();
+ for (int j = i + 1; j < spritesList.size(); j++) {
+ if (collide(bounds, spritesList.get(j).getWindowBounds(), margin)) {
+ return true;
+ }
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Return true if the at least one element of <code>newSpritesList</code> collides with one element of <code>spritesList</code>.
+ * @param spritesList the list of reference sprites.
+ * @param newSpritesList the list of new sprites.
+ * @param margin the collision margin.
+ * @return true if the at least one element of <code>newSpritesList</code> collides with one element of <code>spritesList</code>.
+ */
+ private boolean collide(List<PositionedSprite> spritesList, List<PositionedSprite> newSpritesList, double margin) {
+ for (PositionedSprite sprite1 : newSpritesList) {
+ Rectangle2D bounds = sprite1.getWindowBounds();
+ for (PositionedSprite sprite2 : spritesList) {
+ if (collide(bounds, sprite2.getWindowBounds(), margin)) {
+ return true;
+ }
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Return true if the givens rectangles collide.
+ * @param rectangle1 first rectangle.
+ * @param rectangle2 second rectangle.
+ * @param margin the margin.
+ * @return true if the givens rectangles collide.
+ */
+ private boolean collide(Rectangle2D rectangle1, Rectangle2D rectangle2, double margin) {
+ return ((rectangle2.getMinX() - rectangle1.getMaxX()) < margin)
+ && ((rectangle1.getMinX() - rectangle2.getMaxX()) < margin)
+ && ((rectangle2.getMinY() - rectangle1.getMaxY()) < margin)
+ && ((rectangle1.getMinY() - rectangle2.getMaxY()) < margin);
+ }
+
+ /**
+ * Compute and return a translation along the given <code>direction</code>.
+ * This translation is the vector between the <code>sprite</code> center and is projection along the given
+ * {@see direction} to the sprite edges.
+ * @param sprite the given {@link Texture}
+ * @param direction the given direction.
+ * @return the vector between the sprite center and is projection to the sprite edges.
+ */
+ private Vector3d projectCenterToEdge(Texture sprite, Vector3d direction) {
+ Vector3d usedDirection;
+ if ((direction == null) || (direction.isZero())) {
+ usedDirection = new Vector3d(1, 0, 0);
+ } else {
+ usedDirection = direction;
+ }
+
+ /* +1 is used to have a space between the tick and its label */
+ Dimension textureSize = sprite.getDataProvider().getTextureSize();
+ double ratioX = textureSize.width / Math.abs(usedDirection.getX());
+ double ratioY = textureSize.height / Math.abs(usedDirection.getY());
+ double ratio = Math.min(ratioY, ratioX);
+
+ return usedDirection.times((ratio + 1) / 2);
+ }
+
+ /**
+ * Compute and return a translation along the given <code>direction</code>.
+ * This translation is the vector between the <code>sprite</code> center and is projection along the given
+ * {@see direction} to the sprite edges.
+ * @param textureSize the size of corresponding texture
+ * @param direction the given direction.
+ * @return the vector between the sprite center and is projection to the sprite edges.
+ */
+ private Vector3d projectCenterToEdge(Dimension textureSize, Vector3d direction) {
+ Vector3d usedDirection;
+ if ((direction == null) || (direction.isZero())) {
+ usedDirection = new Vector3d(1, 0, 0);
+ } else {
+ usedDirection = direction;
+ }
+
+ double ratioX = textureSize.width / Math.abs(usedDirection.getX());
+ double ratioY = textureSize.height / Math.abs(usedDirection.getY());
+ double ratio = Math.min(ratioY, ratioX);
+
+ return usedDirection.times((ratio + 1) / 2);
+ }
+
+ /**
+ * Fill a vertices buffer with the needed data to draw a ruler.
+ * @param verticesBuffer the {@link ElementsBuffer} to fill.
+ * @param rulerModel the {@link RulerModel} to draw.
+ * @param ticksValue the list of ticks.
+ * @param subTicksValue the list of sub-ticks.
+ * @param canvasProjection the used canvas projection.
+ */
+ private void fillVertices(ElementsBuffer verticesBuffer, RulerModel rulerModel, List<Double> ticksValue, List<Double> subTicksValue, Transformation canvasProjection) {
+ Vector3d a = rulerModel.getFirstPoint();
+ Vector3d b = rulerModel.getSecondPoint();
+
+ if ((a != null) && (b != null)) {
+ int bufferSize = 2 * ticksValue.size() + 2 * subTicksValue.size();
+ if (rulerModel.isLineVisible()) {
+ bufferSize += 2;
+ }
+ FloatBuffer data = FloatBuffer.allocate(4 * bufferSize);
+ data.rewind();
+
+ for (double value : ticksValue) {
+ Vector3d p = canvasProjection.project(rulerModel.getPosition(value));
+ data.put(p.getDataAsFloatArray(4));
+ data.put(p.plus(windowTicksDelta).getDataAsFloatArray(4));
+ }
+
+ for (double value : subTicksValue) {
+ Vector3d p = canvasProjection.project(rulerModel.getPosition(value));
+ data.put(p.getDataAsFloatArray(4));
+ data.put(p.plus(windowSubTicksDelta).getDataAsFloatArray(4));
+ }
+
+ if (rulerModel.isLineVisible()) {
+ data.put(canvasProjection.project(a).getDataAsFloatArray(4));
+ data.put(canvasProjection.project(b).getDataAsFloatArray(4));
+ }
+
+ data.rewind();
+ verticesBuffer.setData(data, 4);
+ } else {
+ verticesBuffer.setData(new float[0], 4);
+ }
+ }
+
+ /**
+ * Compute the {@link Texture} for a given value.
+ * The {@link Texture} is made once using the current {@link RulerSpriteFactory}.
+ * @param value the given value.
+ * @param format the format to use.
+ * @return A {@link Texture} for the label at the given value.
+ */
+ private Texture computeSprite(double value, DecimalFormat format) {
+ Texture sprite = spriteMap.get(value);
+ if (sprite == null) {
+ sprite = spriteFactory.create(value, format, textureManager);
+ if (sprite != null) {
+ spriteMap.put(value, sprite);
+ }
+ }
+ return sprite;
+ }
+
+ private Dimension computeSpriteDimension(double value) {
+ Dimension spriteDimension = spriteDimensionMap.get(value);
+ if (spriteDimension == null) {
+ Texture sprite = spriteMap.get(value);
+ if (sprite != null) {
+ spriteDimension = sprite.getDataProvider().getTextureSize();
+ spriteDimensionMap.put(value, spriteDimension);
+ }
+ }
+
+ return spriteDimension;
+ }
+
+ /**
+ * This class is a basic container for a {@link Texture} and an associated window position.
+ *
+ * @author Pierre Lando
+ */
+ private class PositionedSprite {
+
+ private final Texture sprite;
+ private final Vector3d windowPosition;
+ private final Rectangle2D windowsBounds;
+
+ /**
+ * Default constructor.
+ * @param sprite the {@link Texture}.
+ * @param windowPosition the window position.
+ */
+ public PositionedSprite(Texture sprite, Vector3d windowPosition) {
+ //long tic = Calendar.getInstance().getTimeInMillis();
+ this.windowPosition = windowPosition;
+ this.sprite = sprite;
+
+ Dimension textureSize = sprite.getDataProvider().getTextureSize();
+ windowsBounds = new Rectangle2D.Double(
+ windowPosition.getX(),
+ windowPosition.getY(),
+ textureSize.width,
+ textureSize.height
+ );
+
+ //System.err.println("====[new PositionedSprite] time = "+(Calendar.getInstance().getTimeInMillis() - tic));
+ }
+
+ public PositionedSprite(Texture sprite, Dimension textureSize, Vector3d windowPosition) {
+ //long tic = Calendar.getInstance().getTimeInMillis();
+ this.windowPosition = windowPosition;
+ this.sprite = sprite;
+
+ windowsBounds = new Rectangle2D.Double(
+ windowPosition.getX(),
+ windowPosition.getY(),
+ textureSize.width,
+ textureSize.height
+ );
+
+ //System.err.println("====[new PositionedSprite] time = "+(Calendar.getInstance().getTimeInMillis() - tic));
+ }
+ /**
+ * Return the {@link Texture}
+ * @return the {@link Texture}
+ */
+ public Texture getSprite() {
+ return sprite;
+ }
+
+ /**
+ * Return the window position of the {@link Texture}.
+ * @return the window position of the {@link Texture}.
+ */
+ public Vector3d getWindowPosition() {
+ return windowPosition;
+ }
+
+ /**
+ * Return the window bounds of the {@link Texture}
+ * @return the window bounds of the {@link Texture}
+ */
+ public Rectangle2D getWindowBounds() {
+ return windowsBounds;
+ }
+ }
+ }
+}
diff --git a/modules/scirenderer/src/org/scilab/forge/scirenderer/ruler/RulerDrawingResult.java b/modules/scirenderer/src/org/scilab/forge/scirenderer/ruler/RulerDrawingResult.java
new file mode 100755
index 000000000..8c0da2b05
--- /dev/null
+++ b/modules/scirenderer/src/org/scilab/forge/scirenderer/ruler/RulerDrawingResult.java
@@ -0,0 +1,136 @@
+/*
+ * Scilab ( http://www.scilab.org/ ) - This file is part of Scilab
+ * Copyright (C) 2009-2011 - DIGITEO - Pierre Lando
+ *
+ * This file must be used under the terms of the CeCILL.
+ * This source file is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at
+ * http://www.cecill.info/licences/Licence_CeCILL_V2.1-en.txt
+ */
+
+package org.scilab.forge.scirenderer.ruler;
+
+import org.scilab.forge.scirenderer.tranformations.Vector3d;
+
+import java.text.DecimalFormat;
+import java.util.List;
+
+/**
+ * Contain information about the ruler drawing result.
+ *
+ * @author Pierre Lando
+ */
+public class RulerDrawingResult {
+
+ /**
+ * Values of drawn ticks.
+ */
+ private final double[] ticksValues;
+
+ /**
+ * Values of drawn sub-ticks.
+ */
+ private final double[] subTicksValues;
+
+ /**
+ * Sub-ticks density.
+ */
+ private final int subTicksDensity;
+
+ /**
+ * The ratio between the maximum distance to any of the sprites' farthest sides
+ * along the projected ticks direction and the projected ticks direction norm.
+ */
+ private final double maxDistToTicksDirNorm;
+
+ /**
+ * The normalized projected ticks direction.
+ */
+ private final Vector3d normalizedTicksDirection;
+
+ /** The used format to draw sprites */
+ private final DecimalFormat format;
+
+ /**
+ * Package constructor.
+ * Those object can only be created by a {@link RulerDrawer}
+ *
+ * @param format
+ * @param ticksValues values of drawn ticks.
+ * @param subTicksValues values of drawn sub-ticks.
+ * @param subTicksDensity sub-ticks density.
+ * @param maxDistToTicksDirNorm the ratio between the maximum sprite distance and the projected ticks direction norm.
+ * @param ticksDir the normalized projected ticks direction.
+ */
+ RulerDrawingResult(DecimalFormat format, List<Double> ticksValues, List<Double> subTicksValues, int subTicksDensity, double maxDistToTicksDirNorm, Vector3d ticksDir) {
+ this.format = format;
+ this.ticksValues = listToArray(ticksValues);
+ this.subTicksValues = listToArray(subTicksValues);
+ this.subTicksDensity = subTicksDensity;
+ this.maxDistToTicksDirNorm = maxDistToTicksDirNorm;
+ this.normalizedTicksDirection = new Vector3d(ticksDir);
+ }
+
+ /**
+ * Format getter
+ * @return the format.
+ */
+ public DecimalFormat getFormat() {
+ return format;
+ }
+
+ /**
+ * Convert a list of Double to an array of double.
+ * @param list the given list.
+ * @return an array of double with the value of the given list.
+ */
+ private double[] listToArray(List<Double> list) {
+ double[] array = new double[list.size()];
+ int index = 0;
+ for (double value : list) {
+ array[index++] = value;
+ }
+ return array;
+ }
+
+ /**
+ * Drawn ticks values getter.
+ * @return the drawn ticks values.
+ */
+ public double[] getTicksValues() {
+ return ticksValues.clone();
+ }
+
+ /**
+ * Drawn sub-ticks values getter.
+ * @return the drawn sub-ticks values.
+ */
+ public double[] getSubTicksValues() {
+ return subTicksValues.clone();
+ }
+
+ /**
+ * Drawn sub-ticks density getter.
+ * @return the drawn sub-ticks density.
+ */
+ public int getSubTicksDensity() {
+ return subTicksDensity;
+ }
+
+ /**
+ * Maximum sprite distance to projected ticks direction norm ratio getter.
+ * @return the distance to ticks direction norm ratio.
+ */
+ public double getMaxDistToTicksDirNorm() {
+ return maxDistToTicksDirNorm;
+ }
+
+ /**
+ * Normalized projected ticks direction getter.
+ * @return the normalized projected ticks direction.
+ */
+ public Vector3d getNormalizedTicksDirection() {
+ return normalizedTicksDirection;
+ }
+}
diff --git a/modules/scirenderer/src/org/scilab/forge/scirenderer/ruler/RulerModel.java b/modules/scirenderer/src/org/scilab/forge/scirenderer/ruler/RulerModel.java
new file mode 100755
index 000000000..baaa86919
--- /dev/null
+++ b/modules/scirenderer/src/org/scilab/forge/scirenderer/ruler/RulerModel.java
@@ -0,0 +1,225 @@
+/*
+ * Scilab ( http://www.scilab.org/ ) - This file is part of Scilab
+ * Copyright (C) 2009-2012 - DIGITEO - Pierre Lando
+ * Copyright (C) 2013 - Scilab Enterprises - Calixte DENIZET
+ *
+ * This file must be used under the terms of the CeCILL.
+ * This source file is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at
+ * http://www.cecill.info/licences/Licence_CeCILL_V2.1-en.txt
+ */
+
+package org.scilab.forge.scirenderer.ruler;
+
+import org.scilab.forge.scirenderer.ruler.graduations.Graduations;
+import org.scilab.forge.scirenderer.shapes.appearance.Color;
+import org.scilab.forge.scirenderer.tranformations.Vector3d;
+
+/**
+ * @author Pierre Lando
+ */
+public interface RulerModel {
+
+ /**
+ * Default first value.
+ */
+ double DEFAULT_FIRST_VALUE = 0;
+
+ /**
+ * Default second value.
+ */
+ double DEFAULT_SECOND_VALUE = 1;
+
+ /**
+ * Default first point position.
+ */
+ Vector3d DEFAULT_FIRST_POINT = new Vector3d(0, 0, 0);
+
+ /**
+ * Default second point position.
+ */
+ Vector3d DEFAULT_SECOND_POINT = new Vector3d(1, 0, 0);
+
+ /**
+ * Default margin in pixel.
+ */
+ double DEFAULT_MARGIN = 12.0;
+
+ /**
+ * Default main line visibility.
+ */
+ boolean DEFAULT_LINE_VISIBLE = true;
+
+ /**
+ * Default {@link org.scilab.forge.scirenderer.sprite.Sprite} distance to the main line in pixel.
+ */
+ int DEFAULT_SPRITE_DISTANCE = 12;
+
+ /**
+ * Default sub-tick length in pixel.
+ */
+ int DEFAULT_SUB_TICK_LENGTH = 5;
+
+ /**
+ * Default tick length in pixel.
+ */
+ int DEFAULT_TICK_LENGTH = 10;
+
+ /**
+ * Default minimal sub-ticks distance.
+ */
+ double DEFAULT_MINIMAL_SUB_TICKS_DISTANCE = 8;
+
+ /**
+ * Default auto-ticks status.
+ */
+ boolean DEFAULT_AUTO_TICKS_STATUS = true;
+
+ /**
+ * Default logarithmic status.
+ */
+ boolean DEFAULT_LOGARITHMIC_STATUS = false;
+
+ /**
+ * Default ticks direction.
+ */
+ Vector3d DEFAULT_TICKS_DIRECTION = new Vector3d(1, 0, 0);
+
+ /**
+ * Default color.
+ */
+ Color DEFAULT_COLOR = new Color(0, 0, 0);
+
+ /**
+ * Default line width.
+ */
+ double DEFAULT_LINE_WIDTH = 1.0;
+
+ /**
+ * Return used graduation to draw this ruler.
+ * @return the used graduation to draw this ruler.
+ */
+ Graduations getGraduations();
+
+ /**
+ * First value getter.
+ * @return the first values.
+ */
+ double getFirstValue();
+
+ /**
+ * Second value getter.
+ * @return the second values.
+ */
+ double getSecondValue();
+
+ /**
+ * First point getter.
+ * @return the first point.
+ */
+ Vector3d getFirstPoint();
+
+ /**
+ * Second point getter.
+ * @return the second point.
+ */
+ Vector3d getSecondPoint();
+
+ /**
+ * Ticks direction getter.
+ * @return the ticks direction.
+ */
+ Vector3d getTicksDirection();
+
+ /**
+ * Ticks length getter.
+ * @return the ticks length in pixel.
+ */
+ int getTicksLength();
+
+ /**
+ * Sub-ticks length getter.
+ * @return the sub-ticks length in pixel.
+ */
+ int getSubTicksLength();
+
+ /**
+ * Return the position corresponding to the given value.
+ * @param value the given value.
+ * @return the position corresponding to the given value.
+ */
+ Vector3d getPosition(double value);
+
+ /**
+ * Return the accepted margin (in pixel) for label drawing.
+ * @return the accepted margin (in pixel) for label drawing.
+ */
+ double getMargin();
+
+ /**
+ * Line visibility getter.
+ * @return the line visibility status.
+ */
+ boolean isLineVisible();
+
+ /**
+ * Auto-ticking getter.
+ * @return the auto-ticking status.
+ */
+ boolean isAutoTicks();
+
+ /**
+ * Logarithmic state getter.
+ * @return the logarithmic state
+ */
+ boolean isLogarithmic();
+
+ /**
+ * Sprite distance getter.
+ * @return the sprite distance (in pixel) between the ruler line and the sprites edges.
+ */
+ int getSpriteDistance();
+
+ /**
+ * Minimal accepted sub-ticks distance getter.
+ * @return the minimal accepted sub-ticks distance.
+ */
+ double getMinimalSubTicksDistance();
+
+ /**
+ * Color getter.
+ * @return the color of ruler line and ticks.
+ */
+ Color getColor();
+
+ /**
+ * Line width getter.
+ * @return the line width of ruler line, grid and ticks.
+ */
+ double getLineWidth();
+
+ /**
+ * Number of subticks.
+ * @return the number of subticks or -1 if the computation is automatic.
+ */
+ int getSubticksNumber();
+
+ /**
+ * Get the format to print the ticks label
+ * @return the format
+ */
+ String getFormat();
+
+ /**
+ * Get the scale factor to recompute label value
+ * @return the scale factor
+ */
+ double getScale();
+
+ /**
+ * Get the translate factor to recompute label value
+ * @return the translate factor
+ */
+ double getTranslate();
+}
diff --git a/modules/scirenderer/src/org/scilab/forge/scirenderer/ruler/RulerSpriteFactory.java b/modules/scirenderer/src/org/scilab/forge/scirenderer/ruler/RulerSpriteFactory.java
new file mode 100755
index 000000000..44a45596f
--- /dev/null
+++ b/modules/scirenderer/src/org/scilab/forge/scirenderer/ruler/RulerSpriteFactory.java
@@ -0,0 +1,32 @@
+/*
+ * Scilab ( http://www.scilab.org/ ) - This file is part of Scilab
+ * Copyright (C) 2009-2011 - DIGITEO - Pierre Lando
+ *
+ * This file must be used under the terms of the CeCILL.
+ * This source file is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at
+ * http://www.cecill.info/licences/Licence_CeCILL_V2.1-en.txt
+ */
+
+package org.scilab.forge.scirenderer.ruler;
+
+import org.scilab.forge.scirenderer.texture.Texture;
+import org.scilab.forge.scirenderer.texture.TextureManager;
+
+import java.text.DecimalFormat;
+
+/**
+ * @author Pierre Lando
+ */
+public interface RulerSpriteFactory {
+
+ /**
+ * Return the texture for the given value.
+ * @param value the value.
+ * @param adaptedFormat an adapted number format for the given value.
+ * @param textureManager {@link TextureManager} to use.
+ * @return a positioned text entity for the given value.
+ */
+ Texture create(double value, DecimalFormat adaptedFormat, TextureManager textureManager);
+}
diff --git a/modules/scirenderer/src/org/scilab/forge/scirenderer/ruler/graduations/AbstractGraduations.java b/modules/scirenderer/src/org/scilab/forge/scirenderer/ruler/graduations/AbstractGraduations.java
new file mode 100755
index 000000000..4a97ceb13
--- /dev/null
+++ b/modules/scirenderer/src/org/scilab/forge/scirenderer/ruler/graduations/AbstractGraduations.java
@@ -0,0 +1,233 @@
+/*
+ * Scilab ( http://www.scilab.org/ ) - This file is part of Scilab
+ * Copyright (C) 2009-2011 - DIGITEO - Pierre Lando
+ * Copyright (C) 2013-2015 - Scilab Enterprises - Calixte DENIZET
+ *
+ * This file must be used under the terms of the CeCILL.
+ * This source file is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at
+ * http://www.cecill.info/licences/Licence_CeCILL_V2.1-en.txt
+ */
+
+package org.scilab.forge.scirenderer.ruler.graduations;
+
+import java.util.Collections;
+import java.util.LinkedList;
+import java.util.List;
+import java.text.DecimalFormat;
+import java.text.DecimalFormatSymbols;
+
+/**
+ * @author Pierre Lando
+ */
+public abstract class AbstractGraduations implements Graduations {
+
+ protected static final double PRECISION = 1e-8;
+
+ /** The left bracket used by {@link #toString()} */
+ private static final String LEFT_BRACKET = "[";
+
+ /** The right bracket used by {@link #toString()} */
+ private static final String RIGHT_BRACKET = "]";
+
+ /** True if the lower bound is included in the graduation interval. */
+ private final boolean isLowerBoundIncluded;
+
+ /** True if the upper bound is included in the graduation interval. */
+ private final boolean isUpperBoundIncluded;
+
+ /** Interval lower bound. */
+ private final double lowerBound;
+
+ /** Interval upper bound. */
+ private final double upperBound;
+
+ private final Graduations parentGraduations;
+ private DecimalFormat numberFormat;
+ protected List<Double> subValues;
+
+ /**
+ * Constructor from parent graduations.
+ * This constructor copy information from given {@link Graduations} and set it as is parent.
+ * @param parentGraduations the parent graduations to copy.
+ */
+ public AbstractGraduations(Graduations parentGraduations) {
+ this.parentGraduations = parentGraduations;
+ this.isLowerBoundIncluded = parentGraduations.isLowerBoundIncluded();
+ this.isUpperBoundIncluded = parentGraduations.isUpperBoundIncluded();
+ this.lowerBound = parentGraduations.getLowerBound();
+ this.upperBound = parentGraduations.getUpperBound();
+ }
+
+ /**
+ * Root constructor.
+ * Graduations made this way don't have a parent.
+ * @param lowerBound the actual lower bounds.
+ * @param lowerBoundIncluded the actual lower bounds included status.
+ * @param upperBound the actual upper bounds.
+ * @param upperBoundIncluded the actual upper bounds included status.
+ */
+ public AbstractGraduations(double lowerBound, boolean lowerBoundIncluded, double upperBound, boolean upperBoundIncluded) {
+ this.parentGraduations = null;
+ this.isLowerBoundIncluded = lowerBoundIncluded;
+ this.isUpperBoundIncluded = upperBoundIncluded;
+ this.lowerBound = lowerBound;
+ this.upperBound = upperBound;
+ }
+
+ /**
+ * Root constructor.
+ * Graduations made this way don't have a parent.
+ * There bounds are included.
+ * @param lowerBound the actual lower bounds included status.
+ * @param upperBound the actual upper bounds included status.
+ */
+ public AbstractGraduations(double lowerBound, double upperBound) {
+ this.parentGraduations = null;
+ this.isLowerBoundIncluded = true;
+ this.isUpperBoundIncluded = true;
+ this.lowerBound = lowerBound;
+ this.upperBound = upperBound;
+ }
+
+ /**
+ * Child constructor.
+ * @param parentGraduations the parent graduation.
+ * @param lowerBound the actual lower bounds.
+ * @param lowerBoundIncluded the actual lower bounds included status.
+ * @param upperBound the actual upper bounds.
+ * @param upperBoundIncluded the actual upper bounds included status.
+ */
+ public AbstractGraduations(Graduations parentGraduations, double lowerBound, boolean lowerBoundIncluded, double upperBound, boolean upperBoundIncluded) {
+ this.parentGraduations = parentGraduations;
+ this.isLowerBoundIncluded = lowerBoundIncluded;
+ this.isUpperBoundIncluded = upperBoundIncluded;
+ this.lowerBound = lowerBound;
+ this.upperBound = upperBound;
+ }
+
+ @Override
+ public final double getLowerBound() {
+ return lowerBound;
+ }
+
+ @Override
+ public final boolean isLowerBoundIncluded() {
+ return isLowerBoundIncluded;
+ }
+
+ @Override
+ public final double getUpperBound() {
+ return upperBound;
+ }
+
+ @Override
+ public final boolean isUpperBoundIncluded() {
+ return isUpperBoundIncluded;
+ }
+
+ @Override
+ public final Graduations getParentGraduations() {
+ return parentGraduations;
+ }
+
+ @Override
+ public final boolean contain(double value) {
+ if (value == lowerBound) {
+ return isLowerBoundIncluded;
+ }
+ if (value == upperBound) {
+ return isUpperBoundIncluded;
+ }
+ return (lowerBound < value) && (value < upperBound);
+ }
+
+ /**
+ * Equivalent to contain but for interval [0, upper-lower] (to avoid rounding error in computations)
+ */
+ public final boolean containRelative(double value) {
+ if (value == 0 || Math.abs(value / (upperBound - lowerBound)) <= PRECISION) {
+ return isLowerBoundIncluded;
+ }
+ if (value == upperBound - lowerBound || Math.abs(1 - value / (upperBound - lowerBound)) <= PRECISION) {
+ return isUpperBoundIncluded;
+ }
+ return (0 < value) && (value < upperBound - lowerBound);
+ }
+
+ @Override
+ public final DecimalFormat getFormat() {
+ if (numberFormat == null) {
+ double maxDisplayedValue = Math.max(Math.abs(lowerBound), Math.abs(upperBound));
+ double len = Math.abs(upperBound - lowerBound);
+
+ if (maxDisplayedValue < 1e-3) {
+ numberFormat = new DecimalFormat("0.##########E00");
+ } else if (false && len <= 1e-3) {
+ // desactivated for now...
+ // the user should be able to do that itself
+ numberFormat = new TinyIntervalFormat("0.####E00", "0.##E00");
+ } else if (maxDisplayedValue >= 1e6) {
+ numberFormat = new DecimalFormat("0.##########E00");
+ } else if (maxDisplayedValue < 1) {
+ numberFormat = new DecimalFormat("0.######");
+ } else {
+ numberFormat = new DecimalFormat("#,##0.####");
+ }
+
+ DecimalFormatSymbols decimalFormatSymbols = numberFormat.getDecimalFormatSymbols();
+ decimalFormatSymbols.setExponentSeparator("e");
+ numberFormat.setDecimalFormatSymbols(decimalFormatSymbols);
+ }
+ return numberFormat;
+ }
+
+ @Override
+ public List<Double> getSubGraduations(final int N) {
+ if (subValues == null) {
+ List<Double> ticksValue = getAllValues();
+ if (N == 0 || ticksValue.size() == 0) {
+ subValues = new LinkedList<Double>();
+ } else {
+ Collections.sort(ticksValue);
+ subValues = new LinkedList<Double>();
+
+ for (int i = 0; i < ticksValue.size() - 1; i++) {
+ final double first = ticksValue.get(i);
+ final double second = ticksValue.get(i + 1);
+ final double step = (second - first) / (N + 1);
+ double v = first;
+ for (int j = 0; j <= N; j++) {
+ subValues.add(v);
+ v += step;
+ }
+ }
+ subValues.add(ticksValue.get(ticksValue.size() - 1));
+ }
+ }
+
+ return subValues;
+ }
+
+ @Override
+ public String toString() {
+ String lowerBoundBracket;
+ String upperBoundBracket;
+
+ if (isLowerBoundIncluded) {
+ lowerBoundBracket = LEFT_BRACKET;
+ } else {
+ lowerBoundBracket = RIGHT_BRACKET;
+ }
+
+ if (isUpperBoundIncluded) {
+ upperBoundBracket = RIGHT_BRACKET;
+ } else {
+ upperBoundBracket = LEFT_BRACKET;
+ }
+ return getClass().getSimpleName() + lowerBoundBracket
+ + getFormat().format(lowerBound) + ", "
+ + getFormat().format(upperBound) + upperBoundBracket;
+ }
+}
diff --git a/modules/scirenderer/src/org/scilab/forge/scirenderer/ruler/graduations/Graduations.java b/modules/scirenderer/src/org/scilab/forge/scirenderer/ruler/graduations/Graduations.java
new file mode 100755
index 000000000..a8aa09bf9
--- /dev/null
+++ b/modules/scirenderer/src/org/scilab/forge/scirenderer/ruler/graduations/Graduations.java
@@ -0,0 +1,108 @@
+/*
+ * Scilab ( http://www.scilab.org/ ) - This file is part of Scilab
+ * Copyright (C) 2009-2011 - DIGITEO - Pierre Lando
+ * Copyright (C) 2013 - Scilab Enterprises - Calixte DENIZET
+ *
+ * This file must be used under the terms of the CeCILL.
+ * This source file is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at
+ * http://www.cecill.info/licences/Licence_CeCILL_V2.1-en.txt
+ */
+
+package org.scilab.forge.scirenderer.ruler.graduations;
+
+import java.text.DecimalFormat;
+import java.util.List;
+
+/**
+ * @author Pierre Lando
+ */
+public interface Graduations {
+
+ /**
+ * Return the lower bound.
+ * @return the lower bound.
+ */
+ double getLowerBound();
+
+ /**
+ * Return true if the lower bound is included.
+ * @return true if the lower bound is included.
+ */
+ boolean isLowerBoundIncluded();
+
+ /**
+ * Return the upper bound.
+ * @return the upper bound.
+ */
+ double getUpperBound();
+
+ /**
+ * Return true if the lower bound is included.
+ * @return true if the lower bound is included.
+ */
+ boolean isUpperBoundIncluded();
+
+ /**
+ * Return true if the interval contain the given value.
+ * @param value the given value.
+ * @return true if the interval contain the given value.
+ */
+ boolean contain(double value);
+
+ /**
+ * Return an adapted number format.
+ * @return an adapted number format.
+ */
+ DecimalFormat getFormat();
+
+ /**
+ * Return all values of this graduation.
+ * @return all values of this graduation.
+ */
+ List<Double> getAllValues();
+
+ /**
+ * Return values not present in parents graduations.
+ * @return values not present in parents graduations.
+ */
+ List<Double> getNewValues();
+
+ /**
+ * Return the parent graduation.
+ * @return the parent graduation.
+ */
+ Graduations getParentGraduations();
+
+ /**
+ * Return a child graduation with more values.
+ * @return a child graduation with more values.
+ */
+ Graduations getMore();
+
+ /**
+ * Return a child graduation with more values but less than <code>getMore()</code>
+ * @return a child graduation with more values but less than <code>getMore()</code>
+ */
+ Graduations getAlternative();
+
+ /**
+ * Return a child graduation for sub ticks.
+ * @return a child graduation for sub ticks.
+ */
+ Graduations getSubGraduations();
+
+ /**
+ * Get the list of subgraduations corresponding to N subticks between two main consecutives ticks
+ * @param N the number of graduations
+ * @return the corresponding list
+ */
+ List<Double> getSubGraduations(int N);
+
+ /**
+ * Return the density of sub ticks.
+ * @return the density of sub ticks.
+ */
+ int getSubDensity();
+}
diff --git a/modules/scirenderer/src/org/scilab/forge/scirenderer/ruler/graduations/LinearGraduations.java b/modules/scirenderer/src/org/scilab/forge/scirenderer/ruler/graduations/LinearGraduations.java
new file mode 100755
index 000000000..418ee172a
--- /dev/null
+++ b/modules/scirenderer/src/org/scilab/forge/scirenderer/ruler/graduations/LinearGraduations.java
@@ -0,0 +1,294 @@
+/*
+ * Scilab ( http://www.scilab.org/ ) - This file is part of Scilab
+ * Copyright (C) 2009-2011 - DIGITEO - Pierre Lando
+ * Copyright (C) 2013 - Scilab Enterprises - Calixte DENIZET
+ *
+ * This file must be used under the terms of the CeCILL.
+ * This source file is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at
+ * http://www.cecill.info/licences/Licence_CeCILL_V2.1-en.txt
+ */
+
+package org.scilab.forge.scirenderer.ruler.graduations;
+
+import java.util.LinkedList;
+import java.util.List;
+
+/**
+ * A linear graduation is a graduation with regular spaces mark.
+ * The mark distance is called "Step" and have for value {@code mantissa x 10^exponent}.
+ * Where mantissa is 1, 2 or 5.
+ * Exponent is an integer.
+ *
+ * @author Pierre Lando
+ */
+public final class LinearGraduations extends AbstractGraduations implements Graduations {
+
+ /**
+ * The step exponent.
+ */
+ protected final int stepExponent;
+
+ /**
+ * The step mantissa.
+ */
+ protected final int stepMantissa;
+
+ private LinearGraduations moreGraduation;
+ private LinearGraduations alternativeGraduation;
+ private Graduations subGraduation;
+ private Double stepValue;
+ private List<Double> allValues;
+ private List<Double> newValues;
+
+ /**
+ * Private constructor.
+ * Use creates methods.
+ */
+ private LinearGraduations() {
+ super(null);
+ stepExponent = 0;
+ stepMantissa = 0;
+ }
+
+ private LinearGraduations(Graduations parentGraduations, int stepExponent, int stepMantissa) {
+ super(parentGraduations);
+ this.stepExponent = stepExponent;
+ this.stepMantissa = stepMantissa;
+ }
+
+ private LinearGraduations(Graduations parentGraduations, double lowerBound, boolean lowerBoundIncluded, double upperBound, boolean upperBoundIncluded) {
+ super(parentGraduations, lowerBound, lowerBoundIncluded, upperBound, upperBoundIncluded);
+ if (lowerBound != upperBound) {
+ double size = upperBound - lowerBound;
+ stepExponent = (int) Math.ceil(Math.log10(size));
+ stepMantissa = 1;
+ } else {
+ stepExponent = 0;
+ stepMantissa = 0;
+ newValues = new LinkedList<Double>();
+ allValues = new LinkedList<Double>();
+ allValues.add(lowerBound);
+ }
+ }
+
+ public static LinearGraduations create(double lowerBound, double upperBound) {
+ return create(lowerBound, true, upperBound, true);
+ }
+
+ public static LinearGraduations create(
+ Graduations parentGraduations,
+ double lowerBound, boolean lowerBoundIncluded,
+ double upperBound, boolean upperBoundIncluded
+ ) {
+ if (lowerBound < upperBound) {
+ return new LinearGraduations(parentGraduations, lowerBound, lowerBoundIncluded, upperBound, upperBoundIncluded);
+ } else {
+ return new LinearGraduations(parentGraduations, upperBound, upperBoundIncluded, lowerBound, lowerBoundIncluded);
+ }
+ }
+
+ public static LinearGraduations create(double lowerBound, boolean lowerBoundIncluded, double upperBound, boolean upperBoundIncluded) {
+ if (lowerBound < upperBound) {
+ return new LinearGraduations(null, lowerBound, lowerBoundIncluded, upperBound, upperBoundIncluded);
+ } else {
+ return new LinearGraduations(null, upperBound, upperBoundIncluded, lowerBound, lowerBoundIncluded);
+ }
+ }
+
+
+ private static final double mypow10(int e) {
+ double p = 10;
+ double r = 1;
+ final boolean signed = e < 0;
+ if (signed) {
+ e = -e;
+ }
+ while (e != 0) {
+ if ((e & 1) != 0) {
+ r *= p;
+ }
+ p *= p;
+ e >>= 1;
+ }
+
+ return signed ? 1 / r : r;
+ }
+
+ private static final long myceil(double x) {
+ if (x == 0) {
+ return 0L;
+ }
+
+ double r = Math.round(x);
+ if (Math.abs(1 - r / x) <= PRECISION) {
+ return (long) r;
+ }
+
+ return (long) Math.ceil(x);
+ }
+
+ private Double getStepValue() {
+ if (stepValue == null) {
+ if (stepMantissa == 1) {
+ stepValue = mypow10(stepExponent);
+ } else {
+ stepValue = stepMantissa * mypow10(stepExponent);
+ }
+ }
+ return stepValue;
+ }
+
+ private final long getIndex(double x) {
+ switch (stepMantissa) {
+ case 1:
+ return myceil(mypow10(-stepExponent) * x);
+ case 2:
+ return myceil(5 * mypow10(-stepExponent - 1) * x);
+ case 5:
+ return myceil(mypow10(-stepExponent - 1) * x * 2);
+ default:
+ return myceil(mypow10(-stepExponent) * x / stepMantissa);
+ }
+ }
+
+ private boolean isNewIndex(final long index) {
+ /* We are now searching for value look like
+ * index * (stepMantissa * 10^n) and we don't want (previousStrepMantissa * 10^k) value.
+ */
+
+ switch (stepMantissa) {
+ case 1:
+ // (5 * index * stepMantissa) % 10 != 0
+ return (index % 2) != 0;
+ case 2:
+ // (2 * index * stepMantissa) % 10 != 0
+ return (index % 5) != 0;
+ default:
+ // (5 * index * stepMantissa) % 10 != 0
+ return ((index * stepMantissa) % 2) != 0;
+ }
+ }
+
+ @Override
+ public List<Double> getNewValues() {
+ if (getParentGraduations() == null) {
+ return getAllValues();
+ }
+
+ if (newValues == null) {
+ newValues = new LinkedList<Double>();
+ final double lb = getLowerBound();
+
+ long currentIndex = getIndex(lb);
+ double currentValue = getStepValue() * currentIndex;
+ double value = currentValue - lb;
+
+ if (value == 0 && !containRelative(value)) {
+ value += getStepValue();
+ currentIndex++;
+ }
+
+ while (containRelative(value) && !Double.isInfinite(lb + value)) {
+ if (isNewIndex(currentIndex)) {
+ newValues.add(lb + value);
+ }
+ value += getStepValue();
+ currentIndex++;
+ }
+ }
+
+ return newValues;
+ }
+
+ @Override
+ public List<Double> getAllValues() {
+ if (allValues == null) {
+ final double lb = getLowerBound();
+ allValues = new LinkedList<Double>();
+ double currentValue = getStepValue() * getIndex(lb);
+ double value = currentValue - lb;
+
+ if (value == 0 && !containRelative(value)) {
+ value += getStepValue();
+ }
+
+ while (containRelative(value) && !Double.isInfinite(lb + value)) {
+ allValues.add(lb + value);
+ value += getStepValue();
+ }
+ }
+ return allValues;
+ }
+
+ @Override
+ public LinearGraduations getMore() {
+ if (stepMantissa != 5) {
+ if (moreGraduation == null) {
+ if (stepMantissa == 1) {
+ moreGraduation = new LinearGraduations(this, stepExponent - 1, 2);
+ } else {
+ moreGraduation = new LinearGraduations(this, stepExponent, 1);
+ }
+ }
+ return moreGraduation;
+ } else {
+ return null;
+ }
+ }
+
+ @Override
+ public LinearGraduations getAlternative() {
+ if (stepMantissa == 2) {
+ if (alternativeGraduation == null) {
+ if (getParentGraduations() == null) {
+ alternativeGraduation = new LinearGraduations(null, getLowerBound(), true, getLowerBound(), true);
+ } else {
+ alternativeGraduation = new LinearGraduations(getParentGraduations(), stepExponent, 5);
+ }
+ }
+ return alternativeGraduation;
+ } else {
+ return null;
+ }
+ }
+
+ @Override
+ public Graduations getSubGraduations() {
+ if (subGraduation == null) {
+ switch (stepMantissa) {
+ case 1:
+ subGraduation = new LinearGraduations(this, stepExponent - 1, 5);
+ break;
+ case 2:
+ subGraduation = new LinearGraduations(this, stepExponent, 1);
+ break;
+ case 5:
+ subGraduation = new LinearGraduations(getParentGraduations(), stepExponent, 1);
+ break;
+ default:
+ subGraduation = null;
+ break;
+ }
+ }
+ return subGraduation;
+ }
+
+ @Override
+ public int getSubDensity() {
+ if (stepMantissa == 5) {
+ return 5;
+ } else {
+ return 2;
+ }
+ }
+
+ @Override
+ public String toString() {
+ String s = super.toString();
+ s += "; stepMantissa=" + stepMantissa + "; stepExponent=" + stepExponent + "; parent=" + getParentGraduations();
+
+ return s;
+ }
+}
diff --git a/modules/scirenderer/src/org/scilab/forge/scirenderer/ruler/graduations/LogarithmicGraduations.java b/modules/scirenderer/src/org/scilab/forge/scirenderer/ruler/graduations/LogarithmicGraduations.java
new file mode 100755
index 000000000..63e162f16
--- /dev/null
+++ b/modules/scirenderer/src/org/scilab/forge/scirenderer/ruler/graduations/LogarithmicGraduations.java
@@ -0,0 +1,348 @@
+/*
+ * Scilab ( http://www.scilab.org/ ) - This file is part of Scilab
+ * Copyright (C) 2009-2011 - DIGITEO - Pierre Lando
+ * Copyright (C) 2013-2015 - Scilab Enterprises - Calixte DENIZET
+ *
+ * This file must be used under the terms of the CeCILL.
+ * This source file is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at
+ * http://www.cecill.info/licences/Licence_CeCILL_V2.1-en.txt
+ */
+
+package org.scilab.forge.scirenderer.ruler.graduations;
+
+import java.util.Collections;
+import java.util.LinkedList;
+import java.util.List;
+
+/**
+ * @author Pierre Lando
+ */
+public final class LogarithmicGraduations extends AbstractGraduations implements Graduations {
+
+ /**
+ * Exponent of the step.
+ * Possible value are : 1, 2 and 3*k with k > 0
+ */
+ private final int stepExponent;
+
+ private List<Double> allValues;
+ private Graduations subGraduation;
+ private Graduations moreGraduation;
+ private Graduations alternativeGraduation;
+
+ /**
+ * Private child constructor.
+ * The interval is copied from parent's one.
+ * @param parentGraduations the parent graduation.
+ * @param stepExponent the step exponent.
+ */
+ private LogarithmicGraduations(Graduations parentGraduations, int stepExponent) {
+ super(parentGraduations);
+ this.stepExponent = stepExponent;
+ }
+
+ /**
+ * Private root graduation constructor.
+ * This graduation has no parent.
+ * @param lowerBound actual lower bound.
+ * @param lowerBoundIncluded true if the lower bound is included in the interval.
+ * @param upperBound actual upper bound.
+ * @param upperBoundIncluded true if the upper bound is included in the interval.
+ */
+ private LogarithmicGraduations(double lowerBound, boolean lowerBoundIncluded, double upperBound, boolean upperBoundIncluded) {
+ super(lowerBound, lowerBoundIncluded, upperBound, upperBoundIncluded);
+ if (lowerBound != upperBound) {
+ stepExponent = 1;
+ } else {
+ stepExponent = 0;
+ allValues = new LinkedList<Double>();
+ allValues.add(lowerBound);
+ }
+ }
+
+ public static LogarithmicGraduations create(double lowerBound, double upperBound) {
+ return create(lowerBound, true, upperBound, true);
+ }
+
+ public static LogarithmicGraduations create(double lowerBound, boolean lowerBoundIncluded, double upperBound, boolean upperBoundIncluded) {
+ if (lowerBound < upperBound) {
+ return new LogarithmicGraduations(lowerBound, lowerBoundIncluded, upperBound, upperBoundIncluded);
+ } else {
+ return new LogarithmicGraduations(upperBound, upperBoundIncluded, lowerBound, lowerBoundIncluded);
+ }
+ }
+
+ @Override
+ public List<Double> getAllValues() {
+ if (allValues == null) {
+ allValues = new LinkedList<Double>();
+ int currentExponent = (int) Math.ceil(Math.log10(getLowerBound()));
+ double currentValue = Math.pow(10, currentExponent);
+ final double step = Math.pow(10, stepExponent);
+
+ if ((currentValue == getLowerBound()) && (!isLowerBoundIncluded())) {
+ currentValue *= step;
+ }
+
+ while (contain(currentValue) && !Double.isInfinite(currentValue)) {
+ allValues.add(currentValue);
+ currentValue *= step;
+ }
+ }
+ return allValues;
+ }
+
+ @Override
+ public List<Double> getNewValues() {
+ return getAllValues();
+ }
+
+ @Override
+ public Graduations getMore() {
+ if (moreGraduation == null) {
+ moreGraduation = new LinLogGraduation(this);
+ }
+ return moreGraduation;
+ }
+
+ @Override
+ public Graduations getAlternative() {
+ if (alternativeGraduation == null) {
+ int nextStep = 3 + stepExponent - stepExponent % 3;
+ alternativeGraduation = new LogarithmicGraduations(this, nextStep);
+ }
+ return alternativeGraduation;
+ }
+
+ @Override
+ public Graduations getSubGraduations() {
+ if (subGraduation == null) {
+ if (stepExponent > 1) {
+ subGraduation = new LogarithmicGraduations(this, stepExponent / 3);
+ } else {
+ subGraduation = new LinLogGraduation(this).getSubGraduations();
+ }
+ }
+ return subGraduation;
+ }
+
+ @Override
+ public List<Double> getSubGraduations(final int N) {
+ if (subValues == null) {
+ List<Double> ticksValue = getAllValues();
+ if (N == 0 || ticksValue.size() == 0) {
+ subValues = new LinkedList<Double>();
+ } else {
+ Collections.sort(ticksValue);
+ subValues = new LinkedList<Double>();
+
+ for (int i = 0; i < ticksValue.size() - 1; i++) {
+ final double first = Math.log10(ticksValue.get(i));
+ final double second = Math.log10(ticksValue.get(i + 1));
+ final double step = (second - first) / (N + 1);
+ double v = first;
+ for (int j = 0; j <= N; j++) {
+ subValues.add(Math.pow(10, v));
+ v += step;
+ }
+ }
+ subValues.add(ticksValue.get(ticksValue.size() - 1));
+ }
+ }
+
+ return subValues;
+ }
+
+ @Override
+ public int getSubDensity() {
+ if (stepExponent >= 3) {
+ return 3;
+ } else if (stepExponent == 2) {
+ return stepExponent;
+ } else {
+ return getSubGraduations().getSubDensity();
+ }
+ }
+
+ @Override
+ public String toString() {
+ String s = super.toString();
+ s += "; stepExponent=" + stepExponent + "; parent=" + getParentGraduations();
+
+ return s;
+ }
+
+ /**
+ * This class manage linear graduation between 10^n and 10^(n+1)
+ */
+ private class LinLogGraduation extends AbstractGraduations implements Graduations {
+ private Graduations alternativeLLGraduation;
+ private Graduations moreLLGraduation;
+ private Graduations subLLGraduation;
+
+ private List<Double> allValues;
+ private List<Double> newValues;
+
+ private final List<Graduations> graduationsList;
+
+ public LinLogGraduation(LogarithmicGraduations parentGraduations) {
+ super(parentGraduations);
+ graduationsList = computeGraduationsList();
+ }
+
+ private LinLogGraduation(Graduations parentGraduations, List<Graduations> graduationsList) {
+ super(parentGraduations);
+ this.graduationsList = graduationsList;
+ }
+
+ @Override
+ public List<Double> getAllValues() {
+ if (allValues == null) {
+ allValues = new LinkedList<Double>();
+ for (Graduations graduations : graduationsList) {
+ allValues.addAll(graduations.getAllValues());
+ }
+
+ allValues.addAll(getLogarithmicParent().getAllValues());
+ }
+ return allValues;
+ }
+
+ @Override
+ public List<Double> getNewValues() {
+ if (newValues == null) {
+ newValues = new LinkedList<Double>();
+ if (getParentGraduations() instanceof LogarithmicGraduations) {
+ for (Graduations graduations : graduationsList) {
+ newValues.addAll(graduations.getAllValues());
+ }
+ } else {
+ for (Graduations graduations : graduationsList) {
+ newValues.addAll(graduations.getNewValues());
+ }
+ }
+ }
+ return newValues;
+ }
+
+ @Override
+ public Graduations getMore() {
+ if (moreLLGraduation == null) {
+ List<Graduations> moreList = new LinkedList<Graduations>();
+ for (Graduations graduations : graduationsList) {
+ Graduations more = graduations.getMore();
+ if (more != null) {
+ moreList.add(more);
+ }
+ }
+ if (!moreList.isEmpty()) {
+ moreLLGraduation = new LinLogGraduation(this, moreList);
+ }
+ }
+ return moreLLGraduation;
+ }
+
+ @Override
+ public Graduations getAlternative() {
+ if (alternativeLLGraduation == null) {
+ List<Graduations> alternativeList = new LinkedList<Graduations>();
+ for (Graduations graduations : graduationsList) {
+ Graduations alternative = graduations.getAlternative();
+ if (alternative != null) {
+ alternativeList.add(alternative);
+ }
+ }
+ if (!alternativeList.isEmpty()) {
+ alternativeLLGraduation = new LinLogGraduation(this, alternativeList);
+ }
+ }
+ return alternativeLLGraduation;
+ }
+
+ @Override
+ public Graduations getSubGraduations() {
+ if (subLLGraduation == null) {
+ List<Graduations> subList = new LinkedList<Graduations>();
+ for (Graduations graduations : graduationsList) {
+ Graduations sub = graduations.getSubGraduations();
+ if (sub != null) {
+ subList.add(sub);
+ }
+ }
+ if (subList.isEmpty()) {
+ subLLGraduation = getMore().getSubGraduations();
+ } else {
+ subLLGraduation = new LinLogGraduation(this, subList);
+ }
+ }
+ return subLLGraduation;
+ }
+
+ @Override
+ public int getSubDensity() {
+ return 0;
+ }
+
+ private List<Graduations> computeGraduationsList() {
+ List<Graduations> list = new LinkedList<Graduations>();
+
+ /**
+ * Let a and b a power of 10.
+ * lowerBound < a < b < upperBound
+ */
+
+ double aPower = Math.ceil(Math.log10(getLowerBound()));
+ double bPower = Math.floor(Math.log10(getUpperBound()));
+ double a = Math.pow(10, aPower);
+ double b = Math.pow(10, bPower);
+
+ if (aPower > bPower) {
+ // Case of 10^n <= a < b <= 10^(n+1)
+ list.add(LinearGraduations.create(
+ this,
+ getLowerBound(), true,
+ getUpperBound(), true
+ ));
+ } else {
+ if (a != getLowerBound()) {
+ list.add(LinearGraduations.create(
+ this,
+ getLowerBound(), true,
+ a, false
+ ));
+ }
+
+ if (aPower != bPower) {
+ // Limit iterations on power smaller than 10^310 (Max double ~ 10^308)
+ for (double i = aPower; i < Math.min(bPower, 310); i++) {
+ list.add(LinearGraduations.create(
+ this,
+ Math.pow(10, i), false,
+ Math.pow(10, i + 1), false
+ ));
+ }
+ }
+
+ if (b != getUpperBound()) {
+ list.add(LinearGraduations.create(
+ this,
+ b, false,
+ getUpperBound(), true
+ ));
+ }
+ }
+
+ return list;
+ }
+
+ private Graduations getLogarithmicParent() {
+ Graduations currentGraduation = getParentGraduations();
+ while (!(currentGraduation instanceof LogarithmicGraduations)) {
+ currentGraduation = currentGraduation.getParentGraduations();
+ }
+ return currentGraduation;
+ }
+ }
+}
diff --git a/modules/scirenderer/src/org/scilab/forge/scirenderer/ruler/graduations/TinyIntervalFormat.java b/modules/scirenderer/src/org/scilab/forge/scirenderer/ruler/graduations/TinyIntervalFormat.java
new file mode 100755
index 000000000..efe7dd6f8
--- /dev/null
+++ b/modules/scirenderer/src/org/scilab/forge/scirenderer/ruler/graduations/TinyIntervalFormat.java
@@ -0,0 +1,95 @@
+/*
+ * Scilab ( http://www.scilab.org/ ) - This file is part of Scilab
+ * Copyright (C) 2013 - Scilab Enterprises - Calixte DENIZET
+ *
+ * This file must be used under the terms of the CeCILL.
+ * This source file is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at
+ * http://www.cecill.info/licences/Licence_CeCILL_V2.1-en.txt
+ */
+
+package org.scilab.forge.scirenderer.ruler.graduations;
+
+import java.text.DecimalFormat;
+import java.text.DecimalFormatSymbols;
+import java.text.FieldPosition;
+
+/**
+ * TinyIntervalFormat allows to format 3.0001 into "3+1e-4" or 2.9999 in "3-1e-4"
+ * It is useful to represent values in a tiny intervall to avoid to have the same representation
+ * for different values.
+ * For a number 3.0001, 3 is called the base and 1e-4 the fractional part.
+ */
+public class TinyIntervalFormat extends DecimalFormat {
+
+ private static final DecimalFormat simpleFormat = new DecimalFormat("0.######");
+
+ private DecimalFormat fracFormat;
+
+ /**
+ * Constructor
+ * @param basePattern the pattern to represent the base
+ * @param fracPattern the pattern to represent frac
+ */
+ public TinyIntervalFormat(String basePattern, String fracPattern) {
+ super(basePattern);
+ fracFormat = new DecimalFormat(fracPattern);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public StringBuffer format(double number, StringBuffer result, FieldPosition fieldPosition) {
+ double[] parts = getParts(number);
+
+ if (parts[1] == 0) {
+ return super.format(number, result, fieldPosition);
+ }
+
+ if (parts[0] != 0) {
+ if (parts[0] < 10) {
+ result = simpleFormat.format(parts[0], result, fieldPosition);
+ } else {
+ result = super.format(parts[0], result, fieldPosition);
+ }
+
+ if (parts[1] > 0) {
+ result.append("+");
+ } else if (parts[1] < 0) {
+ result.append("-");
+ }
+
+ return fracFormat.format(Math.abs(parts[1]), result, fieldPosition);
+ }
+
+ return fracFormat.format(parts[1], result, fieldPosition);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public void setDecimalFormatSymbols(DecimalFormatSymbols newSymbols) {
+ super.setDecimalFormatSymbols(newSymbols);
+ fracFormat.setDecimalFormatSymbols(newSymbols);
+ simpleFormat.setDecimalFormatSymbols(newSymbols);
+ }
+
+ /**
+ * Get the base and the frac part of the number x
+ * @param x the value
+ * @return the parts
+ */
+ private static final double[] getParts(final double x) {
+ double p = 1;
+ double y = x;
+ double f = y - Math.round(y);
+ while (Math.abs(f) > 1e-2) {
+ y *= 10;
+ p *= 10;
+ f = y - Math.round(y);
+ }
+
+ return new double[] {Math.round(y) / p, f / p};
+ }
+}
diff --git a/modules/scirenderer/src/org/scilab/forge/scirenderer/ruler/graduations/UserDefinedFormat.java b/modules/scirenderer/src/org/scilab/forge/scirenderer/ruler/graduations/UserDefinedFormat.java
new file mode 100755
index 000000000..6a63ab853
--- /dev/null
+++ b/modules/scirenderer/src/org/scilab/forge/scirenderer/ruler/graduations/UserDefinedFormat.java
@@ -0,0 +1,96 @@
+/*
+ * Scilab ( http://www.scilab.org/ ) - This file is part of Scilab
+ * Copyright (C) 2014 - Scilab Enterprises - Calixte DENIZET
+ *
+ * This file must be used under the terms of the CeCILL.
+ * This source file is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at
+ * http://www.cecill.info/licences/Licence_CeCILL_V2.1-en.txt
+ */
+
+package org.scilab.forge.scirenderer.ruler.graduations;
+
+import java.text.DecimalFormat;
+import java.text.DecimalFormatSymbols;
+import java.text.FieldPosition;
+import java.util.Formatter;
+import java.util.IllegalFormatConversionException;
+import java.util.Locale;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+/**
+ * Use a user defined format to format ticks label.
+ */
+public class UserDefinedFormat extends DecimalFormat {
+
+ private String format;
+ private double scale;
+ private double translation;
+ private DecimalFormat fallback;
+
+ /**
+ * Constructor
+ * @param basePattern the pattern to represent the base
+ * @param fracPattern the pattern to represent frac
+ */
+ public UserDefinedFormat(DecimalFormat fallback, String format, double scale, double translation) {
+ super();
+ this.format = format;
+ this.scale = scale;
+ this.translation = translation;
+ this.fallback = fallback;
+ }
+
+ public String getFormat() {
+ return format;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public StringBuffer format(double number, StringBuffer result, FieldPosition fieldPosition) {
+ final double d = scale * (number - translation);
+ if (format != null && !format.isEmpty()) {
+ try {
+ Formatter fmt = new Formatter(Locale.US);
+ fmt.format(Locale.US, format, d);
+ return result.append(fmt.toString());
+ } catch (IllegalFormatConversionException e) {
+ try {
+ Formatter fmt = new Formatter(Locale.US);
+ fmt.format(Locale.US, format, (long) d);
+ return result.append(fmt.toString());
+ } catch (Exception ee) { }
+ } catch (ArrayIndexOutOfBoundsException e) {
+ // Java bug in Formatter format("%.1g", 0.) or something like that is faulty
+ // So what is following is just a crappy workaround to replace g by f...
+ if (d == 0) {
+ Pattern pat = Pattern.compile("([^%]*%[-#+ 0,(]?\\.[01])[gG](.*)");
+ Matcher match = pat.matcher(format);
+ if (match.find() && match.groupCount() == 2) {
+ StringBuilder buffer = new StringBuilder(format.length());
+ buffer.append(format.substring(0, match.start())).append(match.group(1)).append('f').append(match.group(2));
+ format = buffer.toString();
+
+ try {
+ Formatter fmt = new Formatter(Locale.US);
+ fmt.format(Locale.US, format, d);
+ return result.append(fmt.toString());
+ } catch (Exception ee) { }
+ }
+ }
+ } catch (Exception e) { }
+ }
+
+ return fallback.format(number, result, fieldPosition);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public void setDecimalFormatSymbols(DecimalFormatSymbols newSymbols) {
+ fallback.setDecimalFormatSymbols(newSymbols);
+ }
+}
diff --git a/modules/scirenderer/src/org/scilab/forge/scirenderer/shapes/appearance/Appearance.java b/modules/scirenderer/src/org/scilab/forge/scirenderer/shapes/appearance/Appearance.java
new file mode 100755
index 000000000..7b7a51cfc
--- /dev/null
+++ b/modules/scirenderer/src/org/scilab/forge/scirenderer/shapes/appearance/Appearance.java
@@ -0,0 +1,190 @@
+/*
+ * Scilab ( http://www.scilab.org/ ) - This file is part of Scilab
+ * Copyright (C) 2009-2011 - DIGITEO - Pierre Lando
+ *
+ * This file must be used under the terms of the CeCILL.
+ * This source file is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at
+ * http://www.cecill.info/licences/Licence_CeCILL_V2.1-en.txt
+ */
+
+package org.scilab.forge.scirenderer.shapes.appearance;
+
+import org.scilab.forge.scirenderer.texture.Texture;
+
+/**
+ *
+ * Basic class for appearance parameters.
+ *
+ * @author Pierre Lando
+ */
+public final class Appearance {
+
+ /**
+ * The default line width.
+ */
+ public static final float DEFAULT_LINE_WIDTH = 1.0f;
+
+ /**
+ * The default line pattern (full line).
+ * The 16 bits of the pattern represents how lines are drawn.
+ */
+ public static final short DEFAULT_LINE_PATTERN = (short) 0xFFFF;
+
+ /**
+ * The default line color.
+ */
+ public static final Color DEFAULT_LINE_COLOR = new Color(.8f, .8f, .8f);
+
+ /**
+ * The default fill color.
+ */
+ public static final Color DEFAULT_FILL_COLOR = new Color(.8f, .8f, .8f);
+
+ /**
+ * Current {@link Texture}
+ */
+ private Texture texture;
+
+ /**
+ * The current line width.
+ */
+ private float lineWidth = DEFAULT_LINE_WIDTH;
+
+ /**
+ * The current line pattern.
+ * The 16 bits of the pattern represents how lines are drawn.
+ */
+ private short linePattern = DEFAULT_LINE_PATTERN;
+
+ /**
+ * the current line color.
+ */
+ private Color lineColor = DEFAULT_LINE_COLOR;
+
+ /**
+ * The current fill color.
+ */
+ private Color fillColor = DEFAULT_FILL_COLOR;
+
+ /**
+ * The material used for lighting.
+ */
+ private Material material;
+
+ /**
+ * Default constructor.
+ */
+ public Appearance() {
+ }
+
+ /**
+ * Return the default appearance.
+ * @return the default appearance.
+ */
+ public static Appearance getDefault() {
+ return new Appearance();
+ }
+
+ /**
+ * Texture getter.
+ * @return the current texture if any.
+ */
+ public Texture getTexture() {
+ if ((texture != null) && (texture.isValid())) {
+ return texture;
+ } else {
+ return null;
+ }
+ }
+
+ /**
+ * Texture setter.
+ * @param texture the new texture.
+ */
+ public void setTexture(Texture texture) {
+ this.texture = texture;
+ }
+
+ /**
+ * Return the line width.
+ * @return the line width.
+ */
+ public float getLineWidth() {
+ return lineWidth;
+ }
+
+ /**
+ * Set the line width.
+ * @param lineWidth the new line width.
+ */
+ public void setLineWidth(float lineWidth) {
+ this.lineWidth = lineWidth;
+ }
+
+ /**
+ * Return the line pattern.
+ * @return the line pattern.
+ */
+ public short getLinePattern() {
+ return linePattern;
+ }
+
+ /**
+ * Set the line pattern.
+ * @param linePattern the new line pattern.
+ */
+ public void setLinePattern(short linePattern) {
+ this.linePattern = linePattern;
+ }
+
+ /**
+ * Return the line color.
+ * @return the line color.
+ */
+ public Color getLineColor() {
+ return lineColor;
+ }
+
+ /**
+ * Set the line color.
+ * @param lineColor the new lne color.
+ */
+ public void setLineColor(Color lineColor) {
+ this.lineColor = lineColor;
+ }
+
+ /**
+ * Return the fill color.
+ * @return the fill color.
+ */
+ public Color getFillColor() {
+ return fillColor;
+ }
+
+ /**
+ * Set the fill color.
+ * @param fillColor the new fill color.
+ */
+ public void setFillColor(Color fillColor) {
+ this.fillColor = fillColor;
+ }
+
+ /**
+ * Get the material.
+ * @return the material.
+ */
+ public Material getMaterial() {
+ return material;
+ }
+
+ /**
+ * Set the material.
+ * @param the new material.
+ */
+ public void setMaterial(Material m) {
+ material = m;
+ }
+}
+
diff --git a/modules/scirenderer/src/org/scilab/forge/scirenderer/shapes/appearance/Color.java b/modules/scirenderer/src/org/scilab/forge/scirenderer/shapes/appearance/Color.java
new file mode 100755
index 000000000..52bae0f9d
--- /dev/null
+++ b/modules/scirenderer/src/org/scilab/forge/scirenderer/shapes/appearance/Color.java
@@ -0,0 +1,104 @@
+/*
+ * Scilab ( http://www.scilab.org/ ) - This file is part of Scilab
+ * Copyright (C) 2009-2011 - DIGITEO - Pierre Lando
+ *
+ * This file must be used under the terms of the CeCILL.
+ * This source file is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at
+ * http://www.cecill.info/licences/Licence_CeCILL_V2.1-en.txt
+ */
+
+package org.scilab.forge.scirenderer.shapes.appearance;
+
+/**
+ * @author Pierre Lando
+ */
+@SuppressWarnings(value = { "serial" })
+public final class Color extends java.awt.Color {
+
+ private static final float COMPONENT_MAX_VALUE = 255f;
+
+ /**
+ * The default color.
+ */
+ private static final Color DEFAULT_COLOR = new Color(.2f, .3f, .4f);
+
+ /**
+ * Default constructor.
+ * Create a copy of the default color.
+ */
+ public Color() {
+ this(DEFAULT_COLOR);
+ }
+
+ /**
+ * Copy constructor
+ * @param c the color to copy.
+ */
+ public Color(Color c) {
+ super(c.getRed(), c.getGreen(), c.getBlue(), c.getAlpha());
+ }
+
+ /**
+ * Creates an sRGB color with the specified red, green, blue, and
+ * alpha values in the range [0.0; 1.0]. The actual color
+ * used in rendering depends on finding the best match given the
+ * color space available for a particular output device.
+ *
+ * @param r the red component
+ * @param g the green component
+ * @param b the blue component
+ * @param a the alpha component
+ */
+ public Color(float r, float g, float b, float a) {
+ super(r, g, b, a);
+ }
+
+ /**
+ * Creates an opaque sRGB color with the specified red, green, and blue
+ * values in the range [0.0; 1.0]. Alpha is defaulted to 1.0. The
+ * actual color used in rendering depends on finding the best
+ * match given the color space available for a particular output
+ * device.
+ *
+ * @param r the red component
+ * @param g the green component
+ * @param b the blue component
+ */
+ public Color(float r, float g, float b) {
+ super(r, g, b);
+ }
+
+ /**
+ * Return red component value. In the range [0; 1].
+ * @return red component value. In the range [0; 1].
+ */
+ public float getRedAsFloat() {
+ return ((float) getRed()) / COMPONENT_MAX_VALUE;
+ }
+
+ /**
+ * Return green component value. In the range [0; 1].
+ * @return green component value. In the range [0; 1].
+ */
+ public float getGreenAsFloat() {
+ return ((float) getGreen()) / COMPONENT_MAX_VALUE;
+ }
+
+ /**
+ * Return blue component value. In the range [0; 1].
+ * @return blue component value. In the range [0; 1].
+ */
+ public float getBlueAsFloat() {
+ return ((float) getBlue()) / COMPONENT_MAX_VALUE;
+ }
+
+ /**
+ * Return alpha component value. In the range [0; 1].
+ * @return alpha component value. In the range [0; 1].
+ */
+ public float getAlphaAsFloat() {
+ return ((float) getAlpha()) / COMPONENT_MAX_VALUE;
+ }
+}
diff --git a/modules/scirenderer/src/org/scilab/forge/scirenderer/shapes/appearance/Material.java b/modules/scirenderer/src/org/scilab/forge/scirenderer/shapes/appearance/Material.java
new file mode 100755
index 000000000..28e516885
--- /dev/null
+++ b/modules/scirenderer/src/org/scilab/forge/scirenderer/shapes/appearance/Material.java
@@ -0,0 +1,100 @@
+/*
+ * Scilab ( http://www.scilab.org/ ) - This file is part of Scilab
+ * Copyright (C) 2013 - Pedro SOUZA
+ *
+ * This file must be used under the terms of the CeCILL.
+ * This source file is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at
+ * http://www.cecill.info/licences/Licence_CeCILL_V2.1-en.txt
+ */
+
+package org.scilab.forge.scirenderer.shapes.appearance;
+
+/**
+ * Material class used for lighting
+ * @author Pedro SOUZA
+ */
+public class Material {
+
+ /** enable use color as material */
+ private boolean colorMaterial = true;
+ /** ambient color */
+ private Color ambient;
+ /** diffuse color*/
+ private Color diffuse;
+ /** specular color */
+ private Color specular;
+ /** shininess level */
+ private float shininess;
+
+ /**
+ * @param the new ambient color;.
+ */
+ public void setAmbientColor(Color color) {
+ ambient = color;
+ }
+
+ /**
+ * @param the new diffuse color.
+ */
+ public void setDiffuseColor(Color color) {
+ diffuse = color;
+ }
+
+ /**
+ * @param the new specular color.
+ */
+ public void setSpecularColor(Color color) {
+ specular = color;
+ }
+
+ /**
+ * @param the new shinines.
+ */
+ public void setShininess(float s) {
+ shininess = s;
+ }
+
+ /**
+ * @return the ambient color.
+ */
+ public Color getAmbientColor() {
+ return ambient;
+ }
+
+ /**
+ * @return the diffuse color.
+ */
+ public Color getDiffuseColor() {
+ return diffuse;
+ }
+
+ /**
+ * @return the specular color.
+ */
+ public Color getSpecularColor() {
+ return specular;
+ }
+
+ /**
+ * @return the shininess.
+ */
+ public float getShininess() {
+ return shininess;
+ }
+
+ /**
+ * @return the color material status.
+ */
+ public boolean isColorMaterialEnable() {
+ return colorMaterial;
+ }
+
+ /**
+ * @param the new color material status.
+ */
+ public void setColorMaterialEnable(boolean status) {
+ colorMaterial = status;
+ }
+}
diff --git a/modules/scirenderer/src/org/scilab/forge/scirenderer/shapes/geometry/DefaultGeometry.java b/modules/scirenderer/src/org/scilab/forge/scirenderer/shapes/geometry/DefaultGeometry.java
new file mode 100755
index 000000000..8e2865457
--- /dev/null
+++ b/modules/scirenderer/src/org/scilab/forge/scirenderer/shapes/geometry/DefaultGeometry.java
@@ -0,0 +1,175 @@
+/*
+ * Scilab ( http://www.scilab.org/ ) - This file is part of Scilab
+ * Copyright (C) 2009-2011 - DIGITEO - Pierre Lando
+ *
+ * This file must be used under the terms of the CeCILL.
+ * This source file is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at
+ * http://www.cecill.info/licences/Licence_CeCILL_V2.1-en.txt
+ */
+
+package org.scilab.forge.scirenderer.shapes.geometry;
+
+import org.scilab.forge.scirenderer.buffers.ElementsBuffer;
+import org.scilab.forge.scirenderer.buffers.IndicesBuffer;
+
+/**
+ *
+ * Default implementation of a Geometry.
+ *
+ * @author Pierre Lando
+ */
+public class DefaultGeometry implements Geometry {
+
+ private FaceCullingMode faceCullingMode = DEFAULT_FACE_CULLING_MODE;
+ private FillDrawingMode fillDrawingMode = DEFAULT_FILL_DRAWING_MODE;
+ private LineDrawingMode lineDrawingMode = DEFAULT_LINE_DRAWING_MODE;
+
+ /** Specifies whether polygon offset is used or not when rendering geometry. */
+ private boolean polygonOffsetMode = DEFAULT_POLYGON_OFFSET_MODE;
+
+ private ElementsBuffer textureCoordinates;
+ private ElementsBuffer vertices;
+ private ElementsBuffer normals;
+ private ElementsBuffer colors;
+
+ private IndicesBuffer wireIndices;
+ private IndicesBuffer indices;
+
+ /**
+ * Default constructor.
+ */
+ public DefaultGeometry() {
+ }
+
+ @Override
+ public final FaceCullingMode getFaceCullingMode() {
+ return faceCullingMode;
+ }
+
+ @Override
+ public final FillDrawingMode getFillDrawingMode() {
+ return fillDrawingMode;
+ }
+
+ @Override
+ public final LineDrawingMode getLineDrawingMode() {
+ return lineDrawingMode;
+ }
+
+ @Override
+ public final boolean getPolygonOffsetMode() {
+ return polygonOffsetMode;
+ }
+
+ @Override
+ public final ElementsBuffer getVertices() {
+ return vertices;
+ }
+
+ @Override
+ public final IndicesBuffer getIndices() {
+ return indices;
+ }
+
+ @Override
+ public final IndicesBuffer getWireIndices() {
+ return wireIndices;
+ }
+
+ @Override
+ public final ElementsBuffer getColors() {
+ return colors;
+ }
+
+ @Override
+ public final ElementsBuffer getTextureCoordinates() {
+ return textureCoordinates;
+ }
+
+ @Override
+ public final ElementsBuffer getNormals() {
+ return normals;
+ }
+
+ /**
+ * Face culling mode setter.
+ * @param faceCullingMode the new face culling mode.
+ */
+ public final void setFaceCullingMode(FaceCullingMode faceCullingMode) {
+ this.faceCullingMode = faceCullingMode;
+ }
+
+ /**
+ * Fill drawing mode setter.
+ * @param fillDrawingMode the new fill drawing mode.
+ */
+ public final void setFillDrawingMode(FillDrawingMode fillDrawingMode) {
+ this.fillDrawingMode = fillDrawingMode;
+ }
+
+ /**
+ * Line drawing mode setter.
+ * @param lineDrawingMode the new line drawing mode.
+ */
+ public final void setLineDrawingMode(LineDrawingMode lineDrawingMode) {
+ this.lineDrawingMode = lineDrawingMode;
+ }
+
+ /**
+ * Polygon offset mode setter.
+ * @param polygonOffsetMode the new polygon offset mode.
+ */
+ public final void setPolygonOffsetMode(boolean polygonOffsetMode) {
+ this.polygonOffsetMode = polygonOffsetMode;
+ }
+
+ /**
+ * Texture coordinates setter.
+ * @param textureCoordinates the new texture coordinate data.
+ */
+ public final void setTextureCoordinates(ElementsBuffer textureCoordinates) {
+ this.textureCoordinates = textureCoordinates;
+ }
+
+ /**
+ * Vertices setter.
+ * @param vertices the new vertices data.
+ */
+ public final void setVertices(ElementsBuffer vertices) {
+ this.vertices = vertices;
+ }
+
+ /**
+ * Normals setter.
+ * @param normals the new normals data.
+ */
+ public final void setNormals(ElementsBuffer normals) {
+ this.normals = normals;
+ }
+
+ /**
+ * Colors setter.
+ * @param colors the new colors data.
+ */
+ public final void setColors(ElementsBuffer colors) {
+ this.colors = colors;
+ }
+
+ /**
+ * Wire indices setter.
+ * @param wireIndices the new wire indices data.
+ */
+ public final void setWireIndices(IndicesBuffer wireIndices) {
+ this.wireIndices = wireIndices;
+ }
+
+ /**
+ * Indices setter.
+ * @param indicesBuffer the new indices data.
+ */
+ public final void setIndices(IndicesBuffer indicesBuffer) {
+ this.indices = indicesBuffer;
+ }
+}
diff --git a/modules/scirenderer/src/org/scilab/forge/scirenderer/shapes/geometry/Geometry.java b/modules/scirenderer/src/org/scilab/forge/scirenderer/shapes/geometry/Geometry.java
new file mode 100755
index 000000000..bb81c7a18
--- /dev/null
+++ b/modules/scirenderer/src/org/scilab/forge/scirenderer/shapes/geometry/Geometry.java
@@ -0,0 +1,176 @@
+/*
+ * Scilab ( http://www.scilab.org/ ) - This file is part of Scilab
+ * Copyright (C) 2009-2011 - DIGITEO - Pierre Lando
+ *
+ * This file must be used under the terms of the CeCILL.
+ * This source file is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at
+ * http://www.cecill.info/licences/Licence_CeCILL_V2.1-en.txt
+ */
+
+package org.scilab.forge.scirenderer.shapes.geometry;
+
+import org.scilab.forge.scirenderer.buffers.ElementsBuffer;
+import org.scilab.forge.scirenderer.buffers.IndicesBuffer;
+
+/**
+ *
+ * Interface for a geometry.
+ *
+ * @author Pierre Lando
+ */
+public interface Geometry {
+
+ /**
+ * This enum specify face culling.
+ */
+ enum FaceCullingMode {
+ /**
+ * Both faces are rendered (default value)
+ */
+ BOTH,
+
+ /**
+ * Only counter clockwise faces are visible.
+ */
+ CCW,
+
+ /**
+ * Only clockwise faces are visible.
+ */
+ CW
+ }
+
+ /**
+ * Default face culling mode.
+ */
+ FaceCullingMode DEFAULT_FACE_CULLING_MODE = FaceCullingMode.BOTH;
+
+ /**
+ * This enum specify how geometry is rendered.
+ */
+ enum FillDrawingMode {
+ /**
+ * Treats each triplet of vertices as an independent triangle.
+ */
+ TRIANGLES,
+
+ /**
+ * Draws a connected group of triangles.
+ */
+ TRIANGLE_STRIP,
+
+ /**
+ * Draws a connected group of triangles with common first element.
+ */
+ TRIANGLE_FAN,
+
+ /**
+ * Nothing is filled.
+ */
+ NONE
+ }
+
+ /**
+ * Default fill drawing mode.
+ */
+ FillDrawingMode DEFAULT_FILL_DRAWING_MODE = FillDrawingMode.TRIANGLES;
+
+ /**
+ * Line drawing modes declaration.
+ */
+ enum LineDrawingMode {
+ /**
+ * Each pair of vertices define an independent segment.
+ */
+ SEGMENTS,
+
+ /**
+ * Connected group of segments from the first vertex to the last.
+ */
+ SEGMENTS_STRIP,
+
+ /**
+ * Connected group of segments from the first vertex to the last, then back to the first.
+ */
+ SEGMENTS_LOOP,
+
+ /**
+ * No segments.
+ */
+ NONE
+ }
+
+ /**
+ * Default wire drawing mode.
+ */
+ LineDrawingMode DEFAULT_LINE_DRAWING_MODE = LineDrawingMode.NONE;
+
+ /**
+ * Default polygon offset mode.
+ */
+ boolean DEFAULT_POLYGON_OFFSET_MODE = false;
+
+ /**
+ * Face-culling mode getter.
+ * @return the face culling mode.
+ */
+ FaceCullingMode getFaceCullingMode();
+
+ /**
+ * Fill drawing mode getter.
+ * @return the fill-drawing mode for this object.
+ */
+ FillDrawingMode getFillDrawingMode();
+
+ /**
+ * Line drawing mode getter.
+ * @return the line drawing mode.
+ */
+ LineDrawingMode getLineDrawingMode();
+
+ /**
+ * Polygon offset mode getter.
+ * @return the polygon offset mode.
+ */
+ boolean getPolygonOffsetMode();
+
+ /**
+ * Return the vertices.
+ * @return the vertices.
+ */
+ ElementsBuffer getVertices();
+
+ /**
+ * Return the colors.
+ * @return the colors.
+ */
+ ElementsBuffer getColors();
+
+ /**
+ * Texture coordinates getter.
+ * @return the texture coordinate.
+ */
+ ElementsBuffer getTextureCoordinates();
+
+ /**
+ * Return the normals.
+ * @return the normals.
+ */
+ ElementsBuffer getNormals();
+
+ /**
+ * Return the indices if any.
+ * If <code>null</code> is returned, indices should be treated as consecutive number.
+ * @return the indices.
+ */
+ IndicesBuffer getIndices();
+
+ /**
+ * Return the wire indices.
+ * If <code>null</code> is returned, no edges are drawn.
+ * @return the edges indices.
+ */
+ IndicesBuffer getWireIndices();
+}
diff --git a/modules/scirenderer/src/org/scilab/forge/scirenderer/texture/AbstractTexture.java b/modules/scirenderer/src/org/scilab/forge/scirenderer/texture/AbstractTexture.java
new file mode 100755
index 000000000..afa5506de
--- /dev/null
+++ b/modules/scirenderer/src/org/scilab/forge/scirenderer/texture/AbstractTexture.java
@@ -0,0 +1,132 @@
+/*
+ * Scilab ( http://www.scilab.org/ ) - This file is part of Scilab
+ * Copyright (C) 2009-2012 - DIGITEO - Pierre Lando
+ *
+ * This file must be used under the terms of the CeCILL.
+ * This source file is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at
+ * http://www.cecill.info/licences/Licence_CeCILL_V2.1-en.txt
+ */
+
+package org.scilab.forge.scirenderer.texture;
+
+/**
+ * @author Pierre Lando
+ */
+public class AbstractTexture implements Texture {
+
+ /**
+ * Texture data provider.
+ */
+ protected TextureDataProvider textureDataProvider;
+
+ /**
+ * True if the data are up to date.
+ */
+ protected boolean upToDate;
+
+ /**
+ * Current magnification filtering method.
+ */
+ private Filter magnificationFilter = Filter.NEAREST;
+
+ /**
+ * Current minifying filtering method.
+ */
+ private Filter minifyingFilter = Filter.NEAREST;
+
+ private Wrap sWrappingMode = Wrap.CLAMP;
+ private Wrap tWrappingMode = Wrap.CLAMP;
+
+ /**
+ * Default constructor.
+ */
+ public AbstractTexture() {
+ upToDate = false;
+ }
+
+ @Override
+ public synchronized boolean isValid() {
+ return (textureDataProvider != null) && (textureDataProvider.isValid());
+ }
+
+ @Override
+ public Wrap getSWrappingMode() {
+ return sWrappingMode;
+ }
+
+ @Override
+ public void setSWrappingMode(Wrap sWrappingMode) {
+ this.sWrappingMode = sWrappingMode;
+ }
+
+ @Override
+ public Wrap getTWrappingMode() {
+ return tWrappingMode;
+ }
+
+ @Override
+ public void setTWrappingMode(Wrap tWrappingMode) {
+ this.tWrappingMode = tWrappingMode;
+ }
+
+ @Override
+ public Filter getMinifyingFilter() {
+ return minifyingFilter;
+ }
+
+ @Override
+ public void setMinifyingFilter(Filter minifyingFilter) {
+ this.minifyingFilter = minifyingFilter;
+ }
+
+ @Override
+ public Filter getMagnificationFilter() {
+ return magnificationFilter;
+ }
+
+ @Override
+ public void setMagnificationFilter(Filter magnificationFilter) {
+ this.magnificationFilter = magnificationFilter;
+ }
+
+ @Override
+ public synchronized TextureDataProvider getDataProvider() {
+ return textureDataProvider;
+ }
+
+ @Override
+ public synchronized void setDataProvider(TextureDataProvider provider) {
+ if (textureDataProvider != null) {
+ textureDataProvider.removeDataUser(this);
+ }
+
+ textureDataProvider = provider;
+ upToDate = false;
+
+ if (textureDataProvider != null) {
+ textureDataProvider.addDataUser(this);
+ }
+ }
+
+ @Override
+ public void setDrawer(TextureDrawer textureDrawer) {
+ setDataProvider(new DrawnTextureDataProvider(textureDrawer));
+ }
+
+ @Override
+ public void dataUpdated() {
+ upToDate = false;
+ }
+
+ @Override
+ public double getSScaleFactor() {
+ return 1;
+ }
+
+ @Override
+ public double getTScaleFactor() {
+ return 1;
+ }
+}
diff --git a/modules/scirenderer/src/org/scilab/forge/scirenderer/texture/AbstractTextureDataProvider.java b/modules/scirenderer/src/org/scilab/forge/scirenderer/texture/AbstractTextureDataProvider.java
new file mode 100755
index 000000000..c37bacc4e
--- /dev/null
+++ b/modules/scirenderer/src/org/scilab/forge/scirenderer/texture/AbstractTextureDataProvider.java
@@ -0,0 +1,71 @@
+/*
+ * Scilab ( http://www.scilab.org/ ) - This file is part of Scilab
+ * Copyright (C) 2012 - Scilab Enterprises - Calixte DENIZET
+ *
+ * This file must be used under the terms of the CeCILL.
+ * This source file is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at
+ * http://www.cecill.info/licences/Licence_CeCILL_V2.1-en.txt
+ */
+
+package org.scilab.forge.scirenderer.texture;
+
+import java.awt.Dimension;
+import java.awt.image.BufferedImage;
+import java.nio.ByteBuffer;
+
+import org.scilab.forge.scirenderer.data.AbstractDataProvider;
+
+/**
+ * @author Calixte DENIZET
+ */
+public abstract class AbstractTextureDataProvider extends AbstractDataProvider<Texture> implements TextureDataProvider {
+
+ protected ImageType imageType;
+
+ @Override
+ public ImageType getImageType() {
+ return imageType;
+ }
+
+ @Override
+ public boolean isRowMajorOrder() {
+ return true;
+ }
+
+ @Override
+ public BufferedImage getImage() {
+ final ByteBuffer data = getData();
+ if (data == null) {
+ return null;
+ }
+
+ data.rewind();
+ Dimension size = getTextureSize();
+ final int width = size.width;
+ final int height = size.height;
+
+ final int[] ibuffer = new int[data.capacity() / 4];
+ final byte[] RGBA = new byte[4];
+ for (int i = 0; i < ibuffer.length; i++) {
+ data.get(RGBA);
+ ibuffer[i] = ((RGBA[3] & 0xFF) << 24) + ((RGBA[0] & 0xFF) << 16) + ((RGBA[1] & 0xFF) << 8) + (RGBA[2] & 0xFF);
+ }
+ data.rewind();
+ BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB);
+ image.setRGB(0, 0, width, height, ibuffer, 0, width);
+
+ return image;
+ }
+
+ @Override
+ public BufferedImage getSubImage(int x, int y, int width, int height) {
+ BufferedImage image = getImage();
+ if (image == null) {
+ return null;
+ }
+
+ return image.getSubimage(x, y, width, height);
+ }
+}
diff --git a/modules/scirenderer/src/org/scilab/forge/scirenderer/texture/AnchorPosition.java b/modules/scirenderer/src/org/scilab/forge/scirenderer/texture/AnchorPosition.java
new file mode 100755
index 000000000..9e91e778d
--- /dev/null
+++ b/modules/scirenderer/src/org/scilab/forge/scirenderer/texture/AnchorPosition.java
@@ -0,0 +1,63 @@
+/*
+ * Scilab ( http://www.scilab.org/ ) - This file is part of Scilab
+ * Copyright (C) 2009-2011 - DIGITEO - Pierre Lando
+ *
+ * This file must be used under the terms of the CeCILL.
+ * This source file is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at
+ * http://www.cecill.info/licences/Licence_CeCILL_V2.1-en.txt
+ */
+
+package org.scilab.forge.scirenderer.texture;
+
+/**
+ * This is an enumeration of possible sprite anchor position.
+ * @author Pierre Lando
+ */
+public enum AnchorPosition {
+ /**
+ * Anchor is in the upper left sprite corner.
+ */
+ UPPER_LEFT,
+
+ /**
+ * Anchor is in the upper right sprite corner.
+ */
+ UPPER_RIGHT,
+
+ /**
+ * Anchor is in the lower left sprite corner.
+ */
+ LOWER_LEFT,
+
+ /**
+ * Anchor is in the lower right sprite corner.
+ */
+ LOWER_RIGHT,
+
+ /**
+ * Anchor is in the sprite center.
+ */
+ CENTER,
+
+ /**
+ * Anchor is in the center of the right edge of the sprite.
+ */
+ RIGHT,
+
+ /**
+ * Anchor is in the center of the left edge of the sprite.
+ */
+ LEFT,
+
+ /**
+ * Anchor is in the center of the down edge of the sprite.
+ */
+ DOWN,
+
+ /**
+ * Anchor is in the center of the upper edge of the sprite.
+ */
+ UP,
+}
diff --git a/modules/scirenderer/src/org/scilab/forge/scirenderer/texture/BufferedImageTextureDrawingTools.java b/modules/scirenderer/src/org/scilab/forge/scirenderer/texture/BufferedImageTextureDrawingTools.java
new file mode 100755
index 000000000..81eb74b99
--- /dev/null
+++ b/modules/scirenderer/src/org/scilab/forge/scirenderer/texture/BufferedImageTextureDrawingTools.java
@@ -0,0 +1,202 @@
+/*
+ * Scilab ( http://www.scilab.org/ ) - This file is part of Scilab
+ * Copyright (C) 2009-2012 - DIGITEO - Pierre Lando
+ *
+ * This file must be used under the terms of the CeCILL.
+ * This source file is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at
+ * http://www.cecill.info/licences/Licence_CeCILL_V2.1-en.txt
+ */
+
+package org.scilab.forge.scirenderer.texture;
+
+import org.scilab.forge.scirenderer.implementation.jogl.utils.G2DShortCuts;
+import org.scilab.forge.scirenderer.shapes.appearance.Appearance;
+import org.scilab.forge.scirenderer.shapes.appearance.Color;
+
+import javax.swing.Icon;
+import javax.swing.JLabel;
+import java.awt.AlphaComposite;
+import java.awt.Dimension;
+import java.awt.Graphics2D;
+import java.awt.RenderingHints;
+import java.awt.font.TextLayout;
+import java.awt.geom.AffineTransform;
+import java.awt.geom.Rectangle2D;
+
+/**
+ *
+ * Implementation of {@link org.scilab.forge.scirenderer.texture.TextureDrawingTools}.
+ * This implementation create a {@link TextureBufferedImage} an fill it with texture drawing.
+ *
+ * @author Pierre Lando
+ */
+public class BufferedImageTextureDrawingTools implements TextureDrawingTools {
+
+ /**
+ * The {@link Graphics2D} used to fill the {@link TextureBufferedImage}
+ */
+ private Graphics2D g2d;
+ private final TextureBufferedImage image;
+ private final Dimension textureSize;
+ private final AffineTransform baseTransform;
+
+ /**
+ * Default constructor.
+ * @param textureSize the texture size.
+ */
+ public BufferedImageTextureDrawingTools(Dimension textureSize) {
+ image = new TextureBufferedImage(textureSize.width, textureSize.height);
+ this.textureSize = textureSize;
+
+ double deltaW = (image.getWidth() - textureSize.width) / 2.0;
+ double deltaH = (image.getHeight() - textureSize.height) / 2.0;
+ baseTransform = AffineTransform.getTranslateInstance(deltaW, deltaH);
+ }
+
+ /**
+ * Ask this image to accept a texture drawer.
+ * This image will contain the drawing of the given drawer.
+ * @param textureDrawer the given texture drawer.
+ */
+ public void accept(TextureDrawer textureDrawer) {
+ g2d = image.createGraphics();
+ g2d.setComposite(AlphaComposite.Src);
+ g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
+ RenderingHints.VALUE_ANTIALIAS_ON);
+ g2d.setRenderingHint(RenderingHints.KEY_RENDERING,
+ RenderingHints.VALUE_RENDER_QUALITY);
+ g2d.transform(baseTransform);
+
+ // Change center coordinate to (0, 0).
+ if (textureDrawer.getOriginPosition() == TextureDrawer.OriginPosition.CENTER) {
+ g2d.translate(textureSize.width / 2, textureSize.height / 2);
+ }
+
+ textureDrawer.draw(this);
+
+ g2d.dispose();
+ }
+
+ @Override
+ public void drawPlus(int size, Appearance appearance) {
+ int r = size / 2;
+ int[] coords1 = new int[] { -r, 0, r, 0};
+ drawPolyline(coords1, appearance);
+ if (r != 0) {
+ int[] coords2 = new int[] {0, -r, 0, r};
+ drawPolyline(coords2, appearance);
+ }
+ }
+
+ @Override
+ public void drawPolyline(int[] coordinates, Appearance appearance) {
+ int nbPoint = coordinates.length / 2;
+
+ int[] xCoordinates = new int[nbPoint];
+ int[] yCoordinates = new int[nbPoint];
+
+ int k = 0;
+ for (int i = 0; i < coordinates.length; i += 2) {
+ xCoordinates[k] = coordinates[i];
+ yCoordinates[k] = coordinates[i + 1];
+ k++;
+ }
+
+ G2DShortCuts.useLineAppearance(g2d, appearance);
+ G2DShortCuts.useColor(g2d, appearance.getLineColor());
+ g2d.drawPolyline(xCoordinates, yCoordinates, nbPoint);
+
+ }
+
+ @Override
+ public void fillPolygon(int[] coordinates, Appearance appearance) {
+ int nbPoint = coordinates.length / 2;
+
+ int[] xCoordinates = new int[nbPoint];
+ int[] yCoordinates = new int[nbPoint];
+
+ int k = 0;
+ for (int i = 0; i < coordinates.length; i += 2) {
+ xCoordinates[k] = coordinates[i];
+ yCoordinates[k] = coordinates[i + 1];
+ k++;
+ }
+
+ if (appearance.getFillColor().getAlphaAsFloat() != 0) {
+ G2DShortCuts.useColor(g2d, appearance.getFillColor());
+ g2d.fillPolygon(xCoordinates, yCoordinates, nbPoint);
+ }
+
+ if (!appearance.getLineColor().equals(appearance.getFillColor())) {
+ int usedLength = coordinates.length - (coordinates.length % 2);
+ int[] borderCoordinate = new int[usedLength + 2];
+ System.arraycopy(coordinates, 0, borderCoordinate, 0, usedLength);
+ borderCoordinate[usedLength] = coordinates[0];
+ borderCoordinate[usedLength + 1] = coordinates[1];
+
+ drawPolyline(borderCoordinate, appearance);
+ }
+ }
+
+ @Override
+ public void drawCircle(int x, int y, int diameter, Appearance appearance) {
+ G2DShortCuts.useLineAppearance(g2d, appearance);
+ G2DShortCuts.useColor(g2d, appearance.getLineColor());
+ int r = diameter / 2;
+ g2d.drawOval(x - r, y - r, diameter, diameter);
+ }
+
+ @Override
+ public void fillDisc(int x, int y, int diameter, Color color) {
+ if (color.getAlphaAsFloat() != 0) {
+ G2DShortCuts.useColor(g2d, color);
+ int r = diameter / 2;
+ g2d.fillOval(x - r, y - r, diameter, diameter);
+ }
+ }
+
+ @Override
+ public void draw(TextEntity textEntity, int x, int y) {
+ if ((textEntity != null) && (textEntity.isValid())) {
+ if (textEntity.isTextAntiAliased()) {
+ g2d.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_ON);
+ } else {
+ g2d.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_OFF);
+ }
+
+ if (textEntity.isTextUseFractionalMetrics()) {
+ g2d.setRenderingHint(RenderingHints.KEY_FRACTIONALMETRICS, RenderingHints.VALUE_FRACTIONALMETRICS_ON);
+ } else {
+ g2d.setRenderingHint(RenderingHints.KEY_FRACTIONALMETRICS, RenderingHints.VALUE_FRACTIONALMETRICS_OFF);
+ }
+ g2d.setColor(textEntity.getTextColor());
+ TextLayout textLayout = new TextLayout(textEntity.getText(), textEntity.getFont(), g2d.getFontRenderContext());
+ Rectangle2D bounds = textLayout.getBounds();
+ textLayout.draw(g2d, (float) (x + 1 - bounds.getX()), y + textLayout.getAscent());
+ }
+ }
+
+ @Override
+ public void draw(Icon icon, int x, int y) {
+ icon.paintIcon(new JLabel(), g2d, x, y);
+ }
+
+ @Override
+ public void clear(Color color) {
+ AffineTransform oldTransform = g2d.getTransform();
+ g2d.setTransform(baseTransform);
+ G2DShortCuts.useColor(g2d, color);
+ g2d.fillRect(0, 0, textureSize.width, textureSize.height);
+ g2d.setTransform(oldTransform);
+ }
+
+ /**
+ * Return the image.
+ * @return the image.
+ */
+ public TextureBufferedImage getImage() {
+ return image;
+ }
+}
diff --git a/modules/scirenderer/src/org/scilab/forge/scirenderer/texture/DrawnTextureDataProvider.java b/modules/scirenderer/src/org/scilab/forge/scirenderer/texture/DrawnTextureDataProvider.java
new file mode 100755
index 000000000..db228e88d
--- /dev/null
+++ b/modules/scirenderer/src/org/scilab/forge/scirenderer/texture/DrawnTextureDataProvider.java
@@ -0,0 +1,134 @@
+/*
+ * Scilab ( http://www.scilab.org/ ) - This file is part of Scilab
+ * Copyright (C) 2009-2012 - DIGITEO - Pierre Lando
+ *
+ * This file must be used under the terms of the CeCILL.
+ * This source file is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at
+ * http://www.cecill.info/licences/Licence_CeCILL_V2.1-en.txt
+ */
+
+package org.scilab.forge.scirenderer.texture;
+
+import org.scilab.forge.scirenderer.data.AbstractDataProvider;
+
+import java.awt.Dimension;
+import java.awt.image.BufferedImage;
+import java.nio.ByteBuffer;
+
+/**
+ * @author Pierre Lando
+ */
+public class DrawnTextureDataProvider extends AbstractDataProvider<Texture> implements TextureDataProvider {
+
+ /** Texture drawer */
+ private TextureDrawer textureDrawer;
+ protected ImageType imageType;
+
+ /** Current image */
+ BufferedImageTextureDrawingTools image;
+
+ public DrawnTextureDataProvider(TextureDrawer textureDrawer) {
+ this.textureDrawer = textureDrawer;
+ imageType = ImageType.RGBA_BYTE;
+ //reDraw();
+ }
+
+ @Override
+ public ImageType getImageType() {
+ return imageType;
+ }
+
+ @Override
+ public boolean isRowMajorOrder() {
+ return true;
+ }
+
+ /** Reload the texture and recall the texture drawing tools. */
+ public void reDraw() {
+ if (isValid()) {
+ image = new BufferedImageTextureDrawingTools(textureDrawer.getTextureSize());
+ image.accept(textureDrawer);
+ }
+ }
+
+ /**
+ * Texture drawer setter.
+ * @param textureDrawer the new texture drawer.
+ */
+ public void setTextureDrawingTools(TextureDrawer textureDrawer) {
+ this.textureDrawer = textureDrawer;
+ reDraw();
+ }
+
+ @Override
+ public Dimension getTextureSize() {
+ if (isValid()) {
+ return textureDrawer.getTextureSize();
+ } else {
+ return new Dimension(-1, -1);
+ }
+ }
+
+ @Override
+ public ByteBuffer getData() {
+ if (isValid()) {
+ if (image == null) {
+ reDraw();
+ }
+ return image.getImage().getRGBABuffer();
+ } else {
+ return null;
+ }
+ }
+
+ @Override
+ public ByteBuffer getSubData(int x, int y, int width, int height) {
+ if (isValid()) {
+ ByteBuffer buffer = getData();
+ return buffer;
+ /*
+ ByteBuffer tempBuffer = ByteBuffer.allocate(4 * width * height);
+ byte[] data = new byte[4 * height];
+ for (int j = y; j < y + height; j++) {
+ buffer.position(4 * (x + j * getTextureSize().width));
+ buffer.get(data);
+ tempBuffer.put(data);
+ }
+ tempBuffer.rewind();
+ buffer.rewind();
+ return tempBuffer;
+ */
+ } else {
+ return null;
+ }
+ }
+
+ @Override
+ public BufferedImage getImage() {
+ if (isValid()) {
+ if (image == null) {
+ reDraw();
+ }
+ return image.getImage();
+ } else {
+ return null;
+ }
+ }
+
+ @Override
+ public BufferedImage getSubImage(int x, int y, int width, int height) {
+ if (isValid()) {
+ BufferedImage image = getImage();
+ return image.getSubimage(x, y, width, height);
+ } else {
+ return null;
+ }
+ }
+
+ @Override
+ public boolean isValid() {
+ return textureDrawer != null;
+ }
+}
diff --git a/modules/scirenderer/src/org/scilab/forge/scirenderer/texture/TextEntity.java b/modules/scirenderer/src/org/scilab/forge/scirenderer/texture/TextEntity.java
new file mode 100755
index 000000000..21df6e29a
--- /dev/null
+++ b/modules/scirenderer/src/org/scilab/forge/scirenderer/texture/TextEntity.java
@@ -0,0 +1,203 @@
+/*
+ * Scilab ( http://www.scilab.org/ ) - This file is part of Scilab
+ * Copyright (C) 2009-2012 - DIGITEO - Pierre Lando
+ *
+ * This file must be used under the terms of the CeCILL.
+ * This source file is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at
+ * http://www.cecill.info/licences/Licence_CeCILL_V2.1-en.txt
+ */
+
+package org.scilab.forge.scirenderer.texture;
+
+import org.scilab.forge.scirenderer.shapes.appearance.Color;
+
+import java.awt.Dimension;
+import java.awt.Font;
+import java.awt.font.FontRenderContext;
+import java.awt.font.TextLayout;
+import java.awt.geom.Rectangle2D;
+
+/**
+ * @author Pierre Lando
+ */
+public class TextEntity {
+
+ /**
+ * The default text color.
+ */
+ public static final Color DEFAULT_TEXT_COLOR = new Color(0.f, 0.f, 0.f);
+
+ /**
+ * The default text anti-aliased status.
+ */
+ public static final boolean DEFAULT_TEXT_ANTI_ALIASED = true;
+
+ /**
+ * The default text use fractional matrix status.
+ */
+ public static final boolean DEFAULT_TEXT_USE_FRACTIONAL_METRICS = true;
+
+ /**
+ * The default font.
+ */
+ private static final Font DEFAULT_FONT = new Font(null);
+
+ /**
+ * The current text color.
+ */
+ private Color textColor = DEFAULT_TEXT_COLOR;
+
+ /**
+ * The current text anti-aliased status.
+ */
+ private boolean textAntiAliased = DEFAULT_TEXT_ANTI_ALIASED;
+
+ /**
+ * The current text use fractional matrix status.
+ */
+ private boolean textUseFractionalMetrics = DEFAULT_TEXT_USE_FRACTIONAL_METRICS;
+
+ /**
+ * The text content of this object.
+ */
+ private String text;
+
+ /**
+ * The font used by this text entity.
+ */
+ private Font font;
+
+ private TextLayout layout;
+
+ /**
+ * Default constructor.
+ * @param text the text content.
+ */
+ public TextEntity(String text) {
+ this.text = text;
+ this.font = DEFAULT_FONT;
+ }
+
+ /**
+ * Return the text content.
+ * @return the text content.
+ */
+ public String getText() {
+ return text;
+ }
+
+ /**
+ * Set the text content.
+ * @param text the new text content.
+ */
+ public void setText(String text) {
+ this.text = text;
+ this.layout = null;
+ }
+
+ /**
+ * Return the text font.
+ * @return the text font.
+ */
+ public Font getFont() {
+ return font;
+ }
+
+ /**
+ * Set the text font.
+ * @param font the new text font.
+ */
+ public void setFont(Font font) {
+ this.font = font;
+ this.layout = null;
+ }
+
+ /**
+ * Return the text color.
+ * @return the text color.
+ */
+ public Color getTextColor() {
+ return textColor;
+ }
+
+ /**
+ * Set the text color.
+ * @param textColor the new text color.
+ */
+ public void setTextColor(Color textColor) {
+ this.textColor = textColor;
+ }
+
+ /**
+ * Return the text anti-aliased status.
+ * @return the text anti-aliased status.
+ */
+ public boolean isTextAntiAliased() {
+ return textAntiAliased;
+ }
+
+ /**
+ * Set the text anti-aliased status.
+ * @param textAntiAliased the new text anti-aliased status.
+ */
+ public void setTextAntiAliased(boolean textAntiAliased) {
+ this.textAntiAliased = textAntiAliased;
+ this.layout = null;
+ }
+
+ /**
+ * Return the text use fractional metrics status.
+ * @return the text use fractional metrics status.
+ */
+ public boolean isTextUseFractionalMetrics() {
+ return textUseFractionalMetrics;
+ }
+
+ /**
+ * Set the text use fractional metrics status.
+ * @param textUseFractionalMetrics the new text use fractional metrics status.
+ */
+ public void setTextUseFractionalMetrics(boolean textUseFractionalMetrics) {
+ this.textUseFractionalMetrics = textUseFractionalMetrics;
+ this.layout = null;
+ }
+
+ /**
+ * TextEntity validity getter.
+ * @return true if the text entity is valid.
+ */
+ public boolean isValid() {
+ return ((getFont() != null)
+ && (getText() != null)
+ && (getText().length() > 0)
+ );
+ }
+
+ public TextLayout getLayout() {
+ if (layout == null) {
+ FontRenderContext frc = new FontRenderContext(null, isTextAntiAliased(), isTextUseFractionalMetrics());
+ layout = new TextLayout(getText(), getFont(), frc);
+ }
+
+ return layout;
+ }
+
+ /**
+ * Return the dimension in pixel of the text entity.
+ * @return the dimension in pixel of the text entity.
+ */
+ public Dimension getSize() {
+ if (isValid()) {
+ TextLayout textLayout = getLayout();
+ Dimension dimension = new Dimension();
+ Rectangle2D r = textLayout.getBounds();
+ /* +1 added to fix rendering of ticks labels, a pixel row/column was missing */
+ dimension.setSize(r.getWidth() + 2, textLayout.getAscent() + textLayout.getDescent() + 1);
+ return dimension;
+ } else {
+ return new Dimension(0, 0);
+ }
+ }
+}
diff --git a/modules/scirenderer/src/org/scilab/forge/scirenderer/texture/Texture.java b/modules/scirenderer/src/org/scilab/forge/scirenderer/texture/Texture.java
new file mode 100755
index 000000000..3c6b48181
--- /dev/null
+++ b/modules/scirenderer/src/org/scilab/forge/scirenderer/texture/Texture.java
@@ -0,0 +1,140 @@
+/*
+ * Scilab ( http://www.scilab.org/ ) - This file is part of Scilab
+ * Copyright (C) 2009-2012 - DIGITEO - Pierre Lando
+ *
+ * This file must be used under the terms of the CeCILL.
+ * This source file is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at
+ * http://www.cecill.info/licences/Licence_CeCILL_V2.1-en.txt
+ */
+
+package org.scilab.forge.scirenderer.texture;
+
+import org.scilab.forge.scirenderer.data.DataUser;
+
+/**
+ * @author Pierre Lando
+ */
+public interface Texture extends DataUser {
+
+ /**
+ * Enumeration of wrapping possibility.
+ */
+ public enum Wrap {
+ /**
+ * REPEAT: the integer part of the texture coordinate to be ignored.
+ */
+ REPEAT,
+
+ /**
+ * CLAMP: the texture coordinate is clamped to [0, 1].
+ */
+ CLAMP
+ }
+
+ /**
+ * Enumeration of filtering possibility.
+ */
+ public enum Filter {
+ /**
+ * Use the value of the texture element that is nearest (in Manhattan distance) to the center of the pixel being textured.
+ */
+ NEAREST,
+
+ /**
+ * Use the weighted average of the four texture elements that are closest to the center of the pixel being textured.
+ */
+ LINEAR
+ }
+
+ /**
+ * Texture validity getter.
+ * @return true is this texture is valid and can be used for rendering.
+ */
+ boolean isValid();
+
+ /**
+ * Wrapping mode on the first texture coordinate getter.
+ * For more information on wrapping mode {see Wrap}.
+ * @return the wrapping mode on the first texture coordinate.
+ */
+ Wrap getSWrappingMode();
+
+ /**
+ * Wrapping mode on the first texture coordinate.
+ * @param wrappingMode the new wrapping mode on the first texture coordinate.
+ */
+ void setSWrappingMode(Wrap wrappingMode);
+
+ /**
+ * Wrapping mode on the second dimension getter.
+ * If the texture dimension is 1, this method will return <code>null</code>.
+ * For more information on wrapping mode {see Wrap}.
+ * @return the wrapping mode on the second dimension.
+ */
+ Wrap getTWrappingMode();
+
+ /**
+ * Wrapping mode on the second texture coordinate.
+ * @param wrappingMode the new wrapping mode on the second texture coordinate.
+ */
+ void setTWrappingMode(Wrap wrappingMode);
+
+ /**
+ * Minifying filter getter.
+ * @return the used minifying filter.
+ */
+ Filter getMinifyingFilter();
+
+ /**
+ * Minifying filter mode setter.
+ * @param minifyingFilter the new minifying filter mode.
+ */
+ void setMinifyingFilter(Filter minifyingFilter);
+
+ /**
+ * Magnification filter getter.
+ * @return the used magnification filter.
+ */
+ Filter getMagnificationFilter();
+
+ /**
+ * Magnification filter mode setter.
+ * @param magnificationFilter the new minifying filter mode.
+ */
+ void setMagnificationFilter(Filter magnificationFilter);
+
+ /**
+ * Texture data provider getter.
+ * @return the texture data provider.
+ */
+ TextureDataProvider getDataProvider();
+
+ /**
+ * Texture data provider setter.
+ * The texture is set to 'no up to date'.
+ * @param provider the new texture data provider.
+ */
+ void setDataProvider(TextureDataProvider provider);
+
+ /**
+ * Set the texture data provider as a drawn texture data provider.
+ * @param textureDrawer the given texture drawer.
+ */
+ void setDrawer(TextureDrawer textureDrawer);
+
+ /**
+ * 2D-Texture coordinates must be modified according to the real texture dimension which can differ from
+ * the textureSize (with certains GC, a texture must have a size which is a power-of-two).
+ * @return the scale factor for the s-coordinate
+ */
+ double getSScaleFactor();
+
+ /**
+ * 2D-Texture coordinates must be modified according to the real texture dimension which can differ from
+ * the textureSize (with certains GC, a texture must have a size which is a power-of-two).
+ * @return the scale factor for the t-coordinate
+ */
+ double getTScaleFactor();
+}
diff --git a/modules/scirenderer/src/org/scilab/forge/scirenderer/texture/TextureBufferedImage.java b/modules/scirenderer/src/org/scilab/forge/scirenderer/texture/TextureBufferedImage.java
new file mode 100755
index 000000000..0d886aae1
--- /dev/null
+++ b/modules/scirenderer/src/org/scilab/forge/scirenderer/texture/TextureBufferedImage.java
@@ -0,0 +1,88 @@
+/*
+ * Scilab ( http://www.scilab.org/ ) - This file is part of Scilab
+ * Copyright (C) 2009-2011 - DIGITEO - Pierre Lando
+ *
+ * This file must be used under the terms of the CeCILL.
+ * This source file is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at
+ * http://www.cecill.info/licences/Licence_CeCILL_V2.1-en.txt
+ */
+
+package org.scilab.forge.scirenderer.texture;
+
+import javax.swing.ImageIcon;
+import javax.swing.JFrame;
+import javax.swing.JLabel;
+import java.awt.BorderLayout;
+import java.awt.image.BufferedImage;
+import java.awt.image.DataBufferInt;
+import java.nio.ByteBuffer;
+import java.nio.ByteOrder;
+
+/**
+ * @author Pierre Lando
+ */
+public class TextureBufferedImage extends BufferedImage {
+ private static final int A_SHIFT = 24;
+ private static final int R_SHIFT = 16;
+ private static final int G_SHIFT = 8;
+ private static final int B_SHIFT = 0;
+ private static final int COMPONENT_MASK = 0xFF;
+ private static final int NB_COMPONENTS = 4;
+
+ /**
+ * Default constructor.
+ * @param width texture width.
+ * @param height texture height.
+ */
+ public TextureBufferedImage(int width, int height) {
+ super(width, height, TYPE_INT_ARGB);
+ }
+
+ /**
+ * Return the buffer data of the image.
+ * Returned data are stored in 4 bytes (RGBA) per pixel.
+ * @return the buffer data of the image.
+ */
+ public int[] getRGBAData() {
+ int[] pixels = ((DataBufferInt) getRaster().getDataBuffer()).getData();
+
+ for (int i = 0; i < pixels.length; i++) {
+ pixels[i] = (pixels[i] & 0xFF00FF00) | ((pixels[i] << 16) & 0x00FF0000) | ((pixels[i] >> 16) & 0xFF);
+ }
+
+ //updateFrame(this);
+ return pixels;
+ }
+
+ static JLabel label;
+ private static void updateFrame(TextureBufferedImage textureBufferedImage) {
+ if (label == null) {
+ JFrame frame = new JFrame("Test");
+ frame.setLayout(new BorderLayout());
+ label = new JLabel();
+ frame.add(label, BorderLayout.CENTER);
+ frame.setSize(500, 500);
+ frame.setVisible(true);
+ }
+ label.setIcon(new ImageIcon(textureBufferedImage));
+ }
+
+
+ /**
+ * Buffered data getter.
+ * @return a byte buffer filled with RGBA data.
+ */
+ public ByteBuffer getRGBABuffer() {
+ int[] pixels = ((DataBufferInt) getRaster().getDataBuffer()).getData();
+ ByteBuffer buffer = ByteBuffer.allocate(pixels.length * 4);
+ buffer.order(ByteOrder.nativeOrder());
+ for (int i = 0; i < pixels.length; i++) {
+ buffer.putInt((pixels[i] & 0xFF00FF00) | ((pixels[i] << 16) & 0x00FF0000) | ((pixels[i] >> 16) & 0xFF));
+ }
+ buffer.rewind();
+
+ return buffer;
+ }
+}
diff --git a/modules/scirenderer/src/org/scilab/forge/scirenderer/texture/TextureDataProvider.java b/modules/scirenderer/src/org/scilab/forge/scirenderer/texture/TextureDataProvider.java
new file mode 100755
index 000000000..e814d2c49
--- /dev/null
+++ b/modules/scirenderer/src/org/scilab/forge/scirenderer/texture/TextureDataProvider.java
@@ -0,0 +1,125 @@
+/*
+ * Scilab ( http://www.scilab.org/ ) - This file is part of Scilab
+ * Copyright (C) 2009-2012 - DIGITEO - Pierre Lando
+ *
+ * This file must be used under the terms of the CeCILL.
+ * This source file is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at
+ * http://www.cecill.info/licences/Licence_CeCILL_V2.1-en.txt
+ */
+
+package org.scilab.forge.scirenderer.texture;
+
+import org.scilab.forge.scirenderer.data.DataProvider;
+
+import java.awt.Dimension;
+import java.awt.image.BufferedImage;
+import java.nio.ByteBuffer;
+
+/**
+ * @author Pierre Lando
+ */
+public interface TextureDataProvider extends DataProvider<Texture> {
+
+ public enum ImageType {
+ RGB, RGB_RGBA, BGR, GRAY, GRAY_16, RGBA, RGBA_REV, ABGR, RGB_332, RED, GREEN, BLUE, INTENSITY, RGBA_4444, RGBA_5551, RGB_FLOAT, RGBA_FLOAT, GRAY_FLOAT, RED_16, GREEN_16, BLUE_16, RED_FLOAT, GREEN_FLOAT, BLUE_FLOAT, RGBA_BYTE;
+
+ public static ImageType fromInt(int n) {
+ switch (n) {
+ case 0:
+ return RGB;
+ case 1:
+ return RGB_RGBA;
+ case 2:
+ return BGR;
+ case 3:
+ return GRAY;
+ case 4:
+ return GRAY_16;
+ case 5:
+ return RGBA;
+ case 6:
+ return RGBA_REV;
+ case 7:
+ return ABGR;
+ case 8:
+ return RGB_332;
+ case 9:
+ return RED;
+ case 10:
+ return GREEN;
+ case 11:
+ return BLUE;
+ case 12:
+ return INTENSITY;
+ case 13:
+ return RGBA_4444;
+ case 14:
+ return RGBA_5551;
+ case 15:
+ return RGB_FLOAT;
+ case 16:
+ return RGBA_FLOAT;
+ case 17:
+ return GRAY_FLOAT;
+ case 18:
+ return RED_16;
+ case 19:
+ return GREEN_16;
+ case 20:
+ return BLUE_16;
+ case 21:
+ return RED_FLOAT;
+ case 22:
+ return GREEN_FLOAT;
+ case 23:
+ return BLUE_FLOAT;
+ case 24:
+ return RGBA_BYTE;
+ default:
+ return GRAY;
+ }
+ }
+ }
+
+ boolean isRowMajorOrder();
+
+ ImageType getImageType();
+
+ /**
+ * Texture size getter.
+ * @return the size of the texture in pixel.
+ */
+ Dimension getTextureSize();
+
+ /**
+ * Data getter.
+ * @return the data.
+ */
+ ByteBuffer getData();
+
+ /**
+ * Sub-data getter.
+ * @param x rectangle origin x-coordinate.
+ * @param y rectangle origin y-coordinate.
+ * @param width rectangle width.
+ * @param height rectangle height.
+ * @return the data.
+ */
+ ByteBuffer getSubData(int x, int y, int width, int height);
+
+ /**
+ * @return the data as a BufferedImage
+ */
+ BufferedImage getImage();
+
+ /**
+ * @param x rectangle origin x-coordinate.
+ * @param y rectangle origin y-coordinate.
+ * @param width rectangle width.
+ * @param height rectangle height.
+ * @return the sub-data as a BufferedImage.
+ */
+ BufferedImage getSubImage(int x, int y, int width, int height);
+}
diff --git a/modules/scirenderer/src/org/scilab/forge/scirenderer/texture/TextureDrawer.java b/modules/scirenderer/src/org/scilab/forge/scirenderer/texture/TextureDrawer.java
new file mode 100755
index 000000000..64db0fd80
--- /dev/null
+++ b/modules/scirenderer/src/org/scilab/forge/scirenderer/texture/TextureDrawer.java
@@ -0,0 +1,54 @@
+/*
+ * Scilab ( http://www.scilab.org/ ) - This file is part of Scilab
+ * Copyright (C) 2009-2012 - DIGITEO - Pierre Lando
+ *
+ * This file must be used under the terms of the CeCILL.
+ * This source file is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at
+ * http://www.cecill.info/licences/Licence_CeCILL_V2.1-en.txt
+ */
+
+package org.scilab.forge.scirenderer.texture;
+
+import java.awt.Dimension;
+
+/**
+ * @author Pierre Lando
+ */
+public interface TextureDrawer {
+
+ /**
+ * Origin position.
+ */
+ public enum OriginPosition {
+ /**
+ * Origin is the sprite center.
+ */
+ CENTER,
+
+ /**
+ * Origin is the upper left sprite corner.
+ */
+ UPPER_LEFT
+ }
+
+ /**
+ * Call the texture drawing.
+ * @param textureDrawingTools the used drawing tools.
+ */
+ void draw(TextureDrawingTools textureDrawingTools);
+
+ /**
+ * Texture size getter.
+ * @return texture size.
+ */
+ Dimension getTextureSize();
+
+ /**
+ * Return the origin position.
+ * Warning: change the returned value during a draw call have no effect.
+ * @return the origin position.
+ */
+ OriginPosition getOriginPosition();
+}
diff --git a/modules/scirenderer/src/org/scilab/forge/scirenderer/texture/TextureDrawingTools.java b/modules/scirenderer/src/org/scilab/forge/scirenderer/texture/TextureDrawingTools.java
new file mode 100755
index 000000000..a6cea6d26
--- /dev/null
+++ b/modules/scirenderer/src/org/scilab/forge/scirenderer/texture/TextureDrawingTools.java
@@ -0,0 +1,89 @@
+/*
+ * Scilab ( http://www.scilab.org/ ) - This file is part of Scilab
+ * Copyright (C) 2009-2011 - DIGITEO - Pierre Lando
+ *
+ * This file must be used under the terms of the CeCILL.
+ * This source file is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at
+ * http://www.cecill.info/licences/Licence_CeCILL_V2.1-en.txt
+ */
+
+package org.scilab.forge.scirenderer.texture;
+
+import org.scilab.forge.scirenderer.shapes.appearance.Appearance;
+import org.scilab.forge.scirenderer.shapes.appearance.Color;
+
+import javax.swing.Icon;
+
+/**
+ *
+ * Interface for the sprite drawing tools.
+ *
+ *
+ * @author Pierre Lando
+ */
+public interface TextureDrawingTools {
+
+ /**
+ * Draw a plus.
+ * @param size the plus size.
+ * @param appearance the used appearance.
+ */
+ void drawPlus(int size, Appearance appearance);
+
+ /**
+ * Draw a polyline.
+ * @param coordinates polyline's point coordinates.
+ * @param appearance the used appearance.
+ */
+ void drawPolyline(int[] coordinates, Appearance appearance);
+
+
+ /**
+ * Fill a polygon.
+ * @param coordinates polygon's point coordinates.
+ * @param appearance the used appearance.
+ */
+ void fillPolygon(int[] coordinates, Appearance appearance);
+
+ /**
+ * Draw a circle.
+ * @param x the x coordinate of the circle center.
+ * @param y the y coordinate of the circle center.
+ * @param diameter the circle diameter.
+ * @param appearance the circle appearance.
+ */
+ void drawCircle(int x, int y, int diameter, Appearance appearance);
+
+ /**
+ * Fill a disc of given diameter, centered at (x, y) with the given appearance.
+ * @param x the x coordinate of the disc center.
+ * @param y the y coordinate of the disc center.
+ * @param diameter the disc diameter.
+ * @param color the disc color.
+ */
+ void fillDisc(int x, int y, int diameter, Color color);
+
+ /**
+ * Draw the given text at the given position with the given appearance.
+ * @param textEntity the text entity to draw.
+ * @param x the x text position.
+ * @param y the y text position.
+ */
+ void draw(TextEntity textEntity, int x, int y);
+
+ /**
+ * Draw the given {@link javax.swing.Icon} at the given position.
+ * @param icon the given icon to paint.
+ * @param x the x text position.
+ * @param y the y text position.
+ */
+ void draw(Icon icon, int x, int y);
+
+ /**
+ * Clear the sprite with the given color.
+ * @param color the new background color.
+ */
+ void clear(Color color);
+}
diff --git a/modules/scirenderer/src/org/scilab/forge/scirenderer/texture/TextureManager.java b/modules/scirenderer/src/org/scilab/forge/scirenderer/texture/TextureManager.java
new file mode 100755
index 000000000..17aada7bb
--- /dev/null
+++ b/modules/scirenderer/src/org/scilab/forge/scirenderer/texture/TextureManager.java
@@ -0,0 +1,34 @@
+/*
+ * Scilab ( http://www.scilab.org/ ) - This file is part of Scilab
+ * Copyright (C) 2009-2012 - DIGITEO - Pierre Lando
+ *
+ * This file must be used under the terms of the CeCILL.
+ * This source file is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at
+ * http://www.cecill.info/licences/Licence_CeCILL_V2.1-en.txt
+ */
+
+package org.scilab.forge.scirenderer.texture;
+
+import java.util.Collection;
+
+/**
+ * @author Pierre Lando
+ */
+public interface TextureManager {
+
+ /**
+ * Texture creator.
+ * @return a new {@link Texture}
+ */
+ Texture createTexture();
+
+ /**
+ * Dispose the given textures.
+ * @param textures textures to dispose.
+ */
+ void dispose(Collection<Texture> textures);
+
+ void dispose(Texture texture);
+} \ No newline at end of file
diff --git a/modules/scirenderer/src/org/scilab/forge/scirenderer/tranformations/DegenerateMatrixException.java b/modules/scirenderer/src/org/scilab/forge/scirenderer/tranformations/DegenerateMatrixException.java
new file mode 100755
index 000000000..291addbe8
--- /dev/null
+++ b/modules/scirenderer/src/org/scilab/forge/scirenderer/tranformations/DegenerateMatrixException.java
@@ -0,0 +1,29 @@
+/*
+ * Scilab ( http://www.scilab.org/ ) - This file is part of Scilab
+ * Copyright (C) 2009-2011 - DIGITEO - Pierre Lando
+ *
+ * This file must be used under the terms of the CeCILL.
+ * This source file is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at
+ * http://www.cecill.info/licences/Licence_CeCILL_V2.1-en.txt
+ */
+
+package org.scilab.forge.scirenderer.tranformations;
+
+import org.scilab.forge.scirenderer.SciRendererException;
+
+/**
+ * @author Pierre Lando
+ */
+@SuppressWarnings(value = { "serial" })
+public class DegenerateMatrixException extends SciRendererException {
+
+ /**
+ * Default constructor.
+ * @param message the message associated with this exception.
+ */
+ public DegenerateMatrixException(String message) {
+ super(message);
+ }
+}
diff --git a/modules/scirenderer/src/org/scilab/forge/scirenderer/tranformations/Rotation.java b/modules/scirenderer/src/org/scilab/forge/scirenderer/tranformations/Rotation.java
new file mode 100755
index 000000000..8783894d8
--- /dev/null
+++ b/modules/scirenderer/src/org/scilab/forge/scirenderer/tranformations/Rotation.java
@@ -0,0 +1,294 @@
+/*
+ * Scilab ( http://www.scilab.org/ ) - This file is part of Scilab
+ * Copyright (C) 2009-2011 - DIGITEO - Pierre Lando
+ *
+ * This file must be used under the terms of the CeCILL.
+ * This source file is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at
+ * http://www.cecill.info/licences/Licence_CeCILL_V2.1-en.txt
+ */
+
+package org.scilab.forge.scirenderer.tranformations;
+
+/**
+ * This class represent a Rotation.
+ * The data are stored as an unitary quaternion [a; b; c; d].
+ * A rotation of an angle alpha along the vector [x; y; z] is stored thus :
+ * a = cos (alpha / 2)
+ * b = sin (alpha / 2) * nx
+ * c = sin (alpha / 2) * ny
+ * d = sin (alpha / 2) * nz
+ *
+ * Where [nx; ny; nz] is [x; y; z] / norm([x; y; z]).
+ *
+ * @author Pierre Lando
+ */
+public class Rotation {
+
+ private static final int MAX_SELF_OPERATION = 16;
+ private int opCount;
+ private double a;
+ private double b;
+ private double c;
+ private double d;
+ private double[] rotationMatrix;
+
+ /**
+ * Default constructor.
+ * The created object represent identity rotation.
+ */
+ public Rotation() {
+ a = 1;
+ b = 0;
+ c = 0;
+ d = 0;
+ normalize();
+ }
+
+ /**
+ * Copy constructor.
+ * The created object is a copy of the given rotation r.
+ * @param r the given rotation.
+ */
+ public Rotation(Rotation r) {
+ a = r.a;
+ b = r.b;
+ c = r.c;
+ d = r.d;
+ normalize();
+ }
+
+ /**
+ * The created object represent a rotation of an angle of 'alpha' radians along the vector 'v'.
+ * @param alpha the rotation angle in radians.
+ * @param v the vector carrying the rotation.
+ */
+ public Rotation(double alpha, Vector3d v) {
+ double t = Math.cos(alpha / 2);
+ Vector3d nv = v.getNormalized().times(Math.sin(alpha / 2));
+
+ a = t;
+ b = nv.getX();
+ c = nv.getY();
+ d = nv.getZ();
+ normalize();
+ }
+
+ /**
+ * The created object represent a rotation of an angle of 'alpha' radians along the vector 'v'.
+ * @param alpha the rotation angle in radians.
+ * @param v the vector carrying the rotation.
+ */
+ public Rotation(double alpha, Vector3f v) {
+ this(alpha, v.asDouble());
+ }
+
+ /**
+ * Get a rotation from an angle alpha given in degree and an axis v
+ * @param alpha angle of rotation in degree
+ * @param v the axis of the rotation
+ * @return a Rotation object
+ *
+ * For information, the function has been written to fix bug 11399.
+ * For angle (in radians) close to Pi the Rotation has a 'a' close to 0
+ * and that conflicts with small axes where length is closed to a: rounding errors
+ * led to a "bad" transformation matrix (AxesDrawer::computeBoxTransformation).
+ */
+ public static Rotation getDegreeRotation(double alpha, Vector3d v) {
+ int a = (int) alpha;
+ if (alpha == a) {
+ a = a % 360;
+ if (a == 0) {
+ return new Rotation(1, 0, 0, 0);
+ }
+ if (a == 180) {
+ Vector3d nv = v.getNormalized();
+ return new Rotation(0, nv.getX(), nv.getY(), nv.getZ());
+ }
+
+ return new Rotation(((double) a) / 180.0 * Math.PI, v);
+ }
+
+ alpha = (alpha / 180.0 - 2 * Math.floor(alpha / 360.0)) * Math.PI;
+
+ return new Rotation(alpha, v);
+ }
+
+
+ private Rotation(double a, double b, double c, double d) {
+ this.a = a;
+ this.b = b;
+ this.c = c;
+ this.d = d;
+ normalize();
+ }
+
+ public Rotation(float[] v) {
+ if ((v != null) && (v.length == 4)) {
+ a = v[0];
+ b = v[1];
+ c = v[2];
+ d = v[3];
+ } else { // TODO throw invalid data exception
+ a = 1;
+ b = 0;
+ c = 0;
+ d = 0;
+ }
+ normalize();
+ }
+
+ public Rotation(double[] v) {
+ if ((v != null) && (v.length == 4)) {
+ a = v[0];
+ b = v[1];
+ c = v[2];
+ d = v[3];
+ } else { // TODO throw invalid data exception
+ a = 1;
+ b = 0;
+ c = 0;
+ d = 0;
+ }
+ normalize();
+ }
+
+ /**
+ * Return the inverse rotation.
+ * @return the inverse rotation.
+ */
+ public Rotation getInverse() {
+ return new Rotation(a, -b, -c, -d);
+ }
+
+ /**
+ * Return true if this object represents an identity transformation.
+ * @return true if this object represents an identity transformation.
+ */
+ public boolean isIdentity() {
+ return (a == 1);
+ }
+
+ public double[] getRotationMatrix() {
+ return rotationMatrix.clone();
+ }
+ public double[] getUnRotateMatrix() {
+ return new double[] {
+ rotationMatrix[0], rotationMatrix[4], rotationMatrix[8], rotationMatrix[12],
+ rotationMatrix[1], rotationMatrix[5], rotationMatrix[9], rotationMatrix[13],
+ rotationMatrix[2], rotationMatrix[6], rotationMatrix[10], rotationMatrix[14],
+ rotationMatrix[3], rotationMatrix[7], rotationMatrix[11], rotationMatrix[15]
+ };
+ }
+
+ public Rotation multiply(Rotation q) {
+ double ar = a * q.a - b * q.b - c * q.c - d * q.d;
+ double br = a * q.b + b * q.a + c * q.d - d * q.c;
+ double cr = a * q.c - b * q.d + c * q.a + d * q.b;
+ double dr = a * q.d + b * q.c - c * q.b + d * q.a;
+ a = ar;
+ b = br;
+ c = cr;
+ d = dr;
+ selfCheck();
+ return this;
+ }
+
+ private void selfCheck() {
+ if (opCount++ > MAX_SELF_OPERATION) {
+ normalize();
+ } else {
+ computeRotationMatrix();
+ }
+ }
+
+ private void normalize() {
+ opCount = 0;
+ double f = 1f / Math.sqrt((a * a) + (b * b) + (c * c) + (d * d));
+ a *= f;
+ b *= f;
+ c *= f;
+ d *= f;
+ computeRotationMatrix();
+ }
+
+
+ public Rotation times(Rotation q) {
+ return new Rotation(this).multiply(q);
+ }
+
+ public Vector3d conjugate(Vector3d v) {
+ return new Vector3d(
+ rotationMatrix[0] * v.getX() + rotationMatrix[4] * v.getY() + rotationMatrix[8] * v.getZ(),
+ rotationMatrix[1] * v.getX() + rotationMatrix[5] * v.getY() + rotationMatrix[9] * v.getZ(),
+ rotationMatrix[2] * v.getX() + rotationMatrix[6] * v.getY() + rotationMatrix[10] * v.getZ()
+ );
+ }
+ public Vector3d conjugateInverse(Vector3d v) {
+ return new Vector3d(
+ rotationMatrix[0] * v.getX() + rotationMatrix[1] * v.getY() + rotationMatrix[2] * v.getZ(),
+ rotationMatrix[4] * v.getX() + rotationMatrix[5] * v.getY() + rotationMatrix[6] * v.getZ(),
+ rotationMatrix[8] * v.getX() + rotationMatrix[9] * v.getY() + rotationMatrix[10] * v.getZ()
+ );
+ }
+
+ private void computeRotationMatrix() {
+ double a2 = a * a;
+ double b2 = b * b;
+ double c2 = c * c;
+ double d2 = d * d;
+ this.rotationMatrix = new double[] {
+ a2 + b2 - c2 - d2, 2 * ((b * c) - (a * d)), 2 * ((a * c) + (b * d)), 0,
+ 2 * ((a * d) + (b * c)), a2 - b2 + c2 - d2, 2 * ((c * d) - (a * b)), 0,
+ 2 * ((b * d) - (a * c)), 2 * ((a * b) + (c * d)), a2 - b2 - c2 + d2, 0,
+ 0, 0, 0, 1
+ };
+ }
+
+ public String toString() {
+ return "(" + a + ", " + b + ", " + c + ", " + d + ")";
+ }
+
+ public Vector3d getVectorY() {
+ return new Vector3d(rotationMatrix[1], rotationMatrix[5], rotationMatrix[9]);
+ }
+
+ public Rotation power(double p) {
+ // TODO : do a better S.L.E.R.P.
+ double cos = a;
+ double sin = Math.sqrt((b * b) + (c * c) + (d * d));
+
+ if (sin < 0.001) {
+ return new Rotation();
+ }
+
+ double t = (p - 1) * Math.atan2(sin, cos);
+ double na = cos * Math.cos(t) - sin * Math.sin(t);
+
+ double beta = Math.cos(t) + Math.sin(t) * (cos / sin);
+ return new Rotation(na, beta * b, beta * c, beta * d);
+ }
+
+ public double[] getData() {
+ return new double[] {a, b, c, d};
+ }
+
+ public float[] getDataAsFloatArray() {
+ return new float[] {(float) a, (float) b, (float) c, (float) d};
+ }
+
+ @Override
+ public int hashCode() {
+ int hashCode = 0;
+ hashCode += 7 * (new Double(a).hashCode());
+ hashCode += 17 * (new Double(b).hashCode());
+ hashCode += 29 * (new Double(c).hashCode());
+ hashCode += 37 * (new Double(d).hashCode());
+ return hashCode;
+ }
+
+ public boolean equals(Rotation r2) {
+ return (r2 != null) && (a == r2.a) && (b == r2.b) && (c == r2.c) && (d == r2.d);
+ }
+}
diff --git a/modules/scirenderer/src/org/scilab/forge/scirenderer/tranformations/Transformation.java b/modules/scirenderer/src/org/scilab/forge/scirenderer/tranformations/Transformation.java
new file mode 100755
index 000000000..70556042d
--- /dev/null
+++ b/modules/scirenderer/src/org/scilab/forge/scirenderer/tranformations/Transformation.java
@@ -0,0 +1,82 @@
+/*
+ * Scilab ( http://www.scilab.org/ ) - This file is part of Scilab
+ * Copyright (C) 2009-2011 - DIGITEO - Pierre Lando
+ *
+ * This file must be used under the terms of the CeCILL.
+ * This source file is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at
+ * http://www.cecill.info/licences/Licence_CeCILL_V2.1-en.txt
+ */
+
+package org.scilab.forge.scirenderer.tranformations;
+
+/**
+ * @author Pierre Lando
+ */
+public interface Transformation {
+
+ /**
+ * Return this right times the given transformation.
+ * @param transformation the given transformation.
+ * @return a new transformation.
+ */
+ Transformation rightTimes(Transformation transformation);
+
+ /**
+ * Return this left times the given transformation.
+ * @param transformation the given transformation.
+ * @return a new transformation.
+ */
+ Transformation leftTimes(Transformation transformation);
+
+ /**
+ * Return the inverse transformation.
+ * @return the inverse transformation.
+ */
+ Transformation getInverseTransformation();
+
+ /**
+ * Project the given vector.
+ * W value is set to 1.
+ * @param vector the given vector.
+ * @return the given vector projected.
+ */
+ Vector3d project(Vector3d vector);
+
+ /**
+ * Project the given direction.
+ * Translation part is not used.
+ * @param direction the direction to project.
+ * @return the given direction projected.
+ */
+ Vector3d projectDirection(Vector3d direction);
+
+ /**
+ * Unproject the given vector.
+ * W value is set to 1.
+ * @param vector the given vector.
+ * @return the given vector un-projected.
+ */
+ Vector3d unproject(Vector3d vector);
+
+ /**
+ * Return true if is identity, false otherwise.
+ * @return true if is identity, false otherwise.
+ */
+ boolean isIdentity();
+
+ /**
+ * Return this transformation matrix.
+ * The returned array is a clone of the transformation array.
+ * @return this transformation matrix.
+ */
+ double[] getMatrix();
+
+ /**
+ * Return this transformation inverse matrix.
+ * The returned array is a clone of the transformation array.
+ * @return this transformation inverse matrix.
+ */
+ double[] getInverseMatrix();
+}
diff --git a/modules/scirenderer/src/org/scilab/forge/scirenderer/tranformations/TransformationFactory.java b/modules/scirenderer/src/org/scilab/forge/scirenderer/tranformations/TransformationFactory.java
new file mode 100755
index 000000000..7439ebd73
--- /dev/null
+++ b/modules/scirenderer/src/org/scilab/forge/scirenderer/tranformations/TransformationFactory.java
@@ -0,0 +1,680 @@
+/*
+ * Scilab ( http://www.scilab.org/ ) - This file is part of Scilab
+ * Copyright (C) 2009-2011 - DIGITEO - Pierre Lando
+ *
+ * This file must be used under the terms of the CeCILL.
+ * This source file is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at
+ * http://www.cecill.info/licences/Licence_CeCILL_V2.1-en.txt
+ */
+
+package org.scilab.forge.scirenderer.tranformations;
+
+import java.awt.Dimension;
+
+/**
+ * @author Pierre Lando
+ */
+public final class TransformationFactory {
+
+ /**
+ * The identity transformation.
+ */
+ static final Transformation IDENTITY_TRANSFORMATION = new IdentityTransformation();
+
+ /**
+ * Default constructor.
+ * The constructor is private : this is an utility class.
+ */
+ private TransformationFactory() {
+ }
+
+
+ /**
+ * Return the identity transformation.
+ * @return the identity transformation.
+ */
+ public static Transformation getIdentity() {
+ return IDENTITY_TRANSFORMATION;
+ }
+
+ /**
+ * Return a translate transformation.
+ * @param x translation in x coordinate.
+ * @param y translation in y coordinate.
+ * @param z translation in z coordinate.
+ * @return a translate transformation.
+ */
+ public static Transformation getTranslateTransformation(double x, double y, double z) {
+ if ((x == 0) && (y == 0) && (z == 0)) {
+ return IDENTITY_TRANSFORMATION;
+ } else {
+ return new TranslateTransformation(x, y, z);
+ }
+ }
+
+ private static Transformation getTranslateTransformation(Vector3d t) {
+ return getTranslateTransformation(t.getX(), t.getY(), t.getZ());
+ }
+
+ /**
+ * Return a scale transformation.
+ * @param x scale in x.
+ * @param y scale in y.
+ * @param z scale in z.
+ * @return a scale transformation.
+ * @throws DegenerateMatrixException - A DegenerateMatrixException is thrown if one of the scale factor is zero.
+ */
+ public static Transformation getScaleTransformation(double x, double y, double z) throws DegenerateMatrixException {
+ if ((x == 1) && (y == 1) && (z == 1)) {
+ return IDENTITY_TRANSFORMATION;
+ } else if ((x == 0) || (y == 0) || (z == 0)) {
+ throw new DegenerateMatrixException("Scale matrix with 0 factor.");
+ } else {
+ return new ScaleTransformation(x, y, z);
+ }
+ }
+
+ /**
+ * Return a scale transformation.
+ * @param s scale vector.
+ * @return a scale transformation.
+ * @throws DegenerateMatrixException - A DegenerateMatrixException is thrown if one coordinate of the scale vector is zero.
+ */
+ private static Transformation getScaleTransformation(Vector3d s) throws DegenerateMatrixException {
+ return getScaleTransformation(s.getX(), s.getY(), s.getZ());
+ }
+
+ /**
+ * Return a scale transformation.
+ * @param s scale value.
+ * @return a scale transformation.
+ * @throws DegenerateMatrixException - A DegenerateMatrixException is thrown if one coordinate of the scale vector is zero.
+ */
+ public static Transformation getScaleTransformation(double s) throws DegenerateMatrixException {
+ return getScaleTransformation(s, s, s);
+ }
+
+ /**
+ * Return a rotation transformation.
+ * @param angle the rotation angle in degree.
+ * @param x the x coordinate of the rotation axes.
+ * @param y the y coordinate of the rotation axes.
+ * @param z the z coordinate of the rotation axes.
+ * @return a rotation transformation.
+ * @throws DegenerateMatrixException - A DegenerateMatrixException is thrown if the rotation axes is zero.
+ */
+ public static Transformation getRotationTransformation(double angle, double x, double y, double z) throws DegenerateMatrixException {
+ if ((x == 0) && (y == 0) && (z == 0)) {
+ throw new DegenerateMatrixException("Rotation axes should not be nul.");
+ } else if (angle == 0) {
+ return IDENTITY_TRANSFORMATION;
+ } else {
+ return new RotationTransformation(Rotation.getDegreeRotation(angle, new Vector3d(x, y, z)));
+ }
+ }
+
+ /**
+ * Return a rotation transformation.
+ * @param q the quaternion.
+ * @return a rotation transformation.
+ */
+ public static Transformation getRotationTransformation(Rotation q) {
+ if (q.isIdentity()) {
+ return IDENTITY_TRANSFORMATION;
+ } else {
+ return new RotationTransformation(q);
+ }
+ }
+
+ /**
+ * Return the 'preferred aspect ratio transformation'
+ * @param dimension the canvas dimension.
+ * @param preferredRatio the preferred aspect ratio.
+ * @return the 'preferred aspect ratio transformation'
+ * @throws DegenerateMatrixException - A DegenerateMatrixException is thrown if the given value are not reasonable.
+ */
+ public static Transformation getPreferredAspectRatioTransformation(Dimension dimension, double preferredRatio) throws DegenerateMatrixException {
+ double ratio = dimension.getWidth() / dimension.getHeight();
+ if (ratio > preferredRatio) {
+ return getScaleTransformation(1 / ratio, 1, 1);
+ } else {
+ return getScaleTransformation(1, ratio, 1);
+ }
+ }
+
+ /**
+ * Return a perspective transformation.
+ * @param near the distance from the viewer to the near clipping plane.
+ * @param far the distance from the viewer to the far clipping plane.
+ * @param fov the field of view angle in degree.
+ * @return a perspective transformation.
+ */
+ public static Transformation getPerspectiveTransformation(double near, double far, double fov) {
+ return new PerspectiveTransformation(near, far, fov);
+ }
+
+ /**
+ * Return an orthographic transformation.
+ * @param left the left plane distance to origin.
+ * @param right the right plane distance to origin.
+ * @param bottom the bottom plane distance to origin.
+ * @param top the top plane distance to origin.
+ * @param near the near plane distance to origin.
+ * @param far the far plane distance to origin.
+ * @return an orthographic transformation.
+ */
+ public static Transformation getOrthographic(double left, double right, double bottom, double top, double near, double far) {
+ return new OrthographicTransformation(left, right, bottom, top, near, far);
+ }
+
+ /**
+ * Return an affine transformation
+ * aX + b
+ * @param s the scale parameter.
+ * @param t the translate parameter.
+ * @return an affine transformation
+ * @throws DegenerateMatrixException - A DegenerateMatrixException is thrown if one coordinate of the scale vector is zero.
+ */
+ public static Transformation getAffineTransformation(Vector3d s, Vector3d t) throws DegenerateMatrixException {
+ return getTranslateTransformation(t).rightTimes(getScaleTransformation(s));
+ }
+
+ /**
+ * Abstract transformation.
+ * Implement common methods of all transformation.
+ */
+ private abstract static class AbstractTransformation implements Transformation {
+
+ @Override
+ public Transformation rightTimes(Transformation transformation) {
+ return getProductTransformation(this, transformation);
+ }
+
+ @Override
+ public Transformation leftTimes(Transformation transformation) {
+ return getProductTransformation(transformation, this);
+ }
+
+ @Override
+ public Vector3d project(Vector3d vector) {
+ double[] matrix = getMatrix();
+ double x = matrix[0] * vector.getX() + matrix[4] * vector.getY() + matrix[8] * vector.getZ() + matrix[12];
+ double y = matrix[1] * vector.getX() + matrix[5] * vector.getY() + matrix[9] * vector.getZ() + matrix[13];
+ double z = matrix[2] * vector.getX() + matrix[6] * vector.getY() + matrix[10] * vector.getZ() + matrix[14];
+ double w = matrix[3] * vector.getX() + matrix[7] * vector.getY() + matrix[11] * vector.getZ() + matrix[15];
+ return new Vector3d(x / w, y / w, z / w);
+ }
+
+ @Override
+ public Vector3d projectDirection(Vector3d direction) {
+ double[] matrix = getMatrix();
+ double x = matrix[0] * direction.getX() + matrix[4] * direction.getY() + matrix[8] * direction.getZ();
+ double y = matrix[1] * direction.getX() + matrix[5] * direction.getY() + matrix[9] * direction.getZ();
+ double z = matrix[2] * direction.getX() + matrix[6] * direction.getY() + matrix[10] * direction.getZ();
+ double w = matrix[3] * direction.getX() + matrix[7] * direction.getY() + matrix[11] * direction.getZ() + matrix[15];
+ return new Vector3d(x / w, y / w, z / w);
+ }
+
+ @Override
+ public Vector3d unproject(Vector3d vector) {
+ return getInverseTransformation().project(vector);
+ }
+
+ @Override
+ public Transformation getInverseTransformation() {
+ return new AbstractTransformation() {
+ @Override
+ public boolean isIdentity() {
+ return AbstractTransformation.this.isIdentity();
+ }
+
+ @Override
+ public double[] getMatrix() {
+ return AbstractTransformation.this.getInverseMatrix();
+ }
+
+ @Override
+ public double[] getInverseMatrix() {
+ return AbstractTransformation.this.getMatrix();
+ }
+ };
+ }
+
+ @Override
+ public String toString() {
+ double[] matrix = getMatrix();
+ String r = "";
+ for (int i = 0; i < 16; i++) {
+ r += matrix[i];
+ if ((i % 4) == 3) {
+ r += "\n";
+ } else {
+ r += ", ";
+ }
+ }
+ return r;
+ }
+
+ /**
+ * Return a product transformation.
+ * @param t1 the first transformation.
+ * @param t2 the second transformation.
+ * @return t1 x t2
+ */
+ private Transformation getProductTransformation(Transformation t1, Transformation t2) {
+ if (t1.isIdentity()) {
+ return t2;
+ } else if (t2.isIdentity()) {
+ return t1;
+ } else {
+ return new ProductTransformation(t1, t2);
+ }
+ }
+ }
+
+
+ /**
+ * The identity transformation.
+ */
+ private static class IdentityTransformation extends AbstractTransformation {
+
+ /**
+ * The identity matrix data.
+ */
+ private static final double[] IDENTITY_MATRIX = new double[] {
+ 1, 0, 0, 0,
+ 0, 1, 0, 0,
+ 0, 0, 1, 0,
+ 0, 0, 0, 1
+ };
+
+ /**
+ * Default constructor.
+ */
+ IdentityTransformation() {
+ }
+
+ @Override
+ public Transformation rightTimes(Transformation transformation) {
+ return transformation;
+ }
+
+ @Override
+ public Transformation leftTimes(Transformation transformation) {
+ return transformation;
+ }
+
+ @Override
+ public Vector3d project(Vector3d vector) {
+ return vector;
+ }
+
+ @Override
+ public Vector3d projectDirection(Vector3d direction) {
+ return direction;
+ }
+
+ @Override
+ public Vector3d unproject(Vector3d vector) {
+ return vector;
+ }
+
+ @Override
+ public boolean isIdentity() {
+ return true;
+ }
+
+ @Override
+ public double[] getMatrix() {
+ return IDENTITY_MATRIX.clone();
+ }
+
+ @Override
+ public double[] getInverseMatrix() {
+ return IDENTITY_MATRIX.clone();
+ }
+ }
+
+ /**
+ * A translate transformation.
+ */
+ private static class TranslateTransformation extends AbstractTransformation {
+
+ /**
+ * translation in x coordinate.
+ */
+ private final double x;
+
+ /**
+ * translation in y coordinate.
+ */
+ private final double y;
+
+ /**
+ * translation in z coordinate.
+ */
+ private final double z;
+
+ /**
+ * Default constructor.
+ *
+ * (x, y, z) != (0, 0, 0).
+ *
+ * @param x translation in x coordinate.
+ * @param y translation in y coordinate.
+ * @param z translation in z coordinate.
+ */
+ public TranslateTransformation(double x, double y, double z) {
+ this.x = x;
+ this.y = y;
+ this.z = z;
+ }
+
+ @Override
+ public Vector3d project(Vector3d vector) {
+ return new Vector3d(vector.getX() + x, vector.getY() + y, vector.getZ() + z);
+ }
+
+ @Override
+ public Vector3d unproject(Vector3d vector) {
+ return new Vector3d(vector.getX() - x, vector.getY() - y, vector.getZ() - z);
+ }
+
+ @Override
+ public boolean isIdentity() {
+ return false;
+ }
+
+ @Override
+ public double[] getMatrix() {
+ return new double[] {
+ 1, 0, 0, 0,
+ 0, 1, 0, 0,
+ 0, 0, 1, 0,
+ x, y, z, 1
+ };
+ }
+
+ @Override
+ public double[] getInverseMatrix() {
+ return new double[] {
+ 1, 0, 0, 0,
+ 0, 1, 0, 0,
+ 0, 0, 1, 0,
+ -x, -y, -z, 1
+ };
+ }
+ }
+
+
+ /**
+ * A scale transformation.
+ */
+ private static class ScaleTransformation extends AbstractTransformation {
+
+ /**
+ * scale in x coordinate.
+ */
+ private final double x;
+
+ /**
+ * scale in y coordinate.
+ */
+ private final double y;
+
+ /**
+ * scale in z coordinate.
+ */
+ private final double z;
+
+
+ /**
+ * Default constructor.
+ *
+ * x, y and z not 0 or 1.
+ *
+ * @param x scale in x coordinate.
+ * @param y scale in y coordinate.
+ * @param z scale in z coordinate.
+ */
+ public ScaleTransformation(double x, double y, double z) {
+ this.x = x;
+ this.y = y;
+ this.z = z;
+ }
+
+ @Override
+ public Vector3d project(Vector3d vector) {
+ return new Vector3d(vector.getX() * x, vector.getY() * y, vector.getZ() * z);
+ }
+
+ @Override
+ public Vector3d unproject(Vector3d vector) {
+ return new Vector3d(vector.getX() / x, vector.getY() / y, vector.getZ() / z);
+ }
+
+ @Override
+ public boolean isIdentity() {
+ return false;
+ }
+
+ @Override
+ public double[] getMatrix() {
+ return new double[] {
+ x, 0, 0, 0,
+ 0, y, 0, 0,
+ 0, 0, z, 0,
+ 0, 0, 0, 1
+ };
+ }
+
+ @Override
+ public double[] getInverseMatrix() {
+ return new double[] {
+ 1 / x, 0, 0, 0,
+ 0, 1 / y, 0, 0,
+ 0, 0, 1 / z, 0,
+ 0, 0, 0, 1
+ };
+ }
+ }
+
+ /**
+ * A perspective transformation.
+ */
+ private static class PerspectiveTransformation extends AbstractTransformation {
+
+ private final double[] matrix;
+ private final double[] inverseMatrix;
+
+ /**
+ * Default constructor.
+ * @param near the distance to the near plane.
+ * @param far the distance to the far plane.
+ * @param fov the field of view in degree.
+ */
+ PerspectiveTransformation(double near, double far, double fov) {
+ double fInv = Math.tan(Math.toRadians(fov / 2));
+ double f = 1 / fInv;
+
+ matrix = new double[] {
+ f, 0, 0, 0,
+ 0, f, 0, 0,
+ 0, 0, (far + near) / (near - far), -1,
+ 0, 0, 2 * far * near / (near - far), 0
+ };
+
+ inverseMatrix = new double[] {
+ fInv, 0, 0, 0,
+ 0, fInv, 0, 0,
+ 0, 0, 0, (near - far) / (2 * far * near),
+ 0, 0, -1, (near + far) / (2 * far * near)
+ };
+ }
+
+ @Override
+ public boolean isIdentity() {
+ return false;
+ }
+
+ @Override
+ public double[] getMatrix() {
+ return matrix.clone();
+ }
+
+ @Override
+ public double[] getInverseMatrix() {
+ return inverseMatrix.clone();
+ }
+ }
+
+ /**
+ * An orthographic transformation.
+ */
+ private static class OrthographicTransformation extends AbstractTransformation {
+
+ private final double[] matrix;
+ private final double[] inverseMatrix;
+ private final boolean isIdentity;
+
+ /**
+ * Default constructor.
+ * @param left the left plane distance to origin.
+ * @param right the right plane distance to origin.
+ * @param bottom the bottom plane distance to origin.
+ * @param top the top plane distance to origin.
+ * @param near the near plane distance to origin.
+ * @param far the far plane distance to origin.
+ */
+ public OrthographicTransformation(double left, double right, double bottom, double top, double near, double far) {
+ double tx = (right + left) / (left - right);
+ double ty = (top + bottom) / (bottom - top);
+ double tz = (far + near) / (near - far);
+
+ matrix = new double[] {
+ 2 / (right - left), 0, 0, 0,
+ 0, 2 / (top - bottom), 0, 0,
+ 0, 0, 2 / (near - far), 0,
+ tx, ty, tz, 1
+ };
+
+ inverseMatrix = new double[] {
+ (right - left) / 2, 0, 0, 0,
+ 0, (top - bottom) / 2, 0, 0,
+ 0, 0, (near - far) / 2, 0,
+ (right + left) / 2, (top + bottom) / 2, -(near + far) / 2, 1
+ };
+
+ isIdentity = ((left == -1) && (right == 1) && (bottom == -1) && (top == 1) && (far == -1) && (near == 1));
+
+ }
+
+ @Override
+ public boolean isIdentity() {
+ return isIdentity;
+ }
+
+ @Override
+ public double[] getMatrix() {
+ return matrix.clone();
+ }
+
+ @Override
+ public double[] getInverseMatrix() {
+ return inverseMatrix.clone();
+ }
+ }
+
+ /**
+ * A rotation transformation.
+ */
+ private static class RotationTransformation extends AbstractTransformation {
+
+ private final double[] matrix;
+ private final double[] inverseMatrix;
+
+ /**
+ * Default constructor.
+ * @param q the quaternion.
+ */
+ public RotationTransformation(Rotation q) {
+ matrix = q.getRotationMatrix();
+ inverseMatrix = q.getUnRotateMatrix();
+ }
+
+ @Override
+ public boolean isIdentity() {
+ return false;
+ }
+
+ @Override
+ public double[] getMatrix() {
+ return matrix.clone();
+ }
+
+ @Override
+ public double[] getInverseMatrix() {
+ return inverseMatrix.clone();
+ }
+ }
+
+ /**
+ * A product transformation.
+ */
+ private static class ProductTransformation extends AbstractTransformation {
+
+ private final double[] matrix;
+ private final double[] inverseMatrix;
+ private final boolean isIdentity;
+
+ /**
+ * Default constructor.
+ * @param t1 first transformation.
+ * @param t2 first transformation.
+ */
+ public ProductTransformation(Transformation t1, Transformation t2) {
+ isIdentity = t1.isIdentity() && t2.isIdentity();
+ matrix = multiply(t1.getMatrix(), t2.getMatrix());
+
+ // TODO : inverse 'matrix' instead.
+ inverseMatrix = multiply(t2.getInverseMatrix(), t1.getInverseMatrix());
+ }
+
+ @Override
+ public boolean isIdentity() {
+ return isIdentity;
+ }
+
+ @Override
+ public double[] getMatrix() {
+ return matrix.clone();
+ }
+
+ @Override
+ public double[] getInverseMatrix() {
+ return inverseMatrix.clone();
+ }
+ }
+
+ /**
+ * Multiply two matrix.
+ * @param matrix1 first matrix.
+ * @param matrix2 second matrix.
+ * @return matrix1 x matrix2
+ */
+ private static double[] multiply(double[] matrix1, double[] matrix2) {
+ double[] result = new double[16];
+ for (int l = 0; l < 4; l++) {
+ for (int c = 0; c < 4; c++) {
+ double r = 0;
+ for (int i = 0; i < 4; i++) {
+ r += matrix1[(4 * i) + c] * matrix2[(4 * l) + i];
+ }
+ result[(4 * l) + c] = r;
+ }
+ }
+ return result;
+ }
+}
diff --git a/modules/scirenderer/src/org/scilab/forge/scirenderer/tranformations/TransformationManager.java b/modules/scirenderer/src/org/scilab/forge/scirenderer/tranformations/TransformationManager.java
new file mode 100755
index 000000000..c0c900c3a
--- /dev/null
+++ b/modules/scirenderer/src/org/scilab/forge/scirenderer/tranformations/TransformationManager.java
@@ -0,0 +1,118 @@
+/*
+ * Scilab ( http://www.scilab.org/ ) - This file is part of Scilab
+ * Copyright (C) 2009-2011 - DIGITEO - Pierre Lando
+ *
+ * This file must be used under the terms of the CeCILL.
+ * This source file is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at
+ * http://www.cecill.info/licences/Licence_CeCILL_V2.1-en.txt
+ */
+
+package org.scilab.forge.scirenderer.tranformations;
+
+/**
+ *
+ * This is an interface for a transformation manager.
+ * The transformation manager is used to manage transformation applied to vertex data sent for drawing.
+ *
+ * Coordinate are in first multiplied by the matrix at the top of ModelView matrix stack.
+ * And then, the result is multiplied by the matrix at the top of Projection matrix stack.
+ *
+ * 'Projection' and 'ModelView' name refers to OpenGl 1.1.
+ *
+ * The rendered vertex are in the box [-1, 1]^3.
+ *
+ * @author Pierre Lando
+ */
+public interface TransformationManager {
+
+ /**
+ * Add a listener.
+ * @param listener added.
+ */
+ void addListener(TransformationManagerListener listener);
+
+ /**
+ * Remove a listener.
+ * @param listener removed.
+ */
+ void removeListener(TransformationManagerListener listener);
+
+
+ /**
+ * Return the model view matrix stack.
+ * @return the model view matrix stack.
+ */
+ TransformationStack getModelViewStack();
+
+ /**
+ * Return the projection matrix stack.
+ * @return the projection matrix stack.
+ */
+ TransformationStack getProjectionStack();
+
+ /**
+ * Return the top scene transformation.
+ * @return the top scene transformation.
+ */
+ Transformation getTransformation();
+
+ /**
+ * Return the inverse of window transformation.
+ * @return the inverse window transformation.
+ */
+ Transformation getInverseWindowTransformation();
+
+ /**
+ * Return the window transformation.
+ * @return the window transformation.
+ */
+ Transformation getWindowTransformation();
+
+ /**
+ * Return the canvas projection matrix.
+ * @return the canvas projection matrix.
+ */
+ Transformation getCanvasProjection();
+
+ /**
+ * Return the canvas projection matrix for Graphics2D.
+ * @return the canvas projection matrix.
+ */
+ Transformation getG2DProjection();
+
+ /**
+ * Return the projection matrix (no modelView).
+ * @return the projection matrix.
+ */
+ Transformation getG2DSingleProjection();
+
+ /**
+ * Return the window projection matrix for Graphics2D.
+ * @return the window projection matrix.
+ */
+ Transformation getG2DWindowProjection();
+
+ /**
+ * Clear all stack.
+ */
+ void reset();
+
+
+ /**
+ * Switch to window coordinate.
+ */
+ void useWindowCoordinate();
+
+ /**
+ * Switch to scene coordinate.
+ */
+ void useSceneCoordinate();
+
+ /**
+ * Return true if is using scene coordinate.
+ * @return true if is using scene coordinate.
+ */
+ boolean isUsingSceneCoordinate();
+}
diff --git a/modules/scirenderer/src/org/scilab/forge/scirenderer/tranformations/TransformationManagerImpl.java b/modules/scirenderer/src/org/scilab/forge/scirenderer/tranformations/TransformationManagerImpl.java
new file mode 100755
index 000000000..e8bef60f3
--- /dev/null
+++ b/modules/scirenderer/src/org/scilab/forge/scirenderer/tranformations/TransformationManagerImpl.java
@@ -0,0 +1,226 @@
+/*
+ * Scilab ( http://www.scilab.org/ ) - This file is part of Scilab
+ * Copyright (C) 2009-2011 - DIGITEO - Pierre Lando
+ *
+ * This file must be used under the terms of the CeCILL.
+ * This source file is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at
+ * http://www.cecill.info/licences/Licence_CeCILL_V2.1-en.txt
+ */
+
+package org.scilab.forge.scirenderer.tranformations;
+
+import org.scilab.forge.scirenderer.Canvas;
+
+import javax.swing.event.EventListenerList;
+
+/**
+ * Default {@link org.scilab.forge.scirenderer.tranformations.TransformationManager} implementation.
+ * @author Pierre Lando
+ */
+public class TransformationManagerImpl implements TransformationManager {
+
+ /**
+ * We use swing EventListenerList for facility.
+ */
+ private final EventListenerList listeners;
+
+ private final Canvas canvas;
+ private final TransformationStack modelViewStack;
+ private final TransformationStack projectionStack;
+
+ /**
+ * The peek transformation value.
+ * Set to null if it must be recalculate.
+ */
+ private Transformation topTransformation;
+ private boolean usingSceneCoordinate = true;
+
+
+ /**
+ * Standard constructor.
+ * @param canvas the canvas.
+ */
+ public TransformationManagerImpl(Canvas canvas) {
+ this.canvas = canvas;
+ listeners = new EventListenerList();
+ modelViewStack = new TransformationStackImpl();
+ projectionStack = new TransformationStackImpl();
+ topTransformation = null;
+
+
+ final TransformationStackListener listener = new TransformationStackListener() {
+ @Override
+ public void changed(TransformationStack transformationStack, TransformationStack.TransformationStackEvent event, Transformation top) {
+ topTransformation = null;
+ fireTransformationChanged();
+ }
+ };
+
+ modelViewStack.addListener(listener);
+ projectionStack.addListener(listener);
+ }
+
+
+ @Override
+ public void addListener(TransformationManagerListener listener) {
+ listeners.add(TransformationManagerListener.class, listener);
+ }
+
+ @Override
+ public void removeListener(TransformationManagerListener listener) {
+ listeners.remove(TransformationManagerListener.class, listener);
+ }
+
+ @Override
+ public TransformationStack getModelViewStack() {
+ return modelViewStack;
+ }
+
+ @Override
+ public TransformationStack getProjectionStack() {
+ return projectionStack;
+ }
+
+ @Override
+ public Transformation getTransformation() {
+ if (topTransformation == null) {
+ final Transformation modelView = modelViewStack.peek();
+ final Transformation projection = projectionStack.peek();
+ final Transformation returnedTransformation = projection.rightTimes(modelView);
+ topTransformation = returnedTransformation;
+ return returnedTransformation;
+ } else {
+ return topTransformation;
+ }
+ }
+
+ @Override
+ public Transformation getWindowTransformation() {
+ double w = 2.0 / canvas.getWidth();
+ double h = 2.0 / canvas.getHeight();
+ try {
+ return TransformationFactory.getAffineTransformation(
+ new Vector3d(w, h, 1),
+ new Vector3d(-1, -1, 0)
+ );
+ } catch (DegenerateMatrixException e) {
+ // Should not occur as long as canvas have not infinite size.
+ throw new Error("Canvas is to big.", e);
+ }
+ }
+
+ @Override
+ public Transformation getInverseWindowTransformation() {
+ double w = canvas.getWidth() / 2;
+ double h = canvas.getHeight() / 2;
+ try {
+ return TransformationFactory.getAffineTransformation(
+ new Vector3d(w, h, 1),
+ new Vector3d(w, h, 0)
+ );
+ } catch (DegenerateMatrixException e) {
+ // Should not occur as long as canvas have not infinite size.
+ throw new Error("Canvas is to big.", e);
+ }
+ }
+
+ @Override
+ public Transformation getCanvasProjection() {
+ double w = canvas.getWidth() / 2.0;
+ double h = canvas.getHeight() / 2.0;
+ try {
+ Transformation windowTransformation = TransformationFactory.getAffineTransformation(
+ new Vector3d(w, h, 1),
+ new Vector3d(w, h, 0)
+ );
+ return windowTransformation.rightTimes(getTransformation());
+ } catch (DegenerateMatrixException e) {
+ // Should not occur as long as canvas have not infinite size.
+ throw new Error("Canvas is to big.", e);
+ }
+ }
+
+ @Override
+ public Transformation getG2DProjection() {
+ double w = canvas.getWidth() / 2.0;
+ double h = canvas.getHeight() / 2.0;
+ try {
+ Transformation windowTransformation = TransformationFactory.getAffineTransformation(
+ new Vector3d(w, -h, 1),
+ new Vector3d(w, h, 0)
+ );
+ return windowTransformation.rightTimes(getTransformation());
+ } catch (DegenerateMatrixException e) {
+ // Should not occur as long as canvas have not infinite size.
+ throw new Error("Canvas is to big.", e);
+ }
+ }
+
+ @Override
+ public Transformation getG2DSingleProjection() {
+ double w = canvas.getWidth() / 2.0;
+ double h = canvas.getHeight() / 2.0;
+ try {
+ Transformation windowTransformation = TransformationFactory.getAffineTransformation(
+ new Vector3d(w, -h, 1),
+ new Vector3d(w, h, 0)
+ );
+ return windowTransformation.rightTimes(projectionStack.peek());
+ } catch (DegenerateMatrixException e) {
+ // Should not occur as long as canvas have not infinite size.
+ throw new Error("Canvas is to big.", e);
+ }
+ }
+
+ @Override
+ public Transformation getG2DWindowProjection() {
+ double h = canvas.getHeight();
+ try {
+ return TransformationFactory.getAffineTransformation(
+ new Vector3d(1, -1, 1),
+ new Vector3d(0, h, 0)
+ );
+ } catch (DegenerateMatrixException e) {
+ // Should not occur as long as canvas have not infinite size.
+ throw new Error("Canvas is to big.", e);
+ }
+ }
+
+ @Override
+ public void reset() {
+ modelViewStack.clear();
+ projectionStack.clear();
+ }
+
+ @Override
+ public void useWindowCoordinate() {
+ if (isUsingSceneCoordinate()) {
+ usingSceneCoordinate = false;
+ fireTransformationChanged();
+ }
+ }
+
+ @Override
+ public void useSceneCoordinate() {
+ if (!isUsingSceneCoordinate()) {
+ usingSceneCoordinate = true;
+ fireTransformationChanged();
+ }
+ }
+
+ @Override
+ public boolean isUsingSceneCoordinate() {
+ return usingSceneCoordinate;
+ }
+
+ /**
+ * Notify listeners the top transformation have changed.
+ */
+ protected void fireTransformationChanged() {
+ for (TransformationManagerListener listener : listeners.getListeners(TransformationManagerListener.class)) {
+ listener.transformationChanged(this);
+ }
+ }
+}
diff --git a/modules/scirenderer/src/org/scilab/forge/scirenderer/tranformations/TransformationManagerListener.java b/modules/scirenderer/src/org/scilab/forge/scirenderer/tranformations/TransformationManagerListener.java
new file mode 100755
index 000000000..97193553f
--- /dev/null
+++ b/modules/scirenderer/src/org/scilab/forge/scirenderer/tranformations/TransformationManagerListener.java
@@ -0,0 +1,31 @@
+/*
+ * Scilab ( http://www.scilab.org/ ) - This file is part of Scilab
+ * Copyright (C) 2009-2011 - DIGITEO - Pierre Lando
+ *
+ * This file must be used under the terms of the CeCILL.
+ * This source file is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at
+ * http://www.cecill.info/licences/Licence_CeCILL_V2.1-en.txt
+ */
+
+package org.scilab.forge.scirenderer.tranformations;
+
+import java.util.EventListener;
+
+/**
+ *
+ * The listener of a {@link org.scilab.forge.scirenderer.tranformations.TransformationManager} functions are called when events occurs in the
+ * listened {@link org.scilab.forge.scirenderer.tranformations.TransformationManager}.
+ *
+ * @author Pierre Lando
+ */
+public interface TransformationManagerListener extends EventListener {
+
+ /**
+ * Called when the top transformation of the listened TransformationManager have changed.
+ * @param transformationManager object where event occur.
+ */
+ void transformationChanged(final TransformationManager transformationManager);
+
+}
diff --git a/modules/scirenderer/src/org/scilab/forge/scirenderer/tranformations/TransformationStack.java b/modules/scirenderer/src/org/scilab/forge/scirenderer/tranformations/TransformationStack.java
new file mode 100755
index 000000000..7805e1254
--- /dev/null
+++ b/modules/scirenderer/src/org/scilab/forge/scirenderer/tranformations/TransformationStack.java
@@ -0,0 +1,86 @@
+/*
+ * Scilab ( http://www.scilab.org/ ) - This file is part of Scilab
+ * Copyright (C) 2009-2011 - DIGITEO - Pierre Lando
+ *
+ * This file must be used under the terms of the CeCILL.
+ * This source file is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at
+ * http://www.cecill.info/licences/Licence_CeCILL_V2.1-en.txt
+ */
+
+package org.scilab.forge.scirenderer.tranformations;
+
+/**
+ * @author Pierre Lando
+ */
+public interface TransformationStack {
+
+ /**
+ * Enum of possible transformation stack event.
+ */
+ enum TransformationStackEvent {
+ /**
+ * When a matrix have been popped.
+ */
+ POPPED,
+
+ /**
+ * When a matrix have been pushed.
+ */
+ PUSHED,
+
+ /**
+ * When the stack have been cleared.
+ */
+ CLEARED
+ }
+
+
+ /**
+ * Add a listener.
+ * @param listener added listener.
+ */
+ void addListener(TransformationStackListener listener);
+
+ /**
+ * Remove a listener.
+ * @param listener removed listener.
+ */
+ void removeListener(TransformationStackListener listener);
+
+ /**
+ * Return the top transformation.
+ * @return the top transformation.
+ */
+ Transformation peek();
+
+ /**
+ * Push the given transformation on the stack.
+ * @param transformation the given transformation.
+ */
+ void push(Transformation transformation);
+
+ /**
+ * Push the given transformation right time the peek on the stack.
+ * @param transformation the given transformation.
+ */
+ void pushRightMultiply(Transformation transformation);
+
+ /**
+ * Push the given transformation left time the peek on the stack.
+ * @param transformation the given transformation.
+ */
+ void pushLeftMultiply(Transformation transformation);
+
+ /**
+ * Pop one matrix on the stack.
+ * @return the popped matrix.
+ */
+ Transformation pop();
+
+ /**
+ * Pop all matrix on the stack except identity.
+ */
+ void clear();
+}
diff --git a/modules/scirenderer/src/org/scilab/forge/scirenderer/tranformations/TransformationStackImpl.java b/modules/scirenderer/src/org/scilab/forge/scirenderer/tranformations/TransformationStackImpl.java
new file mode 100755
index 000000000..452618e09
--- /dev/null
+++ b/modules/scirenderer/src/org/scilab/forge/scirenderer/tranformations/TransformationStackImpl.java
@@ -0,0 +1,98 @@
+/*
+ * Scilab ( http://www.scilab.org/ ) - This file is part of Scilab
+ * Copyright (C) 2009-2011 - DIGITEO - Pierre Lando
+ *
+ * This file must be used under the terms of the CeCILL.
+ * This source file is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at
+ * http://www.cecill.info/licences/Licence_CeCILL_V2.1-en.txt
+ */
+
+package org.scilab.forge.scirenderer.tranformations;
+
+import java.util.Stack;
+
+import javax.swing.event.EventListenerList;
+
+/**
+ * @author Pierre Lando
+ */
+public class TransformationStackImpl implements TransformationStack {
+
+ /**
+ * We use swing EventListenerList for facility.
+ */
+ private final EventListenerList listeners;
+
+ private final Stack<Transformation> stack;
+
+ public TransformationStackImpl() {
+ listeners = new EventListenerList();
+ stack = new Stack<Transformation>();
+ }
+
+ @Override
+ public void addListener(TransformationStackListener listener) {
+ listeners.add(TransformationStackListener.class, listener);
+ }
+
+ @Override
+ public void removeListener(TransformationStackListener listener) {
+ listeners.remove(TransformationStackListener.class, listener);
+ }
+
+ @Override
+ public Transformation peek() {
+ if (stack.isEmpty()) {
+ return TransformationFactory.getIdentity();
+ } else {
+ return stack.peek();
+ }
+ }
+
+ @Override
+ public void push(Transformation transformation) {
+ if (transformation != null) {
+ stack.push(transformation);
+ fireChanged(TransformationStackEvent.PUSHED, transformation);
+ }
+ }
+
+ @Override
+ public void pushRightMultiply(Transformation transformation) {
+ push(peek().rightTimes(transformation));
+ }
+
+ @Override
+ public void pushLeftMultiply(Transformation transformation) {
+ push(peek().leftTimes(transformation));
+ }
+
+ @Override
+ public Transformation pop() {
+ Transformation value = stack.pop();
+ if (value == null) {
+ value = TransformationFactory.getIdentity();
+ }
+ fireChanged(TransformationStackEvent.POPPED, value);
+ return value;
+ }
+
+ @Override
+ public void clear() {
+ stack.clear();
+ fireChanged(TransformationStackEvent.CLEARED, peek());
+ }
+
+ /**
+ * Fire a change event.
+ * @param event the event.
+ * @param top the new top transformation.
+ */
+ protected void fireChanged(TransformationStackEvent event, Transformation top) {
+ for (TransformationStackListener listener : listeners.getListeners(TransformationStackListener.class)) {
+ listener.changed(this, event, top);
+ }
+ }
+}
diff --git a/modules/scirenderer/src/org/scilab/forge/scirenderer/tranformations/TransformationStackListener.java b/modules/scirenderer/src/org/scilab/forge/scirenderer/tranformations/TransformationStackListener.java
new file mode 100755
index 000000000..040b678fa
--- /dev/null
+++ b/modules/scirenderer/src/org/scilab/forge/scirenderer/tranformations/TransformationStackListener.java
@@ -0,0 +1,28 @@
+/*
+ * Scilab ( http://www.scilab.org/ ) - This file is part of Scilab
+ * Copyright (C) 2009-2011 - DIGITEO - Pierre Lando
+ *
+ * This file must be used under the terms of the CeCILL.
+ * This source file is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at
+ * http://www.cecill.info/licences/Licence_CeCILL_V2.1-en.txt
+ */
+
+package org.scilab.forge.scirenderer.tranformations;
+
+import java.util.EventListener;
+
+/**
+ * @author Pierre Lando
+ */
+public interface TransformationStackListener extends EventListener {
+
+ /**
+ * Called when an event occur in the listened transformation stack.
+ * @param transformationStack the transformation stack where the event occur.
+ * @param event the event.
+ * @param top the new peek transformation of the stack.
+ */
+ void changed(final TransformationStack transformationStack, final TransformationStack.TransformationStackEvent event, final Transformation top);
+}
diff --git a/modules/scirenderer/src/org/scilab/forge/scirenderer/tranformations/Vector3d.java b/modules/scirenderer/src/org/scilab/forge/scirenderer/tranformations/Vector3d.java
new file mode 100755
index 000000000..5feccb266
--- /dev/null
+++ b/modules/scirenderer/src/org/scilab/forge/scirenderer/tranformations/Vector3d.java
@@ -0,0 +1,206 @@
+/*
+ * Scilab ( http://www.scilab.org/ ) - This file is part of Scilab
+ * Copyright (C) 2009-2011 - DIGITEO - Pierre Lando
+ *
+ * This file must be used under the terms of the CeCILL.
+ * This source file is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at
+ * http://www.cecill.info/licences/Licence_CeCILL_V2.1-en.txt
+ */
+
+package org.scilab.forge.scirenderer.tranformations;
+
+import java.util.Arrays;
+
+/**
+ * @author Pierre Lando
+ */
+public class Vector3d {
+
+ private final double x;
+ private final double y;
+ private final double z;
+ private int hash = -1;
+
+ public Vector3d(Vector3d v) {
+ this.x = v.x;
+ this.y = v.y;
+ this.z = v.z;
+ }
+
+ public Vector3d(double x, double y, double z) {
+ this.x = x;
+ this.y = y;
+ this.z = z;
+ }
+
+ public Vector3d(float[] position) {
+ this.x = position[0];
+ this.y = position[1];
+ this.z = position[2];
+ }
+
+ public Vector3d(double[] position) {
+ this.x = position[0];
+ this.y = position[1];
+ this.z = position[2];
+ }
+
+ public Vector3d(Double[] position) {
+ this.x = position[0];
+ this.y = position[1];
+ this.z = position[2];
+ }
+
+ public double getX() {
+ return x;
+ }
+
+ public double getY() {
+ return y;
+ }
+
+ public double getZ() {
+ return z;
+ }
+
+ @Override
+ public String toString() {
+ return "[" + x + ", " + y + ", " + z + "]";
+ }
+
+ public double[] getData() {
+ return new double[] {x, y, z};
+ }
+
+ public float[] getDataAsFloatArray() {
+ return new float[] {(float) x, (float) y, (float) z};
+ }
+
+ public float[] getDataAsFloatArray(int size) {
+ if (size == 4) {
+ return new float[] {(float) x, (float) y, (float) z, 1};
+ } else {
+ return new float[] {(float) x, (float) y, (float) z};
+ }
+ }
+
+ public Vector3d plus(Vector3d v) {
+ return new Vector3d(x + v.x, y + v.y, z + v.z);
+ }
+
+ public Vector3d minus(Vector3d v) {
+ return new Vector3d(x - v.x, y - v.y, z - v.z);
+ }
+
+ public Vector3d times(double d) {
+ return new Vector3d(x * d, y * d, z * d);
+ }
+
+ public Vector3d getNormalized() {
+ double norm = getNorm();
+ if (norm == 0) {
+ return new Vector3d(0, 0, 0);
+ }
+ return this.times(1 / getNorm());
+ }
+
+ public double getNorm() {
+ return Math.sqrt(getNorm2());
+ }
+
+ public double getNorm2() {
+ return scalar(this);
+ }
+
+ public double scalar(Vector3d v) {
+ return x * v.x + y * v.y + z * v.z;
+ }
+
+ /**
+ * Create a new vector cross-product of the given vectors.
+ * @param v1 the first given vector.
+ * @param v2 the second given vector.
+ * @return a new vector cross-product of the given vectors.
+ */
+ public static Vector3d product(Vector3d v1, Vector3d v2) {
+ return new Vector3d(
+ v1.y * v2.z - v1.z * v2.y,
+ v1.z * v2.x - v1.x * v2.z,
+ v1.x * v2.y - v1.y * v2.x
+ );
+ }
+
+ public final static double det(final Vector3d v0, final Vector3d v1, final Vector3d v2) {
+ return v0.x * (v1.y * v2.z - v1.z * v2.y) + v0.y * (v1.z * v2.x - v1.x * v2.z) + v0.z * (v1.x * v2.y - v1.y * v2.x);
+ }
+
+ public final static Vector3d getBarycenter(Vector3d v0, Vector3d v1, double w0, double w1) {
+ return new Vector3d(v0.x * w0 + v1.x * w1, v0.y * w0 + v1.y * w1, v0.z * w0 + v1.z * w1);
+ }
+
+ /**
+ * Create a new vector, copy of this one, with a new X value.
+ * @param x the new X value.
+ * @return a new vector, copy of this one, with a new X value.
+ */
+ public Vector3d setX(double x) {
+ return new Vector3d(x, y, z);
+ }
+
+
+ /**
+ * Create a new vector, copy of this one, with a new Y value.
+ * @param y the new Y value.
+ * @return a new vector, copy of this one, with a new Y value.
+ */
+ public Vector3d setY(double y) {
+ return new Vector3d(x, y, z);
+ }
+
+
+ /**
+ * Create a new vector, copy of this one, with a new Z value.
+ * @param z the new Z value.
+ * @return a new vector, copy of this one, with a new Z value.
+ */
+ public Vector3d setZ(double z) {
+ return new Vector3d(x, y, z);
+ }
+
+ /**
+ * Return true if this vector is (0, 0, 0).
+ * @return true if this vector is (0, 0, 0).
+ */
+ public boolean isZero() {
+ return (x == 0) && (y == 0) && (z == 0);
+ }
+
+ /**
+ * Return true if this vector is (0, 0, 0).
+ * @return true if this vector is (0, 0, 0).
+ */
+ public boolean isNearZero() {
+ final double eps = 1e-9;
+ return Math.abs(x) <= eps && Math.abs(y) <= eps && Math.abs(z) <= eps;
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (obj instanceof Vector3d) {
+ Vector3d v = (Vector3d) obj;
+ final double eps = 1e-9;
+ return Math.abs(v.x - x) <= eps && Math.abs(v.y - y) <= eps && Math.abs(v.z - z) <= eps;
+ }
+ return false;
+ }
+
+ @Override
+ public int hashCode() {
+ if (hash == -1) {
+ hash = Arrays.hashCode(new double[] {x, y, z});
+ }
+ return hash;
+ }
+}
diff --git a/modules/scirenderer/src/org/scilab/forge/scirenderer/tranformations/Vector3f.java b/modules/scirenderer/src/org/scilab/forge/scirenderer/tranformations/Vector3f.java
new file mode 100755
index 000000000..281276870
--- /dev/null
+++ b/modules/scirenderer/src/org/scilab/forge/scirenderer/tranformations/Vector3f.java
@@ -0,0 +1,106 @@
+/*
+ * Scilab ( http://www.scilab.org/ ) - This file is part of Scilab
+ * Copyright (C) 2009-2011 - DIGITEO - Pierre Lando
+ *
+ * This file must be used under the terms of the CeCILL.
+ * This source file is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at
+ * http://www.cecill.info/licences/Licence_CeCILL_V2.1-en.txt
+ */
+
+package org.scilab.forge.scirenderer.tranformations;
+
+/**
+ * @author Pierre Lando
+ */
+public class Vector3f {
+ private final float x;
+ private final float y;
+ private final float z;
+
+ public Vector3f(float x, float y, float z) {
+ this.x = x;
+ this.y = y;
+ this.z = z;
+ }
+
+ public float getX() {
+ return x;
+ }
+
+ public float getY() {
+ return y;
+ }
+
+ public float getZ() {
+ return z;
+ }
+
+ @Override
+ public String toString() {
+ return "[" + x + ", " + y + ", " + z + "]";
+ }
+
+ public Vector3d asDouble() {
+ return new Vector3d(x, y, z);
+ }
+
+ public Vector3f plus(Vector3f v) {
+ return new Vector3f(x + v.x, y + v.y, z + v.z);
+ }
+
+ public Vector3f minus(Vector3f v) {
+ return new Vector3f(x - v.x, y - v.y, z - v.z);
+ }
+
+ public Vector3f negate() {
+ return new Vector3f(-x, -y, -z);
+ }
+
+ public Vector3f times(float d) {
+ return new Vector3f(x * d, y * d, z * d);
+ }
+
+ public Vector3f getNormalized() {
+ float norm = getNorm();
+ if (norm == 0) {
+ return new Vector3f(0.0f, 0.0f, 0.0f);
+ }
+ return this.times(1.0f / getNorm());
+ }
+
+ public float getNorm() {
+ return (float)Math.sqrt(getNorm2());
+ }
+
+ public float getNorm2() {
+ return scalar(this);
+ }
+
+ public float scalar(Vector3f v) {
+ return x * v.x + y * v.y + z * v.z;
+ }
+
+ /**
+ * Create a new vector cross-product of the given vectors.
+ * @param v1 the first given vector.
+ * @param v2 the second given vector.
+ * @return a new vector cross-product of the given vectors.
+ */
+ public static Vector3f product(Vector3f v1, Vector3f v2) {
+ return new Vector3f(
+ v1.y * v2.z - v1.z * v2.y,
+ v1.z * v2.x - v1.x * v2.z,
+ v1.x * v2.y - v1.y * v2.x
+ );
+ }
+
+ public final static float det(final Vector3f v0, final Vector3f v1, final Vector3f v2) {
+ return v0.x * (v1.y * v2.z - v1.z * v2.y) + v0.y * (v1.z * v2.x - v1.x * v2.z) + v0.z * (v1.x * v2.y - v1.y * v2.x);
+ }
+
+ public final static Vector3f getBarycenter(Vector3f v0, Vector3f v1, float w0, float w1) {
+ return new Vector3f(v0.x * w0 + v1.x * w1, v0.y * w0 + v1.y * w1, v0.z * w0 + v1.z * w1);
+ }
+}
diff --git a/modules/scirenderer/src/org/scilab/forge/scirenderer/tranformations/Vector4d.java b/modules/scirenderer/src/org/scilab/forge/scirenderer/tranformations/Vector4d.java
new file mode 100755
index 000000000..66a9dc60e
--- /dev/null
+++ b/modules/scirenderer/src/org/scilab/forge/scirenderer/tranformations/Vector4d.java
@@ -0,0 +1,32 @@
+/*
+ * Scilab ( http://www.scilab.org/ ) - This file is part of Scilab
+ * Copyright (C) 2009-2011 - DIGITEO - Pierre Lando
+ *
+ * This file must be used under the terms of the CeCILL.
+ * This source file is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at
+ * http://www.cecill.info/licences/Licence_CeCILL_V2.1-en.txt
+ */
+
+package org.scilab.forge.scirenderer.tranformations;
+
+/**
+ * @author Pierre Lando
+ */
+public class Vector4d {
+ private final double[] data;
+
+
+ public Vector4d(double x, double y, double z, double w) {
+ data = new double[] {x, y, z, w};
+ }
+
+ public double[] getData() {
+ return data.clone();
+ }
+
+ public String toString() {
+ return "[" + data[0] + ", " + data[1] + ", " + data[2] + ", " + data[3] + "]";
+ }
+}
diff --git a/modules/scirenderer/src/org/scilab/forge/scirenderer/utils/shapes/geometry/CubeFactory.java b/modules/scirenderer/src/org/scilab/forge/scirenderer/utils/shapes/geometry/CubeFactory.java
new file mode 100755
index 000000000..7c42467b3
--- /dev/null
+++ b/modules/scirenderer/src/org/scilab/forge/scirenderer/utils/shapes/geometry/CubeFactory.java
@@ -0,0 +1,170 @@
+/*
+ * Scilab ( http://www.scilab.org/ ) - This file is part of Scilab
+ * Copyright (C) 2009-2011 - DIGITEO - Pierre Lando
+ *
+ * This file must be used under the terms of the CeCILL.
+ * This source file is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at
+ * http://www.cecill.info/licences/Licence_CeCILL_V2.1-en.txt
+ */
+
+package org.scilab.forge.scirenderer.utils.shapes.geometry;
+
+import org.scilab.forge.scirenderer.Canvas;
+import org.scilab.forge.scirenderer.buffers.BuffersManager;
+import org.scilab.forge.scirenderer.buffers.ElementsBuffer;
+import org.scilab.forge.scirenderer.buffers.IndicesBuffer;
+import org.scilab.forge.scirenderer.shapes.geometry.DefaultGeometry;
+import org.scilab.forge.scirenderer.shapes.geometry.Geometry;
+
+import java.nio.FloatBuffer;
+import java.nio.IntBuffer;
+
+/**
+ * An utility class to create cube geometry.
+ * @author Pierre Lando
+ */
+public final class CubeFactory {
+
+ /**
+ * The vertex size.
+ */
+ private static final int VERTEX_SIZE = 4;
+
+ /**
+ * The constructor is private : this is an utility class.
+ */
+ private CubeFactory() {
+ }
+
+ /**
+ * Return a geometry representing a simple cube.
+ * @param canvas the canvas where the buffers are created.
+ * @return a geometry representing a simple cube.
+ */
+ public static Geometry createCube(Canvas canvas) {
+ return createCube(canvas, 1);
+ }
+
+ /**
+ * Return a geometry representing a cube.
+ * Each cube face are made of density^2 square.
+ *
+ * @param canvas the canvas where the geometry buffers are created.
+ * @param density the square density on cube faces.
+ * @return a geometry representing a cube.
+ */
+ public static Geometry createCube(Canvas canvas, int density) {
+ return createCube(canvas, density, false);
+ }
+
+ /**
+ * Return a geometry representing a cube.
+ * Each cube face are made of density^2 square.
+ *
+ * @param canvas the canvas where the geometry buffers are created.
+ * @param density the square density on cube faces.
+ * @param wired true if the wire is visible.
+ * @return a geometry representing a cube.
+ */
+ public static Geometry createCube(Canvas canvas, int density, boolean wired) {
+ if (density < 1) {
+ return null;
+ } else {
+ int borderLength = density + 1;
+ FloatBuffer vertices = FloatBuffer.allocate(6 * borderLength * borderLength * 4);
+ FloatBuffer normals = FloatBuffer.allocate(6 * borderLength * borderLength * 4);
+ IntBuffer indices = IntBuffer.allocate(6 * 6 * density * density);
+ IntBuffer wireIndices = IntBuffer.allocate(8 * 6 * density * density);
+
+ int shift = 0;
+ for (int axes = 0; axes < 3; axes++) {
+ for (int orientation : new int[] { -1, 1}) {
+ float[] normal = getVectorPermutation(axes, 0, 0, orientation);
+ for (int i = 0; i < borderLength; i++) {
+ for (int j = 0; j < borderLength; j++) {
+ float s = (2f * i) / density - 1f;
+ float t = (2f * j) / density - 1f;
+ vertices.put(getVectorPermutation(axes, s, t, orientation));
+ normals.put(normal);
+ }
+ }
+ for (int i = 0; i < density; i++) {
+ for (int j = 0; j < density; j++) {
+ int index = shift + j + i * borderLength;
+ indices.put(index);
+ indices.put(index + 1);
+ indices.put(index + borderLength);
+
+ indices.put(index + 1);
+ indices.put(index + borderLength + 1);
+ indices.put(index + borderLength);
+
+ wireIndices.put(index);
+ wireIndices.put(index + 1);
+ wireIndices.put(index + 1);
+ wireIndices.put(index + borderLength + 1);
+ wireIndices.put(index + borderLength + 1);
+ wireIndices.put(index + borderLength);
+ wireIndices.put(index + borderLength);
+ wireIndices.put(index);
+ }
+ }
+ shift += borderLength * borderLength;
+ }
+ }
+
+ vertices.rewind();
+ normals.rewind();
+ indices.rewind();
+
+ BuffersManager bm = canvas.getBuffersManager();
+ final ElementsBuffer verticesBuffer = bm.createElementsBuffer();
+ final ElementsBuffer normalsBuffer = bm.createElementsBuffer();
+ final IndicesBuffer indicesBuffer = bm.createIndicesBuffer();
+
+ verticesBuffer.setData(vertices, VERTEX_SIZE);
+ normalsBuffer.setData(normals, VERTEX_SIZE);
+ indicesBuffer.setData(indices);
+
+ DefaultGeometry geometry = new DefaultGeometry();
+ geometry.setFaceCullingMode(Geometry.FaceCullingMode.BOTH);
+ geometry.setFillDrawingMode(Geometry.FillDrawingMode.TRIANGLES);
+ geometry.setVertices(verticesBuffer);
+ geometry.setNormals(normalsBuffer);
+ geometry.setIndices(indicesBuffer);
+
+ if (wired) {
+ final IndicesBuffer wireIndicesBuffer = bm.createIndicesBuffer();
+ wireIndicesBuffer.setData(wireIndices);
+ geometry.setWireIndices(wireIndicesBuffer);
+ geometry.setLineDrawingMode(Geometry.LineDrawingMode.SEGMENTS);
+ geometry.setPolygonOffsetMode(true);
+ }
+
+ return geometry;
+ }
+ }
+
+ /**
+ * Return a permutation of the [s; t; u] vector.
+ * @param permutation the permutation factor.
+ * @param s x coordinate of the given vector.
+ * @param t y coordinate of the given vector.
+ * @param u z coordinate of the given vector.
+ * @return a permutation of the [s; t; u] vector.
+ */
+ private static float[] getVectorPermutation(int permutation, float s, float t, float u) {
+ switch (permutation % 3) {
+ case 0:
+ return new float[] {s, t, u, 1};
+ case 1:
+ return new float[] {u, s, t, 1};
+ case 2:
+ return new float[] {t, u, s, 1};
+ default:
+ return null;
+ }
+ }
+}
diff --git a/modules/scirenderer/src/org/scilab/forge/scirenderer/utils/shapes/geometry/SphereFactory.java b/modules/scirenderer/src/org/scilab/forge/scirenderer/utils/shapes/geometry/SphereFactory.java
new file mode 100755
index 000000000..55cd25544
--- /dev/null
+++ b/modules/scirenderer/src/org/scilab/forge/scirenderer/utils/shapes/geometry/SphereFactory.java
@@ -0,0 +1,146 @@
+/*
+ * Scilab ( http://www.scilab.org/ ) - This file is part of Scilab
+ * Copyright (C) 2011-2011 - DIGITEO - Pierre Lando
+ *
+ * This file must be used under the terms of the CeCILL.
+ * This source file is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at
+ * http://www.cecill.info/licences/Licence_CeCILL_V2.1-en.txt
+ */
+
+package org.scilab.forge.scirenderer.utils.shapes.geometry;
+
+import org.scilab.forge.scirenderer.Canvas;
+import org.scilab.forge.scirenderer.buffers.ElementsBuffer;
+import org.scilab.forge.scirenderer.buffers.IndicesBuffer;
+import org.scilab.forge.scirenderer.shapes.geometry.DefaultGeometry;
+import org.scilab.forge.scirenderer.shapes.geometry.Geometry;
+
+import java.nio.FloatBuffer;
+import java.nio.IntBuffer;
+
+/**
+ * @author Pierre Lando
+ */
+public final class SphereFactory {
+ private static SphereFactory singleton;
+
+ private SphereFactory() {
+ }
+
+ public static SphereFactory getSingleton() {
+ if (singleton == null) {
+ singleton = new SphereFactory();
+ }
+ return singleton;
+ }
+
+ /**
+ * Create a sphere geometry with classic longitude / latitude division.
+ * @param canvas the canvas where the geometry will be created.
+ * @param radius the sphere radius.
+ * @param givenLatitude number of division in latitude.
+ * @param givenLongitude number of division in longitude.
+ * @return a sphere geometry with classic longitude / latitude division.
+ */
+ public Geometry create(Canvas canvas, Float radius, int givenLatitude, int givenLongitude) {
+ int latitude;
+ int longitude;
+ if (givenLatitude < 3) {
+ latitude = 3;
+ } else {
+ latitude = givenLatitude;
+ }
+
+ if (givenLongitude < 4) {
+ longitude = 4;
+ } else {
+ longitude = givenLongitude;
+ }
+
+ ElementsBuffer vertexBuffer = canvas.getBuffersManager().createElementsBuffer();
+ vertexBuffer.setData(createVertexData(radius, latitude, longitude), 4);
+
+ IndicesBuffer indicesBuffer = canvas.getBuffersManager().createIndicesBuffer();
+ indicesBuffer.setData(createIndicesData(latitude, longitude));
+
+ DefaultGeometry geometry = new DefaultGeometry();
+ geometry.setFillDrawingMode(Geometry.FillDrawingMode.TRIANGLES);
+ geometry.setVertices(vertexBuffer);
+ geometry.setIndices(indicesBuffer);
+
+ return geometry;
+ }
+
+ private IntBuffer createIndicesData(int latitudeResolution, int longitudeResolution) {
+ int indexNumber = 6 * (latitudeResolution - 3) * longitudeResolution + 6 * longitudeResolution;
+ IntBuffer indexBuffer = IntBuffer.allocate(indexNumber);
+ indexBuffer.rewind();
+
+ for (int i = 0; i < longitudeResolution; i++) {
+ indexBuffer.put(0);
+ indexBuffer.put(1 + i);
+ indexBuffer.put(1 + (i + 1) % longitudeResolution);
+ }
+
+ for (int latitude = 1; latitude < latitudeResolution - 2; latitude++) {
+ for (int longitude = 0; longitude < longitudeResolution; longitude++) {
+ int aIndex = 1 + longitude + (latitude - 1) * longitudeResolution;
+ int bIndex = 1 + ((longitude + 1) % longitudeResolution) + (latitude - 1) * longitudeResolution;
+ int cIndex = 1 + ((longitude + 1) % longitudeResolution) + latitude * longitudeResolution;
+ int dIndex = 1 + longitude + latitude * longitudeResolution;
+
+ indexBuffer.put(aIndex);
+ indexBuffer.put(bIndex);
+ indexBuffer.put(cIndex);
+
+ indexBuffer.put(aIndex);
+ indexBuffer.put(cIndex);
+ indexBuffer.put(dIndex);
+ }
+ }
+
+
+ int lastVertexIndex = (latitudeResolution - 2) * longitudeResolution + 2 - 1;
+ for (int i = 0; i < longitudeResolution; i++) {
+ indexBuffer.put(lastVertexIndex);
+ indexBuffer.put(lastVertexIndex - longitudeResolution + i);
+ indexBuffer.put(lastVertexIndex - longitudeResolution + (i + 1) % longitudeResolution);
+ }
+
+ indexBuffer.rewind();
+ return indexBuffer;
+ }
+
+ private FloatBuffer createVertexData(Float radius, int latitudeResolution, int longitudeResolution) {
+ int vertexNumber = (latitudeResolution - 2) * longitudeResolution + 2;
+ FloatBuffer dataBuffer = FloatBuffer.allocate(vertexNumber * 4);
+ dataBuffer.rewind();
+
+ dataBuffer.put(new float[] {0, 0, radius, 1});
+
+ for (int latitude = 1; latitude < latitudeResolution - 1; latitude++) {
+ double latitudeAngle = latitude * Math.PI / (latitudeResolution - 1);
+
+ float z = (float) (radius * Math.cos(latitudeAngle));
+ float discRadius = (float) (radius * Math.sin(latitudeAngle));
+
+ for (int longitude = 0; longitude < longitudeResolution; longitude++) {
+ double longitudeAngle = longitude * 2 * Math.PI / longitudeResolution;
+ float x = (float) (discRadius * Math.cos(longitudeAngle));
+ float y = (float) (discRadius * Math.sin(longitudeAngle));
+
+ dataBuffer.put(x);
+ dataBuffer.put(y);
+ dataBuffer.put(z);
+ dataBuffer.put(1);
+ }
+ }
+
+ dataBuffer.put(new float[] {0, 0, -radius, 1});
+
+ dataBuffer.rewind();
+ return dataBuffer;
+ }
+}
diff --git a/modules/scirenderer/src/org/scilab/forge/scirenderer/utils/shapes/geometry/TetrahedronFactory.java b/modules/scirenderer/src/org/scilab/forge/scirenderer/utils/shapes/geometry/TetrahedronFactory.java
new file mode 100755
index 000000000..83e44c50b
--- /dev/null
+++ b/modules/scirenderer/src/org/scilab/forge/scirenderer/utils/shapes/geometry/TetrahedronFactory.java
@@ -0,0 +1,138 @@
+/*
+ * Scilab ( http://www.scilab.org/ ) - This file is part of Scilab
+ * Copyright (C) 2009-2011 - DIGITEO - Pierre Lando
+ *
+ * This file must be used under the terms of the CeCILL.
+ * This source file is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at
+ * http://www.cecill.info/licences/Licence_CeCILL_V2.1-en.txt
+ */
+
+package org.scilab.forge.scirenderer.utils.shapes.geometry;
+
+import org.scilab.forge.scirenderer.Canvas;
+import org.scilab.forge.scirenderer.buffers.ElementsBuffer;
+import org.scilab.forge.scirenderer.buffers.IndicesBuffer;
+import org.scilab.forge.scirenderer.shapes.geometry.DefaultGeometry;
+import org.scilab.forge.scirenderer.shapes.geometry.Geometry;
+import org.scilab.forge.scirenderer.tranformations.Vector3d;
+
+import java.nio.FloatBuffer;
+import java.nio.IntBuffer;
+
+/**
+ * An utility class to create a tetrahedron.
+ * @author Pierre Lando
+ */
+public final class TetrahedronFactory {
+ private static final int ELEMENTS_SIZE = 4;
+
+ private static final Vector3d A = new Vector3d(+1, +1, +1); // Point #0
+ private static final Vector3d B = new Vector3d(+1, -1, -1); // Point #1
+ private static final Vector3d C = new Vector3d(-1, +1, -1); // Point #2
+ private static final Vector3d D = new Vector3d(-1, -1, +1); // Point #3
+
+ /**
+ * Private constructor.
+ * This is an utility class.
+ */
+ private TetrahedronFactory() {
+ }
+
+ /**
+ * @param canvas the canvas where the buffers are created.
+ * @return a Tetrahedron geometry.
+ */
+ public static DefaultGeometry createTetrahedron(Canvas canvas) {
+ Vector3d mab = A.plus(B).times(.5); // Point #4
+ Vector3d mac = A.plus(C).times(.5); // Point #5
+ Vector3d mad = A.plus(D).times(.5); // Point #6
+
+ Vector3d mbc = B.plus(C).times(.5); // Point #7
+ Vector3d mbd = B.plus(D).times(.5); // Point #8
+
+ Vector3d mcd = C.plus(D).times(.5); // Point #9
+
+ // Create vertices buffer.
+ FloatBuffer vertices = FloatBuffer.allocate(10 * ELEMENTS_SIZE);
+ vertices.rewind();
+ vertices.put(A.getDataAsFloatArray(ELEMENTS_SIZE));
+ vertices.put(B.getDataAsFloatArray(ELEMENTS_SIZE));
+ vertices.put(C.getDataAsFloatArray(ELEMENTS_SIZE));
+ vertices.put(D.getDataAsFloatArray(ELEMENTS_SIZE));
+
+ vertices.put(mab.getDataAsFloatArray(ELEMENTS_SIZE));
+ vertices.put(mac.getDataAsFloatArray(ELEMENTS_SIZE));
+ vertices.put(mad.getDataAsFloatArray(ELEMENTS_SIZE));
+
+ vertices.put(mbc.getDataAsFloatArray(ELEMENTS_SIZE));
+ vertices.put(mbd.getDataAsFloatArray(ELEMENTS_SIZE));
+
+ vertices.put(mcd.getDataAsFloatArray(ELEMENTS_SIZE));
+ vertices.rewind();
+
+ // 4 triangles per faces.
+ // 4 faces.
+ // 3 indices by triangles.
+ IntBuffer indices = IntBuffer.allocate(48);
+ indices.rewind();
+ indices.put(new int[] {
+ 0, 4, 5,
+ 4, 1, 7,
+ 5, 7, 2,
+ 7, 5, 4,
+
+ 0, 5, 6,
+ 5, 2, 9,
+ 6, 9, 3,
+ 9, 6, 5,
+
+ 0, 6, 4,
+ 6, 3, 8,
+ 4, 8, 1,
+ 8, 4, 6,
+
+ 8, 9, 7,
+ 9, 8, 3,
+ 7, 1, 8,
+ 2, 7, 9
+ });
+ indices.rewind();
+
+ IntBuffer edgesIndices = IntBuffer.allocate(48);
+ edgesIndices.rewind();
+ edgesIndices.put(new int[] {
+ 0, 4, 4, 1,
+ 0, 5, 5, 2,
+ 0, 6, 6, 3,
+ 4, 5, 5, 6, 6, 4,
+ 1, 7, 7, 2,
+ 2, 9, 9, 3,
+ 3, 8, 8, 1,
+ 4, 7, 7, 5, 5, 9, 9, 6, 6, 8, 8, 4,
+ 7, 9, 9, 8, 8, 7
+ });
+
+ edgesIndices.rewind();
+
+ canvas.getBuffersManager().createElementsBuffer();
+ ElementsBuffer vertexBuffer = canvas.getBuffersManager().createElementsBuffer();
+ IndicesBuffer indicesBuffer = canvas.getBuffersManager().createIndicesBuffer();
+ IndicesBuffer edgesIndicesBuffer = canvas.getBuffersManager().createIndicesBuffer();
+
+ vertexBuffer.setData(vertices, ELEMENTS_SIZE);
+ indicesBuffer.setData(indices);
+ edgesIndicesBuffer.setData(edgesIndices);
+
+ DefaultGeometry geometry = new DefaultGeometry();
+ geometry.setFillDrawingMode(Geometry.FillDrawingMode.TRIANGLES);
+ geometry.setLineDrawingMode(Geometry.LineDrawingMode.SEGMENTS);
+ geometry.setPolygonOffsetMode(true);
+ geometry.setWireIndices(edgesIndicesBuffer);
+ geometry.setIndices(indicesBuffer);
+ geometry.setVertices(vertexBuffer);
+
+ return geometry;
+ }
+}