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