83807213b0085633c9c89470fd129fe41545d3e6
[scilab.git] / scilab / modules / renderer / src / java / org / scilab / modules / renderer / JoGLView / DrawerVisitor.java
1 /*
2  * Scilab ( http://www.scilab.org/ ) - This file is part of Scilab
3  * Copyright (C) 2010 - DIGITEO - Pierre Lando
4  *
5  * Copyright (C) 2012 - 2016 - Scilab Enterprises
6  *
7  * This file is hereby licensed under the terms of the GNU GPL v2.0,
8  * pursuant to article 5.3.4 of the CeCILL v.2.1.
9  * This file was originally licensed under the terms of the CeCILL v2.1,
10  * and continues to be available under such terms.
11  * For more information, see the COPYING file which you should have received
12  * along with this program.
13  */
14
15 package org.scilab.modules.renderer.JoGLView;
16
17 import java.awt.Component;
18 import java.awt.Dimension;
19 import java.nio.ByteBuffer;
20 import java.nio.FloatBuffer;
21 import java.util.ArrayList;
22 import java.util.Arrays;
23 import java.util.HashMap;
24 import java.util.HashSet;
25 import java.util.LinkedList;
26 import java.util.List;
27 import java.util.Map;
28 import java.util.Set;
29
30 import javax.swing.SwingUtilities;
31
32 import org.scilab.forge.scirenderer.Canvas;
33 import org.scilab.forge.scirenderer.Drawer;
34 import org.scilab.forge.scirenderer.DrawingTools;
35 import org.scilab.forge.scirenderer.implementation.jogl.JoGLDrawingTools;
36 import org.scilab.forge.scirenderer.SciRendererException;
37 import org.scilab.forge.scirenderer.buffers.ElementsBuffer;
38 import org.scilab.forge.scirenderer.buffers.BuffersManager;
39 import org.scilab.forge.scirenderer.shapes.appearance.Appearance;
40 import org.scilab.forge.scirenderer.shapes.appearance.Color;
41 import org.scilab.forge.scirenderer.shapes.geometry.DefaultGeometry;
42 import org.scilab.forge.scirenderer.shapes.geometry.Geometry;
43 import org.scilab.forge.scirenderer.texture.AbstractTextureDataProvider;
44 import org.scilab.forge.scirenderer.texture.AnchorPosition;
45 import org.scilab.forge.scirenderer.texture.Texture;
46 import org.scilab.forge.scirenderer.tranformations.Transformation;
47 import org.scilab.forge.scirenderer.tranformations.TransformationFactory;
48 import org.scilab.forge.scirenderer.tranformations.TransformationStack;
49 import org.scilab.forge.scirenderer.tranformations.Vector3d;
50 import org.scilab.forge.scirenderer.utils.shapes.geometry.CubeFactory;
51 import org.scilab.modules.graphic_objects.ObjectRemovedException;
52 import org.scilab.modules.graphic_objects.arc.Arc;
53 import org.scilab.modules.graphic_objects.axes.Axes;
54 import org.scilab.modules.graphic_objects.axes.AxesContainer;
55 import org.scilab.modules.graphic_objects.axes.Camera.ViewType;
56 import org.scilab.modules.graphic_objects.axis.Axis;
57 import org.scilab.modules.graphic_objects.compound.Compound;
58 import org.scilab.modules.graphic_objects.datatip.Datatip;
59 import org.scilab.modules.graphic_objects.fec.Fec;
60 import org.scilab.modules.graphic_objects.figure.ColorMap;
61 import org.scilab.modules.graphic_objects.figure.Figure;
62 import org.scilab.modules.graphic_objects.graphicController.GraphicController;
63 import org.scilab.modules.graphic_objects.graphicObject.GraphicObject;
64 import org.scilab.modules.graphic_objects.graphicObject.GraphicObjectProperties;
65 import org.scilab.modules.graphic_objects.graphicObject.Visitor;
66 import org.scilab.modules.graphic_objects.graphicView.GraphicView;
67 import org.scilab.modules.graphic_objects.imageplot.Grayplot;
68 import org.scilab.modules.graphic_objects.imageplot.Matplot;
69 import org.scilab.modules.graphic_objects.label.Label;
70 import org.scilab.modules.graphic_objects.legend.Legend;
71 import org.scilab.modules.graphic_objects.polyline.Polyline;
72 import org.scilab.modules.graphic_objects.rectangle.Rectangle;
73 import org.scilab.modules.graphic_objects.surface.Fac3d;
74 import org.scilab.modules.graphic_objects.surface.Plot3d;
75 import org.scilab.modules.graphic_objects.textObject.Text;
76 import org.scilab.modules.graphic_objects.uicontrol.frame.Frame;
77 import org.scilab.modules.graphic_objects.vectfield.Arrow;
78 import org.scilab.modules.graphic_objects.vectfield.Champ;
79 import org.scilab.modules.graphic_objects.vectfield.Segs;
80 import org.scilab.modules.renderer.JoGLView.arrowDrawing.ArrowDrawer;
81 import org.scilab.modules.renderer.JoGLView.axes.AxesDrawer;
82 import org.scilab.modules.renderer.JoGLView.contouredObject.ContouredObjectDrawer;
83 import org.scilab.modules.renderer.JoGLView.datatip.DatatipTextDrawer;
84 import org.scilab.modules.renderer.JoGLView.interaction.InteractionManager;
85 import org.scilab.modules.renderer.JoGLView.label.LabelManager;
86 import org.scilab.modules.renderer.JoGLView.legend.LegendDrawer;
87 import org.scilab.modules.renderer.JoGLView.mark.MarkSpriteManager;
88 import org.scilab.modules.renderer.JoGLView.postRendering.PostRendered;
89 import org.scilab.modules.renderer.JoGLView.text.TextManager;
90 import org.scilab.modules.renderer.JoGLView.util.ColorFactory;
91 import org.scilab.modules.renderer.JoGLView.util.LightingUtils;
92 import org.scilab.modules.renderer.JoGLView.util.OutOfMemoryException;
93 import org.scilab.modules.renderer.JoGLView.util.PixelDrawingModeUtils;
94
95 /**
96  * @author Pierre Lando
97  */
98 public class DrawerVisitor implements Visitor, Drawer, GraphicView {
99
100     /** Set of properties changed during a draw if auto-ticks is on for X axis. */
101     private static final Set<Integer> X_AXIS_TICKS_PROPERTIES = new HashSet<Integer>(Arrays.asList(
102                 GraphicObjectProperties.__GO_X_AXIS_TICKS_LOCATIONS__,
103                 GraphicObjectProperties.__GO_X_AXIS_TICKS_LABELS__
104             ));
105
106     /** Set of properties changed during a draw if auto-ticks is on for Y axis. */
107     private static final Set<Integer> Y_AXIS_TICKS_PROPERTIES = new HashSet<Integer>(Arrays.asList(
108                 GraphicObjectProperties.__GO_Y_AXIS_TICKS_LOCATIONS__,
109                 GraphicObjectProperties.__GO_Y_AXIS_TICKS_LABELS__
110             ));
111
112     /** Set of properties changed during a draw if auto-ticks is on for Z axis. */
113     private static final Set<Integer> Z_AXIS_TICKS_PROPERTIES = new HashSet<Integer>(Arrays.asList(
114                 GraphicObjectProperties.__GO_Z_AXIS_TICKS_LOCATIONS__,
115                 GraphicObjectProperties.__GO_Z_AXIS_TICKS_LABELS__
116             ));
117
118     /** Set of figure properties for witch a change doesn't lead to a redraw */
119     private static final Set<Integer> SILENT_FIGURE_PROPERTIES = new HashSet<Integer>(Arrays.asList(
120                 GraphicObjectProperties.__GO_ROTATION_TYPE__,
121                 GraphicObjectProperties.__GO_INFO_MESSAGE__,
122                 GraphicObjectProperties.__GO_FIGURE_NAME__,
123                 GraphicObjectProperties.__GO_AUTORESIZE__,
124                 GraphicObjectProperties.__GO_POSITION__,
125                 GraphicObjectProperties.__GO_SIZE__,
126                 GraphicObjectProperties.__GO_ID__
127             ));
128
129     private static final boolean DEBUG_MODE = false;
130
131     private final Component component;
132     private final AxesContainer figure;
133     private final InteractionManager interactionManager;
134
135     private final ColorMapTextureDataProvider colorMapTextureDataProvider;
136
137     private final ScilabTextureManager textureManager;
138     private final MarkSpriteManager markManager;
139     private final LabelManager labelManager;
140     private final DataManager dataManager;
141     private final TextManager textManager;
142
143     private final ContouredObjectDrawer contouredObjectDrawer;
144     private final LegendDrawer legendDrawer;
145     protected final AxesDrawer axesDrawer;
146     private final AxisDrawer axisDrawer;
147     private final ArrowDrawer arrowDrawer;
148     private final FecDrawer fecDrawer;
149     private final DatatipTextDrawer datatipTextDrawer;
150
151     private DrawingTools drawingTools;
152     private Texture colorMapTexture;
153     private ColorMap colorMap;
154
155     private Axes currentAxes;
156     private Canvas canvas;
157
158     /**
159      * The map between the existing Figures' identifiers and their corresponding Visitor.
160      * Used to get access to the DrawerVisitor corresponding to a given Figure when the
161      * renderer module is accessed from another thread than the AWT's.
162      */
163     private final static Map<Integer, DrawerVisitor> visitorMap = new HashMap<Integer, DrawerVisitor>();
164     private final List<PostRendered> postRenderedList = new LinkedList<PostRendered>();
165     private final static Map<Integer, List<Integer>> openGLChildren = new HashMap<Integer, List<Integer>>();
166
167     public static int[] getSize() {
168         return new int[] {visitorMap.size(), openGLChildren.size()};
169     }
170
171     public DrawerVisitor(Component component, Canvas canvas, AxesContainer figure) {
172         GraphicController.getController().register(this);
173
174         this.component = component;
175         this.canvas = canvas;
176         this.figure = figure;
177
178         this.interactionManager = new InteractionManager(this);
179         this.dataManager = new DataManager(canvas);
180         this.textureManager = new ScilabTextureManager(this);
181         this.markManager = new MarkSpriteManager(canvas.getTextureManager());
182         this.textManager = new TextManager(canvas.getTextureManager());
183         this.labelManager = new LabelManager(canvas.getTextureManager());
184         this.axesDrawer = new AxesDrawer(this);
185         this.axisDrawer = new AxisDrawer(this);
186         this.arrowDrawer = new ArrowDrawer(this);
187         this.contouredObjectDrawer = new ContouredObjectDrawer(this, this.dataManager, this.markManager);
188         this.legendDrawer = new LegendDrawer(this);
189         this.fecDrawer = new FecDrawer(this);
190         this.colorMapTextureDataProvider = new ColorMapTextureDataProvider();
191         this.datatipTextDrawer = new DatatipTextDrawer(canvas);
192
193         visitorMap.put(figure.getIdentifier(), this);
194     }
195
196     public static void changeVisitor(AxesContainer figure, DrawerVisitor visitor) {
197         if (visitor == null) {
198             visitorMap.remove(figure.getIdentifier());
199         } else {
200             visitorMap.put(figure.getIdentifier(), visitor);
201         }
202     }
203
204     public void setDrawingTools(DrawingTools drawingTools) {
205         this.drawingTools = drawingTools;
206     }
207
208     public DrawingTools getDrawingTools() {
209         return drawingTools;
210     }
211
212     public Canvas getCanvas() {
213         return canvas;
214     }
215
216     public void setCanvas(Canvas canvas) {
217         this.canvas = canvas;
218     }
219
220     /**
221      * @return the DataManager
222      */
223     public DataManager getDataManager() {
224         return dataManager;
225     }
226
227     /**
228      * @return the TextManager
229      */
230     public TextManager getTextManager() {
231         return textManager;
232     }
233
234     /**
235      * @return the LegendDrawer
236      */
237     public LegendDrawer getLegendDrawer() {
238         return legendDrawer;
239     }
240
241     /**
242      * Mark manager getter.
243      * @return the mark manager.
244      */
245     public MarkSpriteManager getMarkManager() {
246         return markManager;
247     }
248
249     /**
250      * @return the AxesDrawer
251      */
252     public AxesDrawer getAxesDrawer() {
253         return axesDrawer;
254     }
255
256     /**
257      * @return the ArrowDrawer
258      */
259     public ArrowDrawer getArrowDrawer() {
260         return arrowDrawer;
261     }
262
263     public ColorMap getColorMap() {
264         return colorMap;
265     }
266
267     public DatatipTextDrawer getDatatipTextDrawer() {
268         return datatipTextDrawer;
269     }
270
271     /**
272      * Returns the visitor corresponding to the Figure identifier.
273      * @param figureId the figure identifier.
274      * @return the visitor.
275      */
276     public static DrawerVisitor getVisitor(Integer figureId) {
277         return visitorMap.get(figureId);
278     }
279
280     public void addPostRendering(PostRendered postRendered) {
281         if (postRendered != null) {
282             postRenderedList.add(postRendered);
283         }
284     }
285
286     public void removePostRendering(PostRendered postRendered) {
287         postRenderedList.remove(postRendered);
288     }
289
290     @Override
291     public void draw(DrawingTools drawingTools) {
292         this.drawingTools = drawingTools;
293         if (figure instanceof Figure) {
294             visit((Figure) figure);
295         } else {
296             visit((Frame) figure);
297         }
298
299         for (PostRendered postRendered : postRenderedList) {
300             try {
301                 postRendered.draw(drawingTools);
302             } catch (SciRendererException e) {
303                 System.err.println("A 'PostRendered' is not drawable because: '" + e.getMessage() + "'");
304             }
305         }
306         drawingTools.getTransformationManager().useSceneCoordinate();
307     }
308
309     /**
310      * Ask the given object to accept visitor.
311      * @param childrenId array of object identifier.
312      */
313     public void askAcceptVisitor(Integer[] childrenId) {
314         if (childrenId != null) {
315
316             for (int i = childrenId.length - 1; i >= 0; --i) {
317                 GraphicObject child = GraphicController.getController().getObjectFromId(childrenId[i]);
318                 if (child != null) {
319                     try {
320                         child.accept(this);
321                     } catch (ObjectRemovedException e) {
322                         if (DEBUG_MODE) {
323                             System.err.println("[DEBUG] Try to draw an already removed object");
324                             System.err.println("[DEBUG] " + e);
325                             System.err.println("[DEBUG] Skipped...");
326                         }
327                     }
328                 }
329             }
330         }
331     }
332
333     /**
334      * @return true if it is a 2D view
335      */
336     public boolean is2DView() {
337         return currentAxes.getViewAsEnum() == ViewType.VIEW_2D;
338     }
339
340     @Override
341     public void visit(Axes axes) {
342         synchronized (axes) {
343             if (axes.isValid() && axes.getVisible()) {
344                 try {
345                     currentAxes = axes;
346                     axesDrawer.computeRulers(axes);
347                     axesDrawer.draw(axes);
348                 } catch (SciRendererException e) {
349                     invalidate(axes, e);
350                 }
351             }
352         }
353     }
354
355     @Override
356     public void visit(Arc arc) {
357         if (arc.isValid() && arc.getVisible()) {
358             axesDrawer.enableClipping(currentAxes, arc.getClipProperty());
359             try {
360                 contouredObjectDrawer.draw(arc, currentAxes.getViewAsEnum() == ViewType.VIEW_2D);
361             } catch (OutOfMemoryException e) {
362                 invalidate(arc, e);
363             } catch (SciRendererException e) {
364                 invalidate(arc, e);
365             } catch (ObjectRemovedException e) {
366                 invalidate(arc, e);
367             }
368             axesDrawer.disableClipping(arc.getClipProperty());
369         }
370     }
371
372     @Override
373     public void visit(Axis axis) {
374         if (axis.getVisible()) {
375             axesDrawer.enableClipping(currentAxes, axis.getClipProperty());
376             axisDrawer.draw(currentAxes, axis);
377             axesDrawer.disableClipping(axis.getClipProperty());
378         }
379     }
380
381     @Override
382     public void visit(Compound compound) {
383         if (compound.getVisible()) {
384             askAcceptVisitor(compound.getChildren());
385         }
386     }
387
388     @Override
389     public void visit(Fec fec) throws ObjectRemovedException {
390         if (fec.isValid() && fec.getVisible()) {
391             axesDrawer.enableClipping(currentAxes, fec.getClipProperty());
392             try {
393                 fecDrawer.draw(fec);
394             } catch (OutOfMemoryException e) {
395                 invalidate(fec, e);
396             }
397             axesDrawer.disableClipping(fec.getClipProperty());
398         }
399     }
400
401     @Override
402     public void visit(Figure figure) {
403         synchronized (figure) {
404             /** Set the current {@see ColorMap}. */
405             try {
406                 Dimension dims = getCanvas().getDimension();
407                 colorMap = figure.getColorMap();
408                 drawingTools.clear(ColorFactory.createColor(colorMap, figure.getBackground()));
409                 drawingTools.clearDepthBuffer();
410                 if (drawingTools instanceof JoGLDrawingTools) {
411                     ((JoGLDrawingTools)drawingTools).setPixelDrawingMode(PixelDrawingModeUtils.figureToJoGLmode(figure.getPixelDrawingModeAsEnum()));
412                 }
413                 if (figure.isValid() && figure.getVisible() && figure.getImmediateDrawing() && dims.width > 1 && dims.height > 1) {
414                     askAcceptVisitor(figure.getChildren());
415                 }
416             } catch (Exception e) {
417                 System.err.println(e);
418             }
419         }
420     }
421
422     public void visit(Frame frame) {
423         synchronized (frame) {
424             /** Set the current {@see ColorMap}. */
425             try {
426                 colorMap = frame.getColorMap();
427                 drawingTools.clear(ColorFactory.createColor(colorMap, frame.getBackground()));
428                 drawingTools.clearDepthBuffer();
429                 if (frame.isValid() && frame.getVisible()) {
430                     DrawerVisitor visitor = visitorMap.get(frame.getIdentifier());
431                     if (visitor != null) {
432                         Dimension dims = visitor.getCanvas().getDimension();
433                         visitor.setDrawingTools(drawingTools);
434                         if (dims.width > 1 && dims.height > 1) {
435                             visitor.askAcceptVisitor(frame.getChildren());
436                         }
437                     }
438                 }
439             } catch (Exception e) {
440                 System.err.println(e);
441             }
442         }
443     }
444
445     @Override
446     public void visit(final Grayplot grayplot) {
447         if (grayplot.isValid() && grayplot.getVisible()) {
448             axesDrawer.enableClipping(currentAxes, grayplot.getClipProperty());
449             try {
450                 DefaultGeometry triangles = new DefaultGeometry();
451                 triangles.setFillDrawingMode(Geometry.FillDrawingMode.TRIANGLES);
452                 triangles.setVertices(dataManager.getVertexBuffer(grayplot.getIdentifier()));
453                 triangles.setColors(dataManager.getColorBuffer(grayplot.getIdentifier()));
454                 triangles.setIndices(dataManager.getIndexBuffer(grayplot.getIdentifier()));
455                 triangles.setFaceCullingMode(Geometry.FaceCullingMode.BOTH);
456                 Appearance trianglesAppearance = new Appearance();
457                 drawingTools.draw(triangles, trianglesAppearance);
458                 /*} catch (ObjectRemovedException e) {
459                   invalidate(grayplot, e);
460                   } catch (SciRendererException e) {
461                   invalidate(grayplot, e);
462                   } catch (OutOfMemoryException e) {
463                   invalidate(grayplot, e);
464                   }*/
465             } catch (Exception e) {
466                 System.err.println(e);
467                 e.printStackTrace();
468             }
469             axesDrawer.disableClipping(grayplot.getClipProperty());
470         }
471     }
472
473     @Override
474     public void visit(final Matplot matplot) {
475         if (matplot.isValid() && matplot.getVisible()) {
476             axesDrawer.enableClipping(currentAxes, matplot.getClipProperty());
477             try {
478                 if ((currentAxes != null) && (currentAxes.getXAxisLogFlag() || currentAxes.getYAxisLogFlag())) {
479                     DefaultGeometry geometry = new DefaultGeometry();
480                     geometry.setFillDrawingMode(Geometry.FillDrawingMode.TRIANGLES);
481                     geometry.setVertices(dataManager.getVertexBuffer(matplot.getIdentifier()));
482                     geometry.setColors(dataManager.getColorBuffer(matplot.getIdentifier()));
483                     geometry.setIndices(dataManager.getIndexBuffer(matplot.getIdentifier()));
484                     geometry.setFaceCullingMode(Geometry.FaceCullingMode.BOTH);
485                     Appearance appearance = new Appearance();
486                     drawingTools.draw(geometry, appearance);
487                 } else {
488                     TransformationStack modelViewStack = drawingTools.getTransformationManager().getModelViewStack();
489                     double[][] factors = currentAxes.getScaleTranslateFactors();
490                     Double[] scale = matplot.getScale();
491                     Double[] translate = matplot.getTranslate();
492
493                     scale[0] *= factors[0][0];
494                     scale[1] *= factors[0][1];
495
496                     translate[0] = translate[0] * factors[0][0] + factors[1][0];
497                     translate[1] = translate[1] * factors[0][1] + factors[1][1];
498
499                     Transformation t = TransformationFactory.getTranslateTransformation(translate[0], translate[1], 0);
500                     Transformation t2 = TransformationFactory.getScaleTransformation(scale[0], scale[1], 1);
501                     modelViewStack.pushRightMultiply(t);
502                     modelViewStack.pushRightMultiply(t2);
503                     drawingTools.draw(textureManager.getTexture(matplot.getIdentifier()));
504                     modelViewStack.pop();
505                     modelViewStack.pop();
506                 }
507             } catch (ObjectRemovedException e) {
508                 invalidate(matplot, e);
509             } catch (SciRendererException e) {
510                 invalidate(matplot, e);
511             } catch (OutOfMemoryException e) {
512                 invalidate(matplot, e);
513             }
514             axesDrawer.disableClipping(matplot.getClipProperty());
515         }
516     }
517
518     @Override
519     public void visit(Label label) {
520         if (label.isValid() && label.getVisible() && !label.isEmpty()) {
521             try {
522                 labelManager.draw(drawingTools, colorMap, label, axesDrawer);
523             } catch (SciRendererException e) {
524                 invalidate(label, e);
525             }
526         }
527     }
528
529     @Override
530     public void visit(Legend legend) {
531         if (legend.isValid() && legend.getVisible()) {
532             try {
533                 legendDrawer.draw(legend);
534             } catch (SciRendererException e) {
535                 invalidate(legend, e);
536             }
537         }
538     }
539
540     @Override
541     public void visit(final Polyline polyline) {
542         synchronized (polyline) {
543             if (polyline.isValid() && polyline.getVisible()) {
544                 axesDrawer.enableClipping(currentAxes, polyline.getClipProperty());
545                 try {
546                     DefaultGeometry geometry = new DefaultGeometry();
547
548                     geometry.setVertices(dataManager.getVertexBuffer(polyline.getIdentifier()));
549                     geometry.setIndices(dataManager.getIndexBuffer(polyline.getIdentifier()));
550                     geometry.setWireIndices(dataManager.getWireIndexBuffer(polyline.getIdentifier()));
551
552                     final int style = polyline.getPolylineStyle();
553                     if (style == 1 || style == 2 || style == 4 || style == 5) {
554                         geometry.setLineDrawingMode(Geometry.LineDrawingMode.SEGMENTS_STRIP);
555                     } else {
556                         geometry.setLineDrawingMode(Geometry.LineDrawingMode.SEGMENTS);
557                     }
558
559                     geometry.setFillDrawingMode(Geometry.FillDrawingMode.TRIANGLES);
560                     geometry.setFaceCullingMode(Geometry.FaceCullingMode.BOTH);
561
562                     geometry.setPolygonOffsetMode(currentAxes.getCamera().getView() == ViewType.VIEW_3D);
563
564                     /* Interpolated color rendering is used only for basic polylines for now. */
565                     Appearance appearance = new Appearance();
566
567                     if (polyline.getInterpColorMode() && style == 1) {
568                         geometry.setTextureCoordinates(dataManager.getTextureCoordinatesBuffer(polyline.getIdentifier()));
569                         appearance.setTexture(getColorMapTexture());
570                     } else {
571                         if (polyline.getColorSet()) {
572                             ElementsBuffer colors = dataManager.getColorBuffer(polyline.getIdentifier());
573                             geometry.setColors(colors);
574                             appearance.setLineColor(null);
575                         } else {
576                             geometry.setColors(null);
577                             appearance.setLineColor(ColorFactory.createColor(colorMap, polyline.getLineColor()));
578                         }
579                     }
580
581                     Integer lineColor = polyline.getSelected() ? polyline.getSelectedColor() : polyline.getLineColor();
582                     appearance.setLineColor(ColorFactory.createColor(colorMap, lineColor));
583                     appearance.setLineWidth(polyline.getLineThickness().floatValue());
584                     appearance.setLinePattern(polyline.getLineStyleAsEnum().asPattern());
585
586                     if (!polyline.getInterpColorMode() || style != 1) {
587                         int fillColor;
588
589                         /*
590                          * The line color is used as fill color for the filled patch polyline style
591                          * whereas the background color is used for all the other styles.
592                          */
593                         if (style == 5) {
594                             fillColor = lineColor;
595                         } else {
596                             fillColor = polyline.getBackground();
597                         }
598
599                         appearance.setFillColor(ColorFactory.createColor(colorMap, fillColor));
600                     }
601
602                     drawingTools.draw(geometry, appearance);
603
604                     if (style == 4) {
605                         arrowDrawer.drawArrows(polyline.getParentAxes(), polyline.getIdentifier(), polyline.getArrowSizeFactor(),
606                                                polyline.getLineThickness(), false, false, lineColor, true);
607                     }
608
609                     if (polyline.getMarkMode()) {
610                         ElementsBuffer positions = dataManager.getVertexBuffer(polyline.getIdentifier());
611                         int offset = polyline.getMarkOffset();
612                         int stride = polyline.getMarkStride();
613                         if (polyline.getColorSet() && (polyline.getNumMarkForegrounds() > 0) || (polyline.getNumMarkBackgrounds() > 0)) {
614                             ElementsBuffer colors = dataManager.getColorBuffer(polyline.getIdentifier());
615                             Color auxColor;
616                             if (polyline.getNumMarkBackgrounds() > 0) {
617                                 auxColor = ColorFactory.createColor(colorMap, polyline.getMark().getForeground());
618                             } else {
619                                 auxColor = ColorFactory.createColor(colorMap, polyline.getMark().getBackground());
620                             }
621                             FloatBuffer data = positions.getData();
622                             FloatBuffer colorData = colors.getData();
623                             Integer[] sizes = polyline.getMarkSizes();
624                             if ( (sizes.length > 0) && (data != null) && (colorData != null) && (positions.getSize() == sizes.length) && (colors.getSize() == sizes.length) ) {
625
626                                 Integer markSizeTmp = polyline.getMarkSize();
627
628                                 // markers with different sizes
629                                 data.rewind();
630                                 colorData.rewind();
631
632                                 stride = stride < 1 ? 1 : stride;
633                                 offset = offset < 0 ? 0 : offset;
634
635                                 int elementSize = positions.getElementsSize();
636                                 int mark = offset * elementSize;
637                                 int k = 0;
638
639                                 while (data.remaining() >= stride * elementSize) {
640
641                                     // Be careful, do not use polyline.setMarkSize since this will destroy the sizes
642                                     polyline.getMark().setSize(sizes[k++]);
643
644                                     BuffersManager bufferManager = drawingTools.getCanvas().getBuffersManager();
645                                     ElementsBuffer singlePosition = bufferManager.createElementsBuffer();
646                                     ElementsBuffer singleColor = bufferManager.createElementsBuffer();
647
648                                     float[] position = {0, 0, 0, 1};
649                                     data.position(mark);
650                                     data.get(position);
651
652                                     float[] color = {0, 0, 0, 0};
653                                     colorData.position(mark);
654                                     colorData.get(color);
655
656                                     mark += stride * elementSize;
657
658                                     singlePosition.setData(position, elementSize);
659                                     singleColor.setData(color, elementSize);
660
661                                     Texture sprite = markManager.getMarkSprite(polyline, null, appearance);
662                                     drawingTools.draw(sprite, AnchorPosition.CENTER, singlePosition, 0, 0, 0, auxColor, singleColor);
663
664                                     bufferManager.dispose(singleColor);
665                                     bufferManager.dispose(singlePosition);
666                                 }
667                                 // restore the size of the mark
668                                 // Be careful, do not use polyline.setMarkSize since this will destroy the sizes
669                                 polyline.getMark().setSize(markSizeTmp);
670                             } else {
671                                 Texture sprite = markManager.getMarkSprite(polyline, null, appearance);
672                                 drawingTools.draw(sprite, AnchorPosition.CENTER, positions, offset, stride, 0, auxColor, colors);
673                             }
674                         } else {
675                             FloatBuffer data = positions.getData();
676                             Integer[] sizes = polyline.getMarkSizes();
677                             if ( (sizes.length > 0) && (data != null) && (positions.getSize() == sizes.length) ) {
678
679                                 Integer markSizeTmp = polyline.getMarkSize();
680
681                                 // markers with different sizes
682                                 data.rewind();
683
684                                 stride = stride < 1 ? 1 : stride;
685                                 offset = offset < 0 ? 0 : offset;
686
687                                 int elementSize = positions.getElementsSize();
688                                 int mark = offset * elementSize;
689                                 int k = 0;
690
691                                 while (data.remaining() >= stride * elementSize) {
692
693                                     // setting the size of the mark temporary
694                                     polyline.getMark().setSize(sizes[k++]);
695
696                                     BuffersManager bufferManager = drawingTools.getCanvas().getBuffersManager();
697                                     ElementsBuffer singlePosition = bufferManager.createElementsBuffer();
698
699                                     float[] position = {0, 0, 0, 1};
700                                     data.position(mark);
701                                     data.get(position);
702                                     mark += stride * elementSize;
703                                     singlePosition.setData(position, elementSize);
704
705                                     Texture sprite = markManager.getMarkSprite(polyline, colorMap, appearance);
706                                     drawingTools.draw(sprite, AnchorPosition.CENTER, singlePosition, 0, 0, 0, null, null);
707
708                                     bufferManager.dispose(singlePosition);
709                                 }
710                                 // restore the size of the mark
711                                 polyline.getMark().setSize(markSizeTmp);
712                             } else {
713                                 Texture sprite = markManager.getMarkSprite(polyline, colorMap, appearance);
714                                 drawingTools.draw(sprite, AnchorPosition.CENTER, positions, offset, stride, 0, null, null);
715                             }
716                         }
717                     }
718                 } catch (ObjectRemovedException e) {
719                     invalidate(polyline, e);
720                 } catch (OutOfMemoryException e) {
721                     invalidate(polyline, e);
722                 } catch (SciRendererException e) {
723                     invalidate(polyline, e);
724                 }
725                 axesDrawer.disableClipping(polyline.getClipProperty());
726                 askAcceptVisitor(polyline.getDatatips());
727             }
728         }
729     }
730
731     @Override
732     public void visit(Rectangle rectangle) {
733         if (rectangle.isValid() && rectangle.getVisible()) {
734             axesDrawer.enableClipping(currentAxes, rectangle.getClipProperty());
735             try {
736                 contouredObjectDrawer.draw(rectangle, currentAxes.getCamera().getView() == ViewType.VIEW_2D);
737             } catch (ObjectRemovedException e) {
738                 invalidate(rectangle, e);
739             } catch (OutOfMemoryException e) {
740                 invalidate(rectangle, e);
741             } catch (SciRendererException e) {
742                 invalidate(rectangle, e);
743             }
744             axesDrawer.disableClipping(rectangle.getClipProperty());
745         }
746     }
747
748     /*
749      * To do:
750      * -use common code for both the Fac3d and Plot3d visit methods
751      *  as they are mostly similar.
752      */
753     @Override
754     public void visit(final Fac3d fac3d) {
755         if (fac3d.isValid() && fac3d.getVisible()) {
756             axesDrawer.enableClipping(currentAxes, fac3d.getClipProperty());
757             try {
758                 if (fac3d.getSurfaceMode()) {
759                     DefaultGeometry geometry = new DefaultGeometry();
760                     geometry.setVertices(dataManager.getVertexBuffer(fac3d.getIdentifier()));
761                     geometry.setNormals(dataManager.getNormalBuffer(fac3d.getIdentifier()));
762                     geometry.setIndices(dataManager.getIndexBuffer(fac3d.getIdentifier()));
763
764                     geometry.setPolygonOffsetMode(true);
765
766                     /* Front-facing triangles */
767                     Appearance appearance = new Appearance();
768                     appearance.setMaterial(LightingUtils.getMaterial(fac3d.getMaterial()));
769                     LightingUtils.setupLights(drawingTools.getLightManager(), currentAxes);
770
771                     if (fac3d.getColorMode() != 0) {
772                         geometry.setFillDrawingMode(Geometry.FillDrawingMode.TRIANGLES);
773                         /* Back-facing triangles */
774                         if (fac3d.getHiddenColor() > 0) {
775                             geometry.setFaceCullingMode(axesDrawer.getBackFaceCullingMode());
776                             Appearance backTrianglesAppearance = new Appearance();
777                             backTrianglesAppearance.setFillColor(ColorFactory.createColor(colorMap, fac3d.getHiddenColor()));
778                             drawingTools.draw(geometry, backTrianglesAppearance);
779
780                             // Now we will draw front face.
781                             geometry.setFaceCullingMode(axesDrawer.getFrontFaceCullingMode());
782                         } else {
783                             geometry.setFaceCullingMode(Geometry.FaceCullingMode.BOTH);
784                         }
785
786                         if (fac3d.getColorFlag() == 0) {
787                             appearance.setFillColor(ColorFactory.createColor(colorMap, Math.abs(fac3d.getColorMode())));
788                         } else if (fac3d.getColorFlag() > 0) {
789                             geometry.setTextureCoordinates(dataManager.getTextureCoordinatesBuffer(fac3d.getIdentifier()));
790                             appearance.setTexture(getColorMapTexture());
791                         } else {
792                             geometry.setColors(null);
793                         }
794                     } else {
795                         geometry.setFillDrawingMode(Geometry.FillDrawingMode.NONE);
796                     }
797
798                     if ((fac3d.getColorMode() >= 0) && (fac3d.getLineThickness() > 0.0)) {
799                         geometry.setLineDrawingMode(Geometry.LineDrawingMode.SEGMENTS);
800                         geometry.setWireIndices(dataManager.getWireIndexBuffer(fac3d.getIdentifier()));
801                         Integer lineColor = fac3d.getSelected() ? fac3d.getSelectedColor() : fac3d.getLineColor();
802                         appearance.setLineColor(ColorFactory.createColor(colorMap, lineColor));
803                         appearance.setLineWidth(fac3d.getLineThickness().floatValue());
804                     }
805
806                     drawingTools.draw(geometry, appearance);
807                     LightingUtils.setLightingEnable(drawingTools.getLightManager(), false);
808                 }
809
810                 if (fac3d.getMarkMode()) {
811                     Appearance appearance = null;
812                     if (fac3d.getLineThickness() > 0.0) {
813                         appearance = new Appearance();
814                         appearance.setLineWidth(fac3d.getLineThickness().floatValue());
815                     }
816
817                     Texture texture = markManager.getMarkSprite(fac3d, colorMap, appearance);
818                     ElementsBuffer positions = dataManager.getVertexBuffer(fac3d.getIdentifier());
819                     drawingTools.draw(texture, AnchorPosition.CENTER, positions);
820                 }
821             } catch (ObjectRemovedException e) {
822                 invalidate(fac3d, e);
823             } catch (OutOfMemoryException e) {
824                 invalidate(fac3d, e);
825             } catch (SciRendererException e) {
826                 invalidate(fac3d, e);
827             }
828             axesDrawer.disableClipping(fac3d.getClipProperty());
829         }
830     }
831
832     @Override
833     public void visit(final Plot3d plot3d) {
834         if (plot3d.isValid() && plot3d.getVisible()) {
835             axesDrawer.enableClipping(currentAxes, plot3d.getClipProperty());
836             try {
837                 if (plot3d.getSurfaceMode()) {
838                     DefaultGeometry geometry = new DefaultGeometry();
839                     if (plot3d.getColorMode() != 0) {
840                         geometry.setFillDrawingMode(Geometry.FillDrawingMode.TRIANGLES);
841                     } else {
842                         geometry.setFillDrawingMode(Geometry.FillDrawingMode.NONE);
843                     }
844
845                     geometry.setPolygonOffsetMode(true);
846
847                     geometry.setVertices(dataManager.getVertexBuffer(plot3d.getIdentifier()));
848                     geometry.setNormals(dataManager.getNormalBuffer(plot3d.getIdentifier()));
849                     geometry.setIndices(dataManager.getIndexBuffer(plot3d.getIdentifier()));
850                     /* Back-facing triangles */
851                     if (plot3d.getHiddenColor() > 0) {
852                         geometry.setFaceCullingMode(axesDrawer.getBackFaceCullingMode());
853                         Appearance backTrianglesAppearance = new Appearance();
854                         backTrianglesAppearance.setFillColor(ColorFactory.createColor(colorMap, plot3d.getHiddenColor()));
855                         drawingTools.draw(geometry, backTrianglesAppearance);
856                     }
857
858                     /* Front-facing triangles */
859                     Appearance appearance = new Appearance();
860                     appearance.setMaterial(LightingUtils.getMaterial(plot3d.getMaterial()));
861                     LightingUtils.setupLights(drawingTools.getLightManager(), currentAxes);
862
863                     if (plot3d.getColorFlag() == 1) {
864                         geometry.setColors(dataManager.getColorBuffer(plot3d.getIdentifier()));
865                     } else {
866                         geometry.setColors(null);
867                     }
868
869                     if (plot3d.getHiddenColor() > 0) {
870                         geometry.setFaceCullingMode(axesDrawer.getFrontFaceCullingMode());
871                     } else {
872                         geometry.setFaceCullingMode(Geometry.FaceCullingMode.BOTH);
873                     }
874
875                     if (plot3d.getColorFlag() == 0) {
876                         appearance.setFillColor(ColorFactory.createColor(colorMap, Math.abs(plot3d.getColorMode())));
877                     }
878
879                     if ((plot3d.getColorMode() >= 0) && (plot3d.getLineThickness() > 0.0)) {
880                         geometry.setLineDrawingMode(Geometry.LineDrawingMode.SEGMENTS);
881                         geometry.setWireIndices(dataManager.getWireIndexBuffer(plot3d.getIdentifier()));
882
883                         appearance.setLinePattern(plot3d.getLineStyleAsEnum().asPattern());
884                         Integer lineColor = plot3d.getSelected() ? plot3d.getSelectedColor() : plot3d.getLineColor();
885                         appearance.setLineColor(ColorFactory.createColor(colorMap, lineColor));
886                         appearance.setLineWidth(plot3d.getLineThickness().floatValue());
887                     }
888                     drawingTools.draw(geometry, appearance);
889                     LightingUtils.setLightingEnable(drawingTools.getLightManager(), false);
890                 }
891
892                 if (plot3d.getMarkMode()) {
893                     Appearance appearance = null;
894                     if (plot3d.getLineThickness() > 0.0) {
895                         appearance = new Appearance();
896                         appearance.setLineWidth(plot3d.getLineThickness().floatValue());
897                     }
898
899                     ElementsBuffer positions = dataManager.getVertexBuffer(plot3d.getIdentifier());
900                     if ((plot3d.getMark().getBackground() == -3 || plot3d.getMark().getForeground() == -3) && plot3d.getColorFlag() == 1) {
901                         Texture sprite = markManager.getMarkSprite(plot3d, null, appearance);
902                         ElementsBuffer colors = dataManager.getColorBuffer(plot3d.getIdentifier());
903                         Color auxColor;
904                         if (plot3d.getMark().getBackground() == -3) {
905                             auxColor = ColorFactory.createColor(colorMap, plot3d.getMark().getForeground());
906                         } else {
907                             auxColor = ColorFactory.createColor(colorMap, plot3d.getMark().getBackground());
908                         }
909                         drawingTools.draw(sprite, AnchorPosition.CENTER, positions, auxColor, colors);
910                     } else {
911                         Texture sprite = markManager.getMarkSprite(plot3d, colorMap, appearance);
912                         drawingTools.draw(sprite, AnchorPosition.CENTER, positions, null, null);
913                     }
914                 }
915             } catch (ObjectRemovedException e) {
916                 invalidate(plot3d, e);
917             } catch (OutOfMemoryException e) {
918                 invalidate(plot3d, e);
919             } catch (SciRendererException e) {
920                 invalidate(plot3d, e);
921             }
922             axesDrawer.disableClipping(plot3d.getClipProperty());
923         }
924     }
925
926     @Override
927     public void visit(Text text) {
928         if (text.isValid() && text.getVisible()) {
929             axesDrawer.enableClipping(currentAxes, text.getClipProperty());
930             try {
931                 textManager.draw(drawingTools, colorMap, text);
932             } catch (SciRendererException e) {
933                 invalidate(text, e);
934             }
935             axesDrawer.disableClipping(text.getClipProperty());
936         }
937     }
938
939     @Override
940     public void visit(Datatip datatip) {
941         if (datatip.isValid() && datatip.getVisible()) {
942             axesDrawer.enableClipping(currentAxes, datatip.getClipProperty());
943             try {
944                 Double[] box = currentAxes.getCorrectedBounds();
945                 Vector3d markPos = DatatipTextDrawer.calculateAnchorPoint(datatip);
946                 Double x = markPos.getX();
947                 Double y = markPos.getY();
948                 Double z = markPos.getZ();
949                 if (x >= box[0] && x <= box[1] &&
950                         y >= box[2] && y <= box[3] &&
951                         z >= box[4] && z <= box[5]) {
952                     if (datatip.getMarkMode()) {
953                         /* TODO: appearance can be not-null */
954                         Texture texture = markManager.getMarkSprite(datatip, colorMap, null);
955                         drawingTools.draw(texture, AnchorPosition.CENTER, markPos);
956                     }
957                     if (datatip.getTipLabelMode()) {
958                         datatipTextDrawer.draw(drawingTools, colorMap, datatip);
959                     }
960                 }
961             } catch (SciRendererException e) {
962                 invalidate((Text)datatip, e);
963             }
964             axesDrawer.disableClipping(datatip.getClipProperty());
965         }
966     }
967
968     @Override
969     public void visit(Arrow arrow) {
970         // TODO
971         System.out.println("How can I draw an arrow ?");
972     }
973
974     @Override
975     public void visit(final Champ champ) {
976         if (champ.isValid() && champ.getVisible()) {
977             axesDrawer.enableClipping(currentAxes, champ.getClipProperty());
978             try {
979                 DefaultGeometry segments = new DefaultGeometry();
980                 segments.setFillDrawingMode(Geometry.FillDrawingMode.NONE);
981                 segments.setLineDrawingMode(Geometry.LineDrawingMode.SEGMENTS);
982                 segments.setVertices(dataManager.getVertexBuffer(champ.getIdentifier()));
983                 segments.setWireIndices(dataManager.getWireIndexBuffer(champ.getIdentifier()));
984                 segments.setFaceCullingMode(Geometry.FaceCullingMode.BOTH);
985                 if (champ.getColored()) {
986                     segments.setColors(dataManager.getColorBuffer(champ.getIdentifier()));
987                 } else {
988                     segments.setColors(null);
989                 }
990
991                 if (champ.getLineMode()) {
992                     Appearance segmentAppearance = new Appearance();
993
994                     /* If not colored, all segments have the same color. */
995                     if (champ.getColored()) {
996                         segmentAppearance.setLineColor(null);
997                     } else {
998                         segmentAppearance.setLineColor(ColorFactory.createColor(colorMap, champ.getLineColor()));
999                     }
1000
1001                     segmentAppearance.setLineWidth(champ.getLineThickness().floatValue());
1002                     segmentAppearance.setLinePattern(champ.getLineStyleAsEnum().asPattern());
1003                     drawingTools.draw(segments, segmentAppearance);
1004                 }
1005
1006                 /* Draw the arrows */
1007                 if (champ.getArrowSize() != 0.0) {
1008                     arrowDrawer.drawArrows(champ.getParentAxes(), champ.getIdentifier(), champ.getArrowSize(), champ.getLineThickness(), false,
1009                                            champ.getColored(), champ.getLineColor(), false);
1010                 }
1011             } catch (OutOfMemoryException e) {
1012                 invalidate(champ, e);
1013             } catch (ObjectRemovedException e) {
1014                 invalidate(champ, e);
1015             } catch (SciRendererException e) {
1016                 invalidate(champ, e);
1017             }
1018             axesDrawer.disableClipping(champ.getClipProperty());
1019         }
1020     }
1021
1022     @Override
1023     public void visit(final Segs segs) {
1024         if (segs.isValid() && segs.getVisible() && segs.getArrows().size() != 0) {
1025             axesDrawer.enableClipping(currentAxes, segs.getClipProperty());
1026             try {
1027                 DefaultGeometry segments = new DefaultGeometry();
1028                 segments.setFillDrawingMode(Geometry.FillDrawingMode.NONE);
1029                 segments.setLineDrawingMode(Geometry.LineDrawingMode.SEGMENTS);
1030                 segments.setVertices(dataManager.getVertexBuffer(segs.getIdentifier()));
1031                 segments.setColors(dataManager.getColorBuffer(segs.getIdentifier()));
1032                 segments.setWireIndices(dataManager.getWireIndexBuffer(segs.getIdentifier()));
1033                 segments.setFaceCullingMode(Geometry.FaceCullingMode.BOTH);
1034
1035                 if (segs.getLineMode()) {
1036                     Appearance segmentAppearance = new Appearance();
1037                     segmentAppearance.setLineColor(null);
1038                     segmentAppearance.setLineWidth(segs.getLineThickness().floatValue());
1039                     segmentAppearance.setLinePattern(segs.getLineStyleAsEnum().asPattern());
1040                     drawingTools.draw(segments, segmentAppearance);
1041                 }
1042
1043                 /*
1044                  * Segs does not derive from ContouredObject but Arrow does, hence we have to get the former's first Arrow
1045                  * in order to obtain the latter's Mark (all arrows are supposed to have the same contour properties for now).
1046                  */
1047                 if (segs.getMarkMode()) {
1048                     ElementsBuffer positions = dataManager.getVertexBuffer(segs.getIdentifier());
1049                     // Take only into account start-end of segs and not the arrow head.
1050                     positions.getData().limit(segs.getNumberArrows() * 2 * 4);
1051
1052                     if (segs.getArrows().get(0).getMark().getBackground() == -3 || segs.getArrows().get(0).getMark().getForeground() == -3) {
1053                         Texture sprite = markManager.getMarkSprite(segs.getIdentifier(), segs.getArrows().get(0).getMark(), null, null);
1054                         ElementsBuffer colors = dataManager.getColorBuffer(segs.getIdentifier());
1055                         Color auxColor;
1056                         if (segs.getArrows().get(0).getMark().getBackground() == -3) {
1057                             auxColor = ColorFactory.createColor(colorMap, segs.getArrows().get(0).getMark().getForeground());
1058                         } else {
1059                             auxColor = ColorFactory.createColor(colorMap, segs.getArrows().get(0).getMark().getBackground());
1060                         }
1061                         drawingTools.draw(sprite, AnchorPosition.CENTER, positions, auxColor, colors);
1062                     } else {
1063                         Texture sprite = markManager.getMarkSprite(segs.getIdentifier(), segs.getArrows().get(0).getMark(), colorMap, null);
1064                         drawingTools.draw(sprite, AnchorPosition.CENTER, positions, null, null);
1065                     }
1066
1067                     positions.getData().limit(positions.getData().capacity());
1068                 }
1069
1070                 /* Draw the arrows */
1071                 if (segs.getArrowSize() != 0.0) {
1072                     arrowDrawer.drawArrows(segs.getParentAxes(), segs.getIdentifier(), segs.getArrowSize(), segs.getLineThickness(), true,
1073                                            true, segs.getLineColor(), false);
1074                 }
1075             } catch (OutOfMemoryException e) {
1076                 invalidate(segs, e);
1077             } catch (ObjectRemovedException e) {
1078                 invalidate(segs, e);
1079             } catch (SciRendererException e) {
1080                 invalidate(segs, e);
1081             }
1082             axesDrawer.disableClipping(segs.getClipProperty());
1083         }
1084     }
1085
1086     @Override
1087     public void updateObject(Integer id, int property) {
1088         /*
1089          * Check if property is CHILDREN and if there is a new child I should care about
1090          */
1091         Integer type = (Integer) GraphicController.getController().getProperty(id, GraphicObjectProperties.__GO_TYPE__);
1092         int objectStyle = (type == GraphicObjectProperties.__GO_UICONTROL__ ? (Integer) GraphicController.getController().getProperty(id, GraphicObjectProperties.__GO_STYLE__) : -1);
1093         if (id.intValue() != figure.getIdentifier().intValue()
1094                 && ((type == GraphicObjectProperties.__GO_UICONTROL__ && objectStyle != GraphicObjectProperties.__GO_UI_FRAME__)
1095                     || type == GraphicObjectProperties.__GO_UIMENU__)) {
1096             return;
1097         }
1098
1099         if (property == GraphicObjectProperties.__GO_CHILDREN__) {
1100             if (id.intValue() != figure.getIdentifier().intValue()) {
1101                 /* Ignore children that are not mine */
1102                 return;
1103             }
1104             Integer[] children = GraphicController.getController().getObjectFromId(id).getChildren();
1105             List<Integer> currentOpenGLChildren = openGLChildren.get(id);
1106             if (currentOpenGLChildren == null) {
1107                 /* No openGLChildren in cache, create empty one */
1108                 openGLChildren.put(id, new ArrayList<Integer>());
1109                 currentOpenGLChildren = openGLChildren.get(id);
1110             }
1111             List<Integer> updatedOpenGLChildren = new ArrayList<Integer>();
1112             for (int i = 0 ; i < children.length ; ++i) {
1113                 Integer currentType = (Integer) GraphicController.getController().getProperty(children[i], GraphicObjectProperties.__GO_TYPE__);
1114                 if (currentType != GraphicObjectProperties.__GO_UICONTROL__ && currentType != GraphicObjectProperties.__GO_UIMENU__) {
1115                     updatedOpenGLChildren.add(children[i]);
1116                 }
1117             }
1118             if (currentOpenGLChildren.size() == updatedOpenGLChildren.size()) {
1119                 /* No change made on openGL children => nothing to do */
1120                 return;
1121             } else {
1122                 openGLChildren.put(id, updatedOpenGLChildren);
1123             }
1124         }
1125
1126         try {
1127             if (needUpdate(id, property)) {
1128                 if (GraphicObjectProperties.__GO_COLORMAP__ == property) {
1129                     labelManager.disposeAll();
1130                     dataManager.disposeAllColorBuffers();
1131                     dataManager.disposeAllTextureCoordinatesBuffers();
1132                     markManager.disposeAll();
1133                     textManager.disposeAll();
1134                     axesDrawer.disposeAll();
1135                     fecDrawer.updateAll();
1136                     colorMapTextureDataProvider.update();
1137                     datatipTextDrawer.disposeAll();
1138                     textureManager.disposeAll();
1139                 } else {
1140                     labelManager.update(id, property);
1141                     dataManager.update(id, property);
1142                     markManager.update(id, property);
1143                     textManager.update(id, property);
1144                     axesDrawer.update(id, property);
1145                     legendDrawer.update(id, property);
1146                     fecDrawer.update(id, property);
1147                     datatipTextDrawer.update(id, property);
1148                 }
1149
1150                 if (GraphicObjectProperties.__GO_ANTIALIASING__ == property) {
1151                     canvas.setAntiAliasingLevel(figure.getAntialiasing());
1152                 }
1153
1154                 Figure parentFigure = (Figure) GraphicController.getController().getObjectFromId(figure.getParentFigure());
1155                 if (figure.getVisible() && parentFigure != null && parentFigure.getVisible()) {
1156                     if (isImmediateDrawing(id)) {
1157                         if (GraphicObjectProperties.__GO_IMMEDIATE_DRAWING__ == property) {
1158                             canvas.redrawAndWait();
1159                         } else {
1160                             canvas.redraw();
1161                         }
1162                     }
1163                 }
1164             }
1165
1166             if (GraphicObjectProperties.__GO_IMMEDIATE_DRAWING__ == property && !isImmediateDrawing(id)) {
1167                 canvas.waitImage();
1168             }
1169
1170         } catch (OutOfMemoryException e) {
1171             invalidate(GraphicController.getController().getObjectFromId(id), e);
1172         } catch (ObjectRemovedException e) {
1173             // Object has been removed before draw : do nothing.
1174         }
1175     }
1176
1177     /**
1178      * Check if the given changed property make the figure out of date.
1179      * @param id the object updated
1180      * @param property the changed property.
1181      * @return true id the given changed property make the figure out of date.
1182      */
1183     protected boolean needUpdate(Integer id, int property) {
1184         GraphicObject object = GraphicController.getController().getObjectFromId(id);
1185         int objectType = (Integer) GraphicController.getController().getProperty(id, GraphicObjectProperties.__GO_TYPE__);
1186         int objectStyle = (objectType == GraphicObjectProperties.__GO_UICONTROL__ ? (Integer) GraphicController.getController().getProperty(id, GraphicObjectProperties.__GO_STYLE__) : -1);
1187         if ((object != null) && (isFigureChild(id) || isFigureParent(id)) || (objectType == GraphicObjectProperties.__GO_UICONTROL__ && objectStyle == GraphicObjectProperties.__GO_UI_FRAME__)
1188                 && objectType != GraphicObjectProperties.__GO_UIMENU__ && objectType != GraphicObjectProperties.__GO_UI_FRAME_BORDER__) {
1189
1190             if (GraphicObjectProperties.__GO_VALID__ == property) {
1191                 return false;
1192             }
1193
1194             if (object instanceof Axes) {
1195                 Axes axes = (Axes) object;
1196
1197                 if ((axes.getXAxisAutoTicks() && X_AXIS_TICKS_PROPERTIES.contains(property)) ||
1198                         (axes.getYAxisAutoTicks() && Y_AXIS_TICKS_PROPERTIES.contains(property)) ||
1199                         (axes.getZAxisAutoTicks() && Z_AXIS_TICKS_PROPERTIES.contains(property))) {
1200                     return false;
1201                 }
1202
1203                 if ((!axes.getXAxisAutoTicks() && X_AXIS_TICKS_PROPERTIES.contains(property)) ||
1204                         (!axes.getYAxisAutoTicks() && Y_AXIS_TICKS_PROPERTIES.contains(property)) ||
1205                         (!axes.getZAxisAutoTicks() && Z_AXIS_TICKS_PROPERTIES.contains(property))) {
1206                     axesDrawer.computeMargins(axes);
1207                     return true;
1208                 }
1209
1210                 if (property != GraphicObjectProperties.__GO_CHILDREN__) {
1211                     axesDrawer.computeRulers(axes);
1212                 }
1213             }
1214
1215             if (object instanceof Label || object instanceof Legend) {
1216                 GraphicObject parent = GraphicController.getController().getObjectFromId(object.getParent());
1217                 if (parent instanceof Axes) {
1218                     Axes axes = (Axes) parent;
1219                     if (axes.getXAxisLabel().equals(id) ||
1220                             axes.getYAxisLabel().equals(id) ||
1221                             axes.getZAxisLabel().equals(id) ||
1222                             axes.getTitle().equals(id)) {
1223                         labelManager.update(id, property);
1224                         axesDrawer.computeMargins(axes);
1225                     } else if (object instanceof Legend && (property == GraphicObjectProperties.__GO_LEGEND_LOCATION__ || property == GraphicObjectProperties.__GO_LINE_WIDTH__)) {
1226                         legendDrawer.update(id, property);
1227                         axesDrawer.computeMargins(axes);
1228                     }
1229                 }
1230             } else if (object instanceof Figure) {
1231                 if (property == GraphicObjectProperties.__GO_SIZE__
1232                         || property == GraphicObjectProperties.__GO_AXES_SIZE__
1233                         || property == GraphicObjectProperties.__GO_CHILDREN__
1234                         || property == GraphicObjectProperties.__GO_POSITION__
1235                         || property == GraphicObjectProperties.__GO_VISIBLE__) {
1236                     for (Integer gid : figure.getChildren()) {
1237                         GraphicObject go = GraphicController.getController().getObjectFromId(gid);
1238                         if (go instanceof Axes) {
1239                             axesDrawer.computeMargins((Axes) go);
1240                             axesDrawer.computeRulers((Axes) go);
1241                         }
1242                     }
1243                 }
1244
1245                 if (SILENT_FIGURE_PROPERTIES.contains(property)) {
1246                     return false;
1247                 }
1248             } else if (object instanceof Frame
1249                        && id.intValue() == figure.getIdentifier().intValue()
1250                        && property == GraphicObjectProperties.__GO_POSITION__) {
1251                 Frame fig = (Frame) object;
1252                 for (Integer gid : fig.getChildren()) {
1253                     GraphicObject go = GraphicController.getController().getObjectFromId(gid);
1254                     if (go instanceof Axes) {
1255                         axesDrawer.computeRulers((Axes) go);
1256                     }
1257                 }
1258
1259             } else if (object instanceof Axes && property == GraphicObjectProperties.__GO_X_AXIS_LOCATION__ ||
1260                        property == GraphicObjectProperties.__GO_Y_AXIS_LOCATION__ || property == GraphicObjectProperties.__GO_AUTO_MARGINS__) {
1261                 axesDrawer.computeMargins((Axes) object);
1262             }
1263
1264             if (!object.isValid()) {
1265                 GraphicController.getController().setProperty(id, GraphicObjectProperties.__GO_VALID__, true);
1266             }
1267
1268             return true;
1269         }
1270         // Special case if top level figure colormap/immediate_drawing has been updated, force redraw
1271         if ((property == GraphicObjectProperties.__GO_COLORMAP__ ||  property == GraphicObjectProperties.__GO_IMMEDIATE_DRAWING__)
1272                 && id.intValue() == figure.getParentFigure().intValue()) {
1273             return true;
1274         }
1275         return false;
1276     }
1277
1278     private boolean isImmediateDrawing(Integer id) {
1279         Integer parentId = (Integer) GraphicController.getController().getProperty(id, GraphicObjectProperties.__GO_PARENT_FIGURE__);
1280         if (figure instanceof Frame) {
1281             parentId = figure.getParentFigure();
1282         }
1283         if (figure instanceof Figure && (parentId == null || !parentId.equals(figure.getIdentifier()))) {
1284             return false;
1285         } else {
1286             Boolean b =  (Boolean) GraphicController.getController().getProperty(parentId, GraphicObjectProperties.__GO_IMMEDIATE_DRAWING__);
1287             return (b == null) ? false : b;
1288         }
1289     }
1290
1291     @Override
1292     public void createObject(Integer id) {
1293     }
1294
1295     @Override
1296     public void deleteObject(Integer id) {
1297         Integer type = (Integer) GraphicController.getController().getProperty(id, GraphicObjectProperties.__GO_TYPE__);
1298         if (!figure.getIdentifier().equals(id) && type == GraphicObjectProperties.__GO_UICONTROL__ || type == GraphicObjectProperties.__GO_UIMENU__) {
1299             return; // Not of my managed openGL children
1300         }
1301
1302         openGLChildren.remove(id);
1303
1304         if (isImmediateDrawing(id)) {
1305             canvas.redraw();
1306         }
1307
1308         dataManager.dispose(id);
1309         markManager.dispose(id);
1310         textManager.dispose(id);
1311         labelManager.dispose(id);
1312         axesDrawer.dispose(id);
1313         legendDrawer.dispose(id);
1314         fecDrawer.dispose(id);
1315         textureManager.dispose(id);
1316         /*
1317          * Check we are deleting Figure managed by DrawerVisitor(this)
1318          * Otherwise do nothing on deletion.
1319          */
1320         if (!figure.getIdentifier().equals(id)) {
1321             return;
1322         }
1323
1324         visitorMap.remove(id);
1325         GraphicController.getController().unregister(this);
1326         if (SwingUtilities.isEventDispatchThread()) {
1327             canvas.destroy();
1328         } else {
1329             try {
1330                 SwingUtilities.invokeAndWait(new Runnable() {
1331                     public void run() {
1332                         canvas.destroy();
1333                     }
1334                 });
1335             } catch (Exception e) { }
1336         }
1337     }
1338
1339     /**
1340      * Check if the given id correspond to a parent of the current {@see Figure}.
1341      * @param id the given id.
1342      * @return true if the given id correspond to a parent of the current {@see Figure}.
1343      */
1344     private boolean isFigureParent(Integer id) {
1345         GraphicObject object = GraphicController.getController().getObjectFromId(id);
1346         if (object != null) {
1347             Object parentObject = GraphicController.getController().getProperty(figure.getIdentifier(), GraphicObjectProperties.__GO_PARENT__);
1348             Integer parentUID = parentObject == null ? 0 : (Integer) parentObject;
1349             while (parentUID.intValue() != 0) {
1350                 if (parentUID.intValue() == id.intValue()) {
1351                     return true;
1352                 }
1353                 parentObject = GraphicController.getController().getProperty(parentUID, GraphicObjectProperties.__GO_PARENT__);
1354                 parentUID = parentObject == null ? 0 : (Integer) parentObject;
1355             }
1356         }
1357
1358         return false;
1359     }
1360
1361     /**
1362      * Check if the given id correspond to a child of the current {@see Figure}.
1363      * @param id the given id.
1364      * @return true if the given id correspond to a child of the current {@see Figure}.
1365      */
1366     private boolean isFigureChild(Integer id) {
1367         if (id.intValue() == figure.getIdentifier().intValue()) {
1368             return true;
1369         }
1370
1371         Object parentObject = GraphicController.getController().getProperty(id, GraphicObjectProperties.__GO_PARENT__);
1372         Integer parentUID = parentObject == null ? 0 : (Integer) parentObject;
1373         while (parentUID != 0) {
1374
1375             if (figure.getIdentifier().intValue() == parentUID.intValue()) {
1376                 return true;
1377             }
1378
1379             Integer parentStyle = (Integer) GraphicController.getController().getProperty(parentUID, GraphicObjectProperties.__GO_STYLE__);
1380             if (parentStyle != null && parentStyle.intValue() == GraphicObjectProperties.__GO_UI_FRAME__) {
1381                 // Drop drawing if parent is a Frame and I'm not the dedicated visitor.
1382                 return false;
1383             }
1384
1385             parentObject = GraphicController.getController().getProperty(parentUID, GraphicObjectProperties.__GO_PARENT__);
1386             parentUID = parentObject == null ? 0 : (Integer) parentObject;
1387
1388         }
1389         return false;
1390     }
1391
1392     /**
1393      * Invalidate the given graphic object and inform the user.
1394      * @param graphicObject the graphic object to invalidate
1395      * @param exception the cause of invalidation.
1396      */
1397     public void invalidate(GraphicObject graphicObject, Exception exception) {
1398         if (DEBUG_MODE) {
1399             System.err.println("The " + graphicObject.getType() + " \"" + graphicObject.getIdentifier()
1400                                + "\" has been invalidated: " + exception.getMessage());
1401             exception.printStackTrace();
1402         }
1403         GraphicController.getController().setProperty(graphicObject.getIdentifier(), GraphicObjectProperties.__GO_VALID__, false);
1404     }
1405
1406     public LabelManager getLabelManager() {
1407         return labelManager;
1408     }
1409
1410     public Texture getColorMapTexture() {
1411         if (colorMapTexture == null) {
1412             colorMapTexture = canvas.getTextureManager().createTexture();
1413             colorMapTexture.setMagnificationFilter(Texture.Filter.NEAREST);
1414             colorMapTexture.setMinifyingFilter(Texture.Filter.NEAREST);
1415             colorMapTexture.setSWrappingMode(Texture.Wrap.CLAMP);
1416             colorMapTexture.setTWrappingMode(Texture.Wrap.CLAMP);
1417             colorMapTexture.setDataProvider(colorMapTextureDataProvider);
1418         }
1419         return colorMapTexture;
1420     }
1421
1422     /**
1423      * Figure getter.
1424      * @return the figure this visitor draw.
1425      */
1426     public AxesContainer getFigure() {
1427         return figure;
1428     }
1429
1430     public Axes getAxes() {
1431         return currentAxes;
1432     }
1433
1434     private Geometry cube;
1435     public Geometry getCube() {
1436         if (cube == null) {
1437             cube = CubeFactory.createCube(canvas);
1438         }
1439         return cube;
1440     }
1441
1442     /**
1443      * Component getter.
1444      * @return return the attached component.
1445      */
1446     public Component getComponent() {
1447         return component;
1448     }
1449
1450     /**
1451      * Interaction manager getter
1452      * @return the interaction manager.
1453      */
1454     public InteractionManager getInteractionManager() {
1455         return interactionManager;
1456     }
1457
1458     private class ColorMapTextureDataProvider extends AbstractTextureDataProvider {
1459         byte[] whiteColor = {(byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF};
1460         byte[] blackColor = {0x00, 0x00, 0x00, (byte) 0xFF};
1461
1462         public ColorMapTextureDataProvider() {
1463             super();
1464             this.imageType = ImageType.RGBA_BYTE;
1465         }
1466
1467         @Override
1468         public Dimension getTextureSize() {
1469             return new Dimension(colorMap.getSize() + 2, 1);
1470         }
1471
1472         @Override
1473         public ByteBuffer getData() {
1474             Double[] data = colorMap.getData();
1475             ByteBuffer buffer = ByteBuffer.allocate(4 * ((data.length / 3) + 2));
1476
1477             /* White and black are written in the first and second positions */
1478             buffer.put(whiteColor);
1479             buffer.put(blackColor);
1480
1481             for (int i = 0 ; i < data.length / 3 ; i++) {
1482                 buffer.put(toByte(data[i]));
1483                 buffer.put(toByte(data[i + colorMap.getSize()].floatValue()));
1484                 buffer.put(toByte(data[i + 2 * colorMap.getSize()].floatValue()));
1485                 buffer.put(toByte(1));
1486             }
1487             buffer.rewind();
1488             return buffer;
1489         }
1490
1491         @Override
1492         public ByteBuffer getSubData(int x, int y, int width, int height) {
1493             /*
1494              * For the moment, we presuppose that x and y are 0 and that
1495              * width is equal to the colormap's total size (with height == 1).
1496              * To be correctly implemented.
1497              */
1498             return getData();
1499         }
1500
1501         @Override
1502         public boolean isValid() {
1503             return true;
1504         }
1505
1506         public void update() {
1507             fireUpdate();
1508         }
1509     }
1510 }