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