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