5b703feae2ecd7308c02d35e152de849e81a7b5e
[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                         if (polyline.getColorSet()) {
561                             ElementsBuffer colors = dataManager.getColorBuffer(polyline.getIdentifier());
562                             geometry.setColors(colors);
563                             appearance.setLineColor(null);
564                         } else {
565                             geometry.setColors(null);
566                             appearance.setLineColor(ColorFactory.createColor(colorMap, polyline.getLineColor()));
567                         }
568                     }
569
570                     Integer lineColor = polyline.getSelected() ? polyline.getSelectedColor() : polyline.getLineColor();
571                     appearance.setLineColor(ColorFactory.createColor(colorMap, lineColor));
572                     appearance.setLineWidth(polyline.getLineThickness().floatValue());
573                     appearance.setLinePattern(polyline.getLineStyleAsEnum().asPattern());
574
575                     if (!polyline.getInterpColorMode() || style != 1) {
576                         int fillColor;
577
578                         /*
579                          * The line color is used as fill color for the filled patch polyline style
580                          * whereas the background color is used for all the other styles.
581                          */
582                         if (style == 5) {
583                             fillColor = lineColor;
584                         } else {
585                             fillColor = polyline.getBackground();
586                         }
587
588                         appearance.setFillColor(ColorFactory.createColor(colorMap, fillColor));
589                     }
590
591                     drawingTools.draw(geometry, appearance);
592
593                     if (style == 4) {
594                         arrowDrawer.drawArrows(polyline.getParentAxes(), polyline.getIdentifier(), polyline.getArrowSizeFactor(),
595                                                polyline.getLineThickness(), false, false, lineColor, true);
596                     }
597
598                     if (polyline.getMarkMode()) {
599                         ElementsBuffer positions = dataManager.getVertexBuffer(polyline.getIdentifier());
600                         int offset = polyline.getMarkOffset();
601                         int stride = polyline.getMarkStride();
602                         if (polyline.getColorSet() && polyline.getMark().getBackground() == -3) {
603                             Texture sprite = markManager.getMarkSprite(polyline, null, appearance);
604                             ElementsBuffer colors = dataManager.getColorBuffer(polyline.getIdentifier());
605                             drawingTools.draw(sprite, AnchorPosition.CENTER, positions, offset, stride, 0, colors);
606                         } else {
607                             Texture sprite = markManager.getMarkSprite(polyline, colorMap, appearance);
608                             drawingTools.draw(sprite, AnchorPosition.CENTER, positions, offset, stride, 0, null);
609                         }
610                     }
611                 } catch (ObjectRemovedException e) {
612                     invalidate(polyline, e);
613                 } catch (OutOfMemoryException e) {
614                     invalidate(polyline, e);
615                 } catch (SciRendererException e) {
616                     invalidate(polyline, e);
617                 }
618                 axesDrawer.disableClipping(polyline.getClipProperty());
619                 askAcceptVisitor(polyline.getDatatips());
620             }
621         }
622     }
623
624     @Override
625     public void visit(Rectangle rectangle) {
626         if (rectangle.isValid() && rectangle.getVisible()) {
627             axesDrawer.enableClipping(currentAxes, rectangle.getClipProperty());
628             try {
629                 contouredObjectDrawer.draw(rectangle, currentAxes.getCamera().getView() == ViewType.VIEW_2D);
630             } catch (ObjectRemovedException e) {
631                 invalidate(rectangle, e);
632             } catch (OutOfMemoryException e) {
633                 invalidate(rectangle, e);
634             } catch (SciRendererException e) {
635                 invalidate(rectangle, e);
636             }
637             axesDrawer.disableClipping(rectangle.getClipProperty());
638         }
639     }
640
641     /*
642      * To do:
643      * -use common code for both the Fac3d and Plot3d visit methods
644      *  as they are mostly similar.
645      */
646     @Override
647     public void visit(final Fac3d fac3d) {
648         if (fac3d.isValid() && fac3d.getVisible()) {
649             axesDrawer.enableClipping(currentAxes, fac3d.getClipProperty());
650             try {
651                 if (fac3d.getSurfaceMode()) {
652                     DefaultGeometry geometry = new DefaultGeometry();
653                     geometry.setVertices(dataManager.getVertexBuffer(fac3d.getIdentifier()));
654                     geometry.setNormals(dataManager.getNormalBuffer(fac3d.getIdentifier()));
655                     geometry.setIndices(dataManager.getIndexBuffer(fac3d.getIdentifier()));
656
657                     geometry.setPolygonOffsetMode(true);
658
659                     /* Front-facing triangles */
660                     Appearance appearance = new Appearance();
661                     appearance.setMaterial(LightingUtils.getMaterial(fac3d.getMaterial()));
662                     LightingUtils.setupLights(drawingTools.getLightManager(), currentAxes);
663
664                     if (fac3d.getColorMode() != 0) {
665                         geometry.setFillDrawingMode(Geometry.FillDrawingMode.TRIANGLES);
666                         /* Back-facing triangles */
667                         if (fac3d.getHiddenColor() > 0) {
668                             geometry.setFaceCullingMode(axesDrawer.getBackFaceCullingMode());
669                             Appearance backTrianglesAppearance = new Appearance();
670                             backTrianglesAppearance.setFillColor(ColorFactory.createColor(colorMap, fac3d.getHiddenColor()));
671                             drawingTools.draw(geometry, backTrianglesAppearance);
672
673                             // Now we will draw front face.
674                             geometry.setFaceCullingMode(axesDrawer.getFrontFaceCullingMode());
675                         } else {
676                             geometry.setFaceCullingMode(Geometry.FaceCullingMode.BOTH);
677                         }
678
679                         if (fac3d.getColorFlag() == 0) {
680                             appearance.setFillColor(ColorFactory.createColor(colorMap, Math.abs(fac3d.getColorMode())));
681                         } else if (fac3d.getColorFlag() > 0) {
682                             geometry.setTextureCoordinates(dataManager.getTextureCoordinatesBuffer(fac3d.getIdentifier()));
683                             appearance.setTexture(getColorMapTexture());
684                         } else {
685                             geometry.setColors(null);
686                         }
687                     } else {
688                         geometry.setFillDrawingMode(Geometry.FillDrawingMode.NONE);
689                     }
690
691                     if ((fac3d.getColorMode() >= 0) && (fac3d.getLineThickness() > 0.0)) {
692                         geometry.setLineDrawingMode(Geometry.LineDrawingMode.SEGMENTS);
693                         geometry.setWireIndices(dataManager.getWireIndexBuffer(fac3d.getIdentifier()));
694                         Integer lineColor = fac3d.getSelected() ? fac3d.getSelectedColor() : fac3d.getLineColor();
695                         appearance.setLineColor(ColorFactory.createColor(colorMap, lineColor));
696                         appearance.setLineWidth(fac3d.getLineThickness().floatValue());
697                     }
698
699                     drawingTools.draw(geometry, appearance);
700                     LightingUtils.setLightingEnable(drawingTools.getLightManager(), false);
701                 }
702
703                 if (fac3d.getMarkMode()) {
704                     Appearance appearance = null;
705                     if (fac3d.getLineThickness() > 0.0) {
706                         appearance = new Appearance();
707                         appearance.setLineWidth(fac3d.getLineThickness().floatValue());
708                     }
709
710                     Texture texture = markManager.getMarkSprite(fac3d, colorMap, appearance);
711                     ElementsBuffer positions = dataManager.getVertexBuffer(fac3d.getIdentifier());
712                     drawingTools.draw(texture, AnchorPosition.CENTER, positions);
713                 }
714             } catch (ObjectRemovedException e) {
715                 invalidate(fac3d, e);
716             } catch (OutOfMemoryException e) {
717                 invalidate(fac3d, e);
718             } catch (SciRendererException e) {
719                 invalidate(fac3d, e);
720             }
721             axesDrawer.disableClipping(fac3d.getClipProperty());
722         }
723     }
724
725     @Override
726     public void visit(final Plot3d plot3d) {
727         if (plot3d.isValid() && plot3d.getVisible()) {
728             axesDrawer.enableClipping(currentAxes, plot3d.getClipProperty());
729             try {
730                 if (plot3d.getSurfaceMode()) {
731                     DefaultGeometry geometry = new DefaultGeometry();
732                     if (plot3d.getColorMode() != 0) {
733                         geometry.setFillDrawingMode(Geometry.FillDrawingMode.TRIANGLES);
734                     } else {
735                         geometry.setFillDrawingMode(Geometry.FillDrawingMode.NONE);
736                     }
737
738                     geometry.setPolygonOffsetMode(true);
739
740                     geometry.setVertices(dataManager.getVertexBuffer(plot3d.getIdentifier()));
741                     geometry.setNormals(dataManager.getNormalBuffer(plot3d.getIdentifier()));
742                     geometry.setIndices(dataManager.getIndexBuffer(plot3d.getIdentifier()));
743                     /* Back-facing triangles */
744                     if (plot3d.getHiddenColor() > 0) {
745                         geometry.setFaceCullingMode(axesDrawer.getBackFaceCullingMode());
746                         Appearance backTrianglesAppearance = new Appearance();
747                         backTrianglesAppearance.setFillColor(ColorFactory.createColor(colorMap, plot3d.getHiddenColor()));
748                         drawingTools.draw(geometry, backTrianglesAppearance);
749                     }
750
751                     /* Front-facing triangles */
752                     Appearance appearance = new Appearance();
753                     appearance.setMaterial(LightingUtils.getMaterial(plot3d.getMaterial()));
754                     LightingUtils.setupLights(drawingTools.getLightManager(), currentAxes);
755
756                     if (plot3d.getColorFlag() == 1) {
757                         geometry.setColors(dataManager.getColorBuffer(plot3d.getIdentifier()));
758                     } else {
759                         geometry.setColors(null);
760                     }
761
762                     if (plot3d.getHiddenColor() > 0) {
763                         geometry.setFaceCullingMode(axesDrawer.getFrontFaceCullingMode());
764                     } else {
765                         geometry.setFaceCullingMode(Geometry.FaceCullingMode.BOTH);
766                     }
767
768                     if (plot3d.getColorFlag() == 0) {
769                         appearance.setFillColor(ColorFactory.createColor(colorMap, Math.abs(plot3d.getColorMode())));
770                     }
771
772                     if ((plot3d.getColorMode() >= 0) && (plot3d.getLineThickness() > 0.0)) {
773                         geometry.setLineDrawingMode(Geometry.LineDrawingMode.SEGMENTS);
774                         geometry.setWireIndices(dataManager.getWireIndexBuffer(plot3d.getIdentifier()));
775
776                         appearance.setLinePattern(plot3d.getLineStyleAsEnum().asPattern());
777                         Integer lineColor = plot3d.getSelected() ? plot3d.getSelectedColor() : plot3d.getLineColor();
778                         appearance.setLineColor(ColorFactory.createColor(colorMap, lineColor));
779                         appearance.setLineWidth(plot3d.getLineThickness().floatValue());
780                     }
781                     drawingTools.draw(geometry, appearance);
782                     LightingUtils.setLightingEnable(drawingTools.getLightManager(), false);
783                 }
784
785                 if (plot3d.getMarkMode()) {
786                     Appearance appearance = null;
787                     if (plot3d.getLineThickness() > 0.0) {
788                         appearance = new Appearance();
789                         appearance.setLineWidth(plot3d.getLineThickness().floatValue());
790                     }
791
792                     ElementsBuffer positions = dataManager.getVertexBuffer(plot3d.getIdentifier());
793                     if (plot3d.getMark().getBackground() == -3 && plot3d.getColorFlag() == 1) {
794                         Texture sprite = markManager.getMarkSprite(plot3d, null, appearance);
795                         ElementsBuffer colors = dataManager.getColorBuffer(plot3d.getIdentifier());
796                         drawingTools.draw(sprite, AnchorPosition.CENTER, positions, colors);
797                     } else {
798                         Texture sprite = markManager.getMarkSprite(plot3d, colorMap, appearance);
799                         drawingTools.draw(sprite, AnchorPosition.CENTER, positions, null);
800                     }
801                 }
802             } catch (ObjectRemovedException e) {
803                 invalidate(plot3d, e);
804             } catch (OutOfMemoryException e) {
805                 invalidate(plot3d, e);
806             } catch (SciRendererException e) {
807                 invalidate(plot3d, e);
808             }
809             axesDrawer.disableClipping(plot3d.getClipProperty());
810         }
811     }
812
813     @Override
814     public void visit(Text text) {
815         if (text.isValid() && text.getVisible()) {
816             axesDrawer.enableClipping(currentAxes, text.getClipProperty());
817             try {
818                 textManager.draw(drawingTools, colorMap, text);
819             } catch (SciRendererException e) {
820                 invalidate(text, e);
821             }
822             axesDrawer.disableClipping(text.getClipProperty());
823         }
824     }
825
826     @Override
827     public void visit(Datatip datatip) {
828         if (datatip.isValid() && datatip.getVisible()) {
829             axesDrawer.enableClipping(currentAxes, datatip.getClipProperty());
830             try {
831                 if (datatip.getMarkMode()) {
832                     /* TODO: appearance can be not-null */
833                     Texture texture = markManager.getMarkSprite(datatip, colorMap, null);
834                     Vector3d markPos = DatatipTextDrawer.calculateAnchorPoint(datatip);
835                     drawingTools.draw(texture, AnchorPosition.CENTER, markPos);
836                 }
837                 if (datatip.getTipLabelMode()) {
838                     datatipTextDrawer.draw(drawingTools, colorMap, datatip);
839                 }
840             } catch (SciRendererException e) {
841                 invalidate((Text)datatip, e);
842             }
843             axesDrawer.disableClipping(datatip.getClipProperty());
844         }
845     }
846
847     @Override
848     public void visit(Arrow arrow) {
849         // TODO
850         System.out.println("How can I draw an arrow ?");
851     }
852
853     @Override
854     public void visit(final Champ champ) {
855         if (champ.isValid() && champ.getVisible()) {
856             axesDrawer.enableClipping(currentAxes, champ.getClipProperty());
857             try {
858                 DefaultGeometry segments = new DefaultGeometry();
859                 segments.setFillDrawingMode(Geometry.FillDrawingMode.NONE);
860                 segments.setLineDrawingMode(Geometry.LineDrawingMode.SEGMENTS);
861                 segments.setVertices(dataManager.getVertexBuffer(champ.getIdentifier()));
862                 segments.setWireIndices(dataManager.getWireIndexBuffer(champ.getIdentifier()));
863                 segments.setFaceCullingMode(Geometry.FaceCullingMode.BOTH);
864                 if (champ.getColored()) {
865                     segments.setColors(dataManager.getColorBuffer(champ.getIdentifier()));
866                 } else {
867                     segments.setColors(null);
868                 }
869
870                 if (champ.getLineMode()) {
871                     Appearance segmentAppearance = new Appearance();
872
873                     /* If not colored, all segments have the same color. */
874                     if (champ.getColored()) {
875                         segmentAppearance.setLineColor(null);
876                     } else {
877                         segmentAppearance.setLineColor(ColorFactory.createColor(colorMap, champ.getLineColor()));
878                     }
879
880                     segmentAppearance.setLineWidth(champ.getLineThickness().floatValue());
881                     segmentAppearance.setLinePattern(champ.getLineStyleAsEnum().asPattern());
882                     drawingTools.draw(segments, segmentAppearance);
883                 }
884
885                 /* Draw the arrows */
886                 if (champ.getArrowSize() != 0.0) {
887                     arrowDrawer.drawArrows(champ.getParentAxes(), champ.getIdentifier(), champ.getArrowSize(), champ.getLineThickness(), false,
888                                            champ.getColored(), champ.getLineColor(), false);
889                 }
890             } catch (OutOfMemoryException e) {
891                 invalidate(champ, e);
892             } catch (ObjectRemovedException e) {
893                 invalidate(champ, e);
894             } catch (SciRendererException e) {
895                 invalidate(champ, e);
896             }
897             axesDrawer.disableClipping(champ.getClipProperty());
898         }
899     }
900
901     @Override
902     public void visit(final Segs segs) {
903         if (segs.isValid() && segs.getVisible() && segs.getArrows().size() != 0) {
904             axesDrawer.enableClipping(currentAxes, segs.getClipProperty());
905             try {
906                 DefaultGeometry segments = new DefaultGeometry();
907                 segments.setFillDrawingMode(Geometry.FillDrawingMode.NONE);
908                 segments.setLineDrawingMode(Geometry.LineDrawingMode.SEGMENTS);
909                 segments.setVertices(dataManager.getVertexBuffer(segs.getIdentifier()));
910                 segments.setColors(dataManager.getColorBuffer(segs.getIdentifier()));
911                 segments.setWireIndices(dataManager.getWireIndexBuffer(segs.getIdentifier()));
912                 segments.setFaceCullingMode(Geometry.FaceCullingMode.BOTH);
913
914                 if (segs.getLineMode()) {
915                     Appearance segmentAppearance = new Appearance();
916                     segmentAppearance.setLineColor(null);
917                     segmentAppearance.setLineWidth(segs.getLineThickness().floatValue());
918                     segmentAppearance.setLinePattern(segs.getLineStyleAsEnum().asPattern());
919                     drawingTools.draw(segments, segmentAppearance);
920                 }
921
922                 /*
923                  * Segs does not derive from ContouredObject but Arrow does, hence we have to get the former's first Arrow
924                  * in order to obtain the latter's Mark (all arrows are supposed to have the same contour properties for now).
925                  */
926                 if (segs.getMarkMode()) {
927                     ElementsBuffer positions = dataManager.getVertexBuffer(segs.getIdentifier());
928                     // Take only into account start-end of segs and not the arrow head.
929                     positions.getData().limit(segs.getNumberArrows() * 2 * 4);
930
931                     if (segs.getArrows().get(0).getMark().getBackground() == -3) {
932                         Texture sprite = markManager.getMarkSprite(segs.getIdentifier(), segs.getArrows().get(0).getMark(), null, null);
933                         ElementsBuffer colors = dataManager.getColorBuffer(segs.getIdentifier());
934                         drawingTools.draw(sprite, AnchorPosition.CENTER, positions, colors);
935                     } else {
936                         Texture sprite = markManager.getMarkSprite(segs.getIdentifier(), segs.getArrows().get(0).getMark(), colorMap, null);
937                         drawingTools.draw(sprite, AnchorPosition.CENTER, positions, null);
938                     }
939
940                     positions.getData().limit(positions.getData().capacity());
941                 }
942
943                 /* Draw the arrows */
944                 if (segs.getArrowSize() != 0.0) {
945                     arrowDrawer.drawArrows(segs.getParentAxes(), segs.getIdentifier(), segs.getArrowSize(), segs.getLineThickness(), true,
946                                            true, segs.getLineColor(), false);
947                 }
948             } catch (OutOfMemoryException e) {
949                 invalidate(segs, e);
950             } catch (ObjectRemovedException e) {
951                 invalidate(segs, e);
952             } catch (SciRendererException e) {
953                 invalidate(segs, e);
954             }
955             axesDrawer.disableClipping(segs.getClipProperty());
956         }
957     }
958
959     @Override
960     public void updateObject(Integer id, int property) {
961         /*
962          * Check if property is CHILDREN and if there is a new child I should care about
963          */
964         Integer type = (Integer) GraphicController.getController().getProperty(id, GraphicObjectProperties.__GO_TYPE__);
965         int objectStyle = (type == GraphicObjectProperties.__GO_UICONTROL__ ? (Integer) GraphicController.getController().getProperty(id, GraphicObjectProperties.__GO_STYLE__) : -1);
966         if (id.intValue() != figure.getIdentifier().intValue()
967                 && ((type == GraphicObjectProperties.__GO_UICONTROL__ && objectStyle != GraphicObjectProperties.__GO_UI_FRAME__)
968                     || type == GraphicObjectProperties.__GO_UIMENU__)) {
969             return;
970         }
971
972         if (property == GraphicObjectProperties.__GO_CHILDREN__) {
973             if (id.intValue() != figure.getIdentifier().intValue()) {
974                 /* Ignore children that are not mine */
975                 return;
976             }
977             Integer[] children = GraphicController.getController().getObjectFromId(id).getChildren();
978             List<Integer> currentOpenGLChildren = openGLChildren.get(id);
979             if (currentOpenGLChildren == null) {
980                 /* No openGLChildren in cache, create empty one */
981                 openGLChildren.put(id, new ArrayList<Integer>());
982                 currentOpenGLChildren = openGLChildren.get(id);
983             }
984             List<Integer> updatedOpenGLChildren = new ArrayList<Integer>();
985             for (int i = 0 ; i < children.length ; ++i) {
986                 Integer currentType = (Integer) GraphicController.getController().getProperty(children[i], GraphicObjectProperties.__GO_TYPE__);
987                 if (currentType != GraphicObjectProperties.__GO_UICONTROL__ && currentType != GraphicObjectProperties.__GO_UIMENU__) {
988                     updatedOpenGLChildren.add(children[i]);
989                 }
990             }
991             if (currentOpenGLChildren.size() == updatedOpenGLChildren.size()) {
992                 /* No change made on openGL children => nothing to do */
993                 return;
994             } else {
995                 openGLChildren.put(id, updatedOpenGLChildren);
996             }
997         }
998
999         try {
1000             if (needUpdate(id, property)) {
1001                 if (GraphicObjectProperties.__GO_COLORMAP__ == property) {
1002                     labelManager.disposeAll();
1003                     dataManager.disposeAllColorBuffers();
1004                     dataManager.disposeAllTextureCoordinatesBuffers();
1005                     markManager.disposeAll();
1006                     textManager.disposeAll();
1007                     axesDrawer.disposeAll();
1008                     fecDrawer.updateAll();
1009                     colorMapTextureDataProvider.update();
1010                     datatipTextDrawer.disposeAll();
1011                     textureManager.disposeAll();
1012                 } else {
1013                     labelManager.update(id, property);
1014                     dataManager.update(id, property);
1015                     markManager.update(id, property);
1016                     textManager.update(id, property);
1017                     axesDrawer.update(id, property);
1018                     legendDrawer.update(id, property);
1019                     fecDrawer.update(id, property);
1020                     datatipTextDrawer.update(id, property);
1021                 }
1022
1023                 if (GraphicObjectProperties.__GO_ANTIALIASING__ == property) {
1024                     canvas.setAntiAliasingLevel(figure.getAntialiasing());
1025                 }
1026
1027                 Figure parentFigure = (Figure) GraphicController.getController().getObjectFromId(figure.getParentFigure());
1028                 if (figure.getVisible() && parentFigure != null && parentFigure.getVisible()) {
1029                     if (isImmediateDrawing(id)) {
1030                         if (GraphicObjectProperties.__GO_IMMEDIATE_DRAWING__ == property) {
1031                             canvas.redrawAndWait();
1032                         } else {
1033                             canvas.redraw();
1034                         }
1035                     }
1036                 }
1037             }
1038
1039             if (GraphicObjectProperties.__GO_IMMEDIATE_DRAWING__ == property && !isImmediateDrawing(id)) {
1040                 canvas.waitImage();
1041             }
1042
1043         } catch (OutOfMemoryException e) {
1044             invalidate(GraphicController.getController().getObjectFromId(id), e);
1045         } catch (ObjectRemovedException e) {
1046             // Object has been removed before draw : do nothing.
1047         }
1048     }
1049
1050     /**
1051      * Check if the given changed property make the figure out of date.
1052      * @param id the object updated
1053      * @param property the changed property.
1054      * @return true id the given changed property make the figure out of date.
1055      */
1056     protected boolean needUpdate(Integer id, int property) {
1057         GraphicObject object = GraphicController.getController().getObjectFromId(id);
1058         int objectType = (Integer) GraphicController.getController().getProperty(id, GraphicObjectProperties.__GO_TYPE__);
1059         int objectStyle = (objectType == GraphicObjectProperties.__GO_UICONTROL__ ? (Integer) GraphicController.getController().getProperty(id, GraphicObjectProperties.__GO_STYLE__) : -1);
1060         if ((object != null) && isFigureChild(id) || (objectType == GraphicObjectProperties.__GO_UICONTROL__ && objectStyle == GraphicObjectProperties.__GO_UI_FRAME__)
1061                 && objectType != GraphicObjectProperties.__GO_UIMENU__ && objectType != GraphicObjectProperties.__GO_UI_FRAME_BORDER__) {
1062
1063             if (GraphicObjectProperties.__GO_VALID__ == property) {
1064                 return false;
1065             }
1066
1067             if (object instanceof Axes) {
1068                 Axes axes = (Axes) object;
1069
1070                 if ((axes.getXAxisAutoTicks() && X_AXIS_TICKS_PROPERTIES.contains(property)) ||
1071                         (axes.getYAxisAutoTicks() && Y_AXIS_TICKS_PROPERTIES.contains(property)) ||
1072                         (axes.getZAxisAutoTicks() && Z_AXIS_TICKS_PROPERTIES.contains(property))) {
1073                     return false;
1074                 }
1075
1076                 if ((!axes.getXAxisAutoTicks() && X_AXIS_TICKS_PROPERTIES.contains(property)) ||
1077                         (!axes.getYAxisAutoTicks() && Y_AXIS_TICKS_PROPERTIES.contains(property)) ||
1078                         (!axes.getZAxisAutoTicks() && Z_AXIS_TICKS_PROPERTIES.contains(property))) {
1079                     axesDrawer.computeMargins(axes);
1080                     return true;
1081                 }
1082
1083                 if (property != GraphicObjectProperties.__GO_CHILDREN__) {
1084                     axesDrawer.computeRulers(axes);
1085                 }
1086             }
1087
1088             if (object instanceof Label || object instanceof Legend) {
1089                 GraphicObject parent = GraphicController.getController().getObjectFromId(object.getParent());
1090                 if (parent instanceof Axes) {
1091                     Axes axes = (Axes) parent;
1092                     if (axes.getXAxisLabel().equals(id) ||
1093                             axes.getYAxisLabel().equals(id) ||
1094                             axes.getZAxisLabel().equals(id) ||
1095                             axes.getTitle().equals(id)) {
1096                         labelManager.update(id, property);
1097                         axesDrawer.computeMargins(axes);
1098                     } else if (object instanceof Legend && (property == GraphicObjectProperties.__GO_LEGEND_LOCATION__ || property == GraphicObjectProperties.__GO_LINE_WIDTH__)) {
1099                         legendDrawer.update(id, property);
1100                         axesDrawer.computeMargins(axes);
1101                     }
1102                 }
1103             } else if (object instanceof Figure) {
1104                 if (property == GraphicObjectProperties.__GO_SIZE__
1105                         || property == GraphicObjectProperties.__GO_AXES_SIZE__
1106                         || property == GraphicObjectProperties.__GO_CHILDREN__
1107                         || property == GraphicObjectProperties.__GO_POSITION__) {
1108                     Figure fig = (Figure) object;
1109                     for (Integer gid : fig.getChildren()) {
1110                         GraphicObject go = GraphicController.getController().getObjectFromId(gid);
1111                         if (go instanceof Axes) {
1112                             axesDrawer.computeRulers((Axes) go);
1113                         }
1114                     }
1115                 }
1116
1117                 if (SILENT_FIGURE_PROPERTIES.contains(property)) {
1118                     return false;
1119                 }
1120             } else if (object instanceof Frame
1121                        && id.intValue() == figure.getIdentifier().intValue()
1122                        && property == GraphicObjectProperties.__GO_POSITION__) {
1123                 Frame fig = (Frame) object;
1124                 for (Integer gid : fig.getChildren()) {
1125                     GraphicObject go = GraphicController.getController().getObjectFromId(gid);
1126                     if (go instanceof Axes) {
1127                         axesDrawer.computeRulers((Axes) go);
1128                     }
1129                 }
1130
1131             } else if (object instanceof Axes && property == GraphicObjectProperties.__GO_X_AXIS_LOCATION__ ||
1132                        property == GraphicObjectProperties.__GO_Y_AXIS_LOCATION__ || property == GraphicObjectProperties.__GO_AUTO_MARGINS__) {
1133                 axesDrawer.computeMargins((Axes) object);
1134             }
1135
1136             if (!object.isValid()) {
1137                 GraphicController.getController().setProperty(id, GraphicObjectProperties.__GO_VALID__, true);
1138             }
1139
1140             return true;
1141         }
1142         // Special case if top level figure colormap/immediate_drawing has been updated, force redraw
1143         if ((property == GraphicObjectProperties.__GO_COLORMAP__ ||  property == GraphicObjectProperties.__GO_IMMEDIATE_DRAWING__)
1144                 && id.intValue() == figure.getParentFigure().intValue()) {
1145             return true;
1146         }
1147         return false;
1148     }
1149
1150     private boolean isImmediateDrawing(Integer id) {
1151         Integer parentId = (Integer) GraphicController.getController().getProperty(id, GraphicObjectProperties.__GO_PARENT_FIGURE__);
1152         if (figure instanceof Frame) {
1153             parentId = figure.getParentFigure();
1154         }
1155         if (figure instanceof Figure && (parentId == null || !parentId.equals(figure.getIdentifier()))) {
1156             return false;
1157         } else {
1158             Boolean b =  (Boolean) GraphicController.getController().getProperty(parentId, GraphicObjectProperties.__GO_IMMEDIATE_DRAWING__);
1159             return (b == null) ? false : b;
1160         }
1161     }
1162
1163     @Override
1164     public void createObject(Integer id) {
1165     }
1166
1167     @Override
1168     public void deleteObject(Integer id) {
1169         Integer type = (Integer) GraphicController.getController().getProperty(id, GraphicObjectProperties.__GO_TYPE__);
1170         if (!figure.getIdentifier().equals(id) && type == GraphicObjectProperties.__GO_UICONTROL__ || type == GraphicObjectProperties.__GO_UIMENU__) {
1171             return; // Not of my managed openGL children
1172         }
1173
1174         openGLChildren.remove(id);
1175
1176         if (isImmediateDrawing(id)) {
1177             canvas.redraw();
1178         }
1179
1180         dataManager.dispose(id);
1181         markManager.dispose(id);
1182         textManager.dispose(id);
1183         labelManager.dispose(id);
1184         axesDrawer.dispose(id);
1185         legendDrawer.dispose(id);
1186         fecDrawer.dispose(id);
1187         textureManager.dispose(id);
1188         /*
1189          * Check we are deleting Figure managed by DrawerVisitor(this)
1190          * Otherwise do nothing on deletion.
1191          */
1192         if (!figure.getIdentifier().equals(id)) {
1193             return;
1194         }
1195
1196         visitorMap.remove(id);
1197         GraphicController.getController().unregister(this);
1198         if (SwingUtilities.isEventDispatchThread()) {
1199             canvas.destroy();
1200         } else {
1201             try {
1202                 SwingUtilities.invokeAndWait(new Runnable() {
1203                     public void run() {
1204                         canvas.destroy();
1205                     }
1206                 });
1207             } catch (Exception e) { }
1208         }
1209     }
1210
1211     /**
1212      * Check if the given id correspond to a child of the current {@see Figure}.
1213      * @param id the given id.
1214      * @return true if the given id correspond to a child of the current {@see Figure}.
1215      */
1216     private boolean isFigureChild(Integer id) {
1217         if (id.intValue() == figure.getIdentifier().intValue()) {
1218             return true;
1219         }
1220
1221         Object parentObject = GraphicController.getController().getProperty(id, GraphicObjectProperties.__GO_PARENT__);
1222         Integer parentUID = parentObject == null ? 0 : (Integer) parentObject;
1223         while (parentUID != 0) {
1224
1225             if (figure.getIdentifier().intValue() == parentUID.intValue()) {
1226                 return true;
1227             }
1228
1229             Integer parentStyle = (Integer) GraphicController.getController().getProperty(parentUID, GraphicObjectProperties.__GO_STYLE__);
1230             if (parentStyle != null && parentStyle.intValue() == GraphicObjectProperties.__GO_UI_FRAME__) {
1231                 // Drop drawing if parent is a Frame and I'm not the dedicated visitor.
1232                 return false;
1233             }
1234
1235             parentObject = GraphicController.getController().getProperty(parentUID, GraphicObjectProperties.__GO_PARENT__);
1236             parentUID = parentObject == null ? 0 : (Integer) parentObject;
1237
1238         }
1239         return false;
1240     }
1241
1242     /**
1243      * Invalidate the given graphic object and inform the user.
1244      * @param graphicObject the graphic object to invalidate
1245      * @param exception the cause of invalidation.
1246      */
1247     public void invalidate(GraphicObject graphicObject, Exception exception) {
1248         if (DEBUG_MODE) {
1249             System.err.println("The " + graphicObject.getType() + " \"" + graphicObject.getIdentifier()
1250                                + "\" has been invalidated: " + exception.getMessage());
1251             exception.printStackTrace();
1252         }
1253         GraphicController.getController().setProperty(graphicObject.getIdentifier(), GraphicObjectProperties.__GO_VALID__, false);
1254     }
1255
1256     public LabelManager getLabelManager() {
1257         return labelManager;
1258     }
1259
1260     public Texture getColorMapTexture() {
1261         if (colorMapTexture == null) {
1262             colorMapTexture = canvas.getTextureManager().createTexture();
1263             colorMapTexture.setMagnificationFilter(Texture.Filter.NEAREST);
1264             colorMapTexture.setMinifyingFilter(Texture.Filter.NEAREST);
1265             colorMapTexture.setSWrappingMode(Texture.Wrap.CLAMP);
1266             colorMapTexture.setTWrappingMode(Texture.Wrap.CLAMP);
1267             colorMapTexture.setDataProvider(colorMapTextureDataProvider);
1268         }
1269         return colorMapTexture;
1270     }
1271
1272     /**
1273      * Figure getter.
1274      * @return the figure this visitor draw.
1275      */
1276     public AxesContainer getFigure() {
1277         return figure;
1278     }
1279
1280     public Axes getAxes() {
1281         return currentAxes;
1282     }
1283
1284     private Geometry cube;
1285     public Geometry getCube() {
1286         if (cube == null) {
1287             cube = CubeFactory.createCube(canvas);
1288         }
1289         return cube;
1290     }
1291
1292     /**
1293      * Component getter.
1294      * @return return the attached component.
1295      */
1296     public Component getComponent() {
1297         return component;
1298     }
1299
1300     /**
1301      * Interaction manager getter
1302      * @return the interaction manager.
1303      */
1304     public InteractionManager getInteractionManager() {
1305         return interactionManager;
1306     }
1307
1308     private class ColorMapTextureDataProvider extends AbstractTextureDataProvider {
1309         byte[] whiteColor = {(byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF};
1310         byte[] blackColor = {0x00, 0x00, 0x00, (byte) 0xFF};
1311
1312         public ColorMapTextureDataProvider() {
1313             super();
1314             this.imageType = ImageType.RGBA_BYTE;
1315         }
1316
1317         @Override
1318         public Dimension getTextureSize() {
1319             return new Dimension(colorMap.getSize() + 2, 1);
1320         }
1321
1322         @Override
1323         public ByteBuffer getData() {
1324             Double[] data = colorMap.getData();
1325             ByteBuffer buffer = ByteBuffer.allocate(4 * ((data.length / 3) + 2));
1326
1327             /* White and black are written in the first and second positions */
1328             buffer.put(whiteColor);
1329             buffer.put(blackColor);
1330
1331             for (int i = 0 ; i < data.length / 3 ; i++) {
1332                 buffer.put(toByte(data[i]));
1333                 buffer.put(toByte(data[i + colorMap.getSize()].floatValue()));
1334                 buffer.put(toByte(data[i + 2 * colorMap.getSize()].floatValue()));
1335                 buffer.put(toByte(1));
1336             }
1337             buffer.rewind();
1338             return buffer;
1339         }
1340
1341         @Override
1342         public ByteBuffer getSubData(int x, int y, int width, int height) {
1343             /*
1344              * For the moment, we presuppose that x and y are 0 and that
1345              * width is equal to the colormap's total size (with height == 1).
1346              * To be correctly implemented.
1347              */
1348             return getData();
1349         }
1350
1351         @Override
1352         public boolean isValid() {
1353             return true;
1354         }
1355
1356         public void update() {
1357             fireUpdate();
1358         }
1359     }
1360 }