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