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