be5d6bf91dc7639bd4dd4fe7e63f096b25d077ec
[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                 if (datatip.getMarkMode()) {
940                     /* TODO: appearance can be not-null */
941                     Texture texture = markManager.getMarkSprite(datatip, colorMap, null);
942                     Vector3d markPos = DatatipTextDrawer.calculateAnchorPoint(datatip);
943                     drawingTools.draw(texture, AnchorPosition.CENTER, markPos);
944                 }
945                 if (datatip.getTipLabelMode()) {
946                     datatipTextDrawer.draw(drawingTools, colorMap, datatip);
947                 }
948             } catch (SciRendererException e) {
949                 invalidate((Text)datatip, e);
950             }
951             axesDrawer.disableClipping(datatip.getClipProperty());
952         }
953     }
954
955     @Override
956     public void visit(Arrow arrow) {
957         // TODO
958         System.out.println("How can I draw an arrow ?");
959     }
960
961     @Override
962     public void visit(final Champ champ) {
963         if (champ.isValid() && champ.getVisible()) {
964             axesDrawer.enableClipping(currentAxes, champ.getClipProperty());
965             try {
966                 DefaultGeometry segments = new DefaultGeometry();
967                 segments.setFillDrawingMode(Geometry.FillDrawingMode.NONE);
968                 segments.setLineDrawingMode(Geometry.LineDrawingMode.SEGMENTS);
969                 segments.setVertices(dataManager.getVertexBuffer(champ.getIdentifier()));
970                 segments.setWireIndices(dataManager.getWireIndexBuffer(champ.getIdentifier()));
971                 segments.setFaceCullingMode(Geometry.FaceCullingMode.BOTH);
972                 if (champ.getColored()) {
973                     segments.setColors(dataManager.getColorBuffer(champ.getIdentifier()));
974                 } else {
975                     segments.setColors(null);
976                 }
977
978                 if (champ.getLineMode()) {
979                     Appearance segmentAppearance = new Appearance();
980
981                     /* If not colored, all segments have the same color. */
982                     if (champ.getColored()) {
983                         segmentAppearance.setLineColor(null);
984                     } else {
985                         segmentAppearance.setLineColor(ColorFactory.createColor(colorMap, champ.getLineColor()));
986                     }
987
988                     segmentAppearance.setLineWidth(champ.getLineThickness().floatValue());
989                     segmentAppearance.setLinePattern(champ.getLineStyleAsEnum().asPattern());
990                     drawingTools.draw(segments, segmentAppearance);
991                 }
992
993                 /* Draw the arrows */
994                 if (champ.getArrowSize() != 0.0) {
995                     arrowDrawer.drawArrows(champ.getParentAxes(), champ.getIdentifier(), champ.getArrowSize(), champ.getLineThickness(), false,
996                                            champ.getColored(), champ.getLineColor(), false);
997                 }
998             } catch (OutOfMemoryException e) {
999                 invalidate(champ, e);
1000             } catch (ObjectRemovedException e) {
1001                 invalidate(champ, e);
1002             } catch (SciRendererException e) {
1003                 invalidate(champ, e);
1004             }
1005             axesDrawer.disableClipping(champ.getClipProperty());
1006         }
1007     }
1008
1009     @Override
1010     public void visit(final Segs segs) {
1011         if (segs.isValid() && segs.getVisible() && segs.getArrows().size() != 0) {
1012             axesDrawer.enableClipping(currentAxes, segs.getClipProperty());
1013             try {
1014                 DefaultGeometry segments = new DefaultGeometry();
1015                 segments.setFillDrawingMode(Geometry.FillDrawingMode.NONE);
1016                 segments.setLineDrawingMode(Geometry.LineDrawingMode.SEGMENTS);
1017                 segments.setVertices(dataManager.getVertexBuffer(segs.getIdentifier()));
1018                 segments.setColors(dataManager.getColorBuffer(segs.getIdentifier()));
1019                 segments.setWireIndices(dataManager.getWireIndexBuffer(segs.getIdentifier()));
1020                 segments.setFaceCullingMode(Geometry.FaceCullingMode.BOTH);
1021
1022                 if (segs.getLineMode()) {
1023                     Appearance segmentAppearance = new Appearance();
1024                     segmentAppearance.setLineColor(null);
1025                     segmentAppearance.setLineWidth(segs.getLineThickness().floatValue());
1026                     segmentAppearance.setLinePattern(segs.getLineStyleAsEnum().asPattern());
1027                     drawingTools.draw(segments, segmentAppearance);
1028                 }
1029
1030                 /*
1031                  * Segs does not derive from ContouredObject but Arrow does, hence we have to get the former's first Arrow
1032                  * in order to obtain the latter's Mark (all arrows are supposed to have the same contour properties for now).
1033                  */
1034                 if (segs.getMarkMode()) {
1035                     ElementsBuffer positions = dataManager.getVertexBuffer(segs.getIdentifier());
1036                     // Take only into account start-end of segs and not the arrow head.
1037                     positions.getData().limit(segs.getNumberArrows() * 2 * 4);
1038
1039                     if (segs.getArrows().get(0).getMark().getBackground() == -3 || segs.getArrows().get(0).getMark().getForeground() == -3) {
1040                         Texture sprite = markManager.getMarkSprite(segs.getIdentifier(), segs.getArrows().get(0).getMark(), null, null);
1041                         ElementsBuffer colors = dataManager.getColorBuffer(segs.getIdentifier());
1042                         Color auxColor;
1043                         if (segs.getArrows().get(0).getMark().getBackground() == -3) {
1044                             auxColor = ColorFactory.createColor(colorMap, segs.getArrows().get(0).getMark().getForeground());
1045                         } else {
1046                             auxColor = ColorFactory.createColor(colorMap, segs.getArrows().get(0).getMark().getBackground());
1047                         }
1048                         drawingTools.draw(sprite, AnchorPosition.CENTER, positions, auxColor, colors);
1049                     } else {
1050                         Texture sprite = markManager.getMarkSprite(segs.getIdentifier(), segs.getArrows().get(0).getMark(), colorMap, null);
1051                         drawingTools.draw(sprite, AnchorPosition.CENTER, positions, null, null);
1052                     }
1053
1054                     positions.getData().limit(positions.getData().capacity());
1055                 }
1056
1057                 /* Draw the arrows */
1058                 if (segs.getArrowSize() != 0.0) {
1059                     arrowDrawer.drawArrows(segs.getParentAxes(), segs.getIdentifier(), segs.getArrowSize(), segs.getLineThickness(), true,
1060                                            true, segs.getLineColor(), false);
1061                 }
1062             } catch (OutOfMemoryException e) {
1063                 invalidate(segs, e);
1064             } catch (ObjectRemovedException e) {
1065                 invalidate(segs, e);
1066             } catch (SciRendererException e) {
1067                 invalidate(segs, e);
1068             }
1069             axesDrawer.disableClipping(segs.getClipProperty());
1070         }
1071     }
1072
1073     @Override
1074     public void updateObject(Integer id, int property) {
1075         /*
1076          * Check if property is CHILDREN and if there is a new child I should care about
1077          */
1078         Integer type = (Integer) GraphicController.getController().getProperty(id, GraphicObjectProperties.__GO_TYPE__);
1079         int objectStyle = (type == GraphicObjectProperties.__GO_UICONTROL__ ? (Integer) GraphicController.getController().getProperty(id, GraphicObjectProperties.__GO_STYLE__) : -1);
1080         if (id.intValue() != figure.getIdentifier().intValue()
1081                 && ((type == GraphicObjectProperties.__GO_UICONTROL__ && objectStyle != GraphicObjectProperties.__GO_UI_FRAME__)
1082                     || type == GraphicObjectProperties.__GO_UIMENU__)) {
1083             return;
1084         }
1085
1086         if (property == GraphicObjectProperties.__GO_CHILDREN__) {
1087             if (id.intValue() != figure.getIdentifier().intValue()) {
1088                 /* Ignore children that are not mine */
1089                 return;
1090             }
1091             Integer[] children = GraphicController.getController().getObjectFromId(id).getChildren();
1092             List<Integer> currentOpenGLChildren = openGLChildren.get(id);
1093             if (currentOpenGLChildren == null) {
1094                 /* No openGLChildren in cache, create empty one */
1095                 openGLChildren.put(id, new ArrayList<Integer>());
1096                 currentOpenGLChildren = openGLChildren.get(id);
1097             }
1098             List<Integer> updatedOpenGLChildren = new ArrayList<Integer>();
1099             for (int i = 0 ; i < children.length ; ++i) {
1100                 Integer currentType = (Integer) GraphicController.getController().getProperty(children[i], GraphicObjectProperties.__GO_TYPE__);
1101                 if (currentType != GraphicObjectProperties.__GO_UICONTROL__ && currentType != GraphicObjectProperties.__GO_UIMENU__) {
1102                     updatedOpenGLChildren.add(children[i]);
1103                 }
1104             }
1105             if (currentOpenGLChildren.size() == updatedOpenGLChildren.size()) {
1106                 /* No change made on openGL children => nothing to do */
1107                 return;
1108             } else {
1109                 openGLChildren.put(id, updatedOpenGLChildren);
1110             }
1111         }
1112
1113         try {
1114             if (needUpdate(id, property)) {
1115                 if (GraphicObjectProperties.__GO_COLORMAP__ == property) {
1116                     labelManager.disposeAll();
1117                     dataManager.disposeAllColorBuffers();
1118                     dataManager.disposeAllTextureCoordinatesBuffers();
1119                     markManager.disposeAll();
1120                     textManager.disposeAll();
1121                     axesDrawer.disposeAll();
1122                     fecDrawer.updateAll();
1123                     colorMapTextureDataProvider.update();
1124                     datatipTextDrawer.disposeAll();
1125                     textureManager.disposeAll();
1126                 } else {
1127                     labelManager.update(id, property);
1128                     dataManager.update(id, property);
1129                     markManager.update(id, property);
1130                     textManager.update(id, property);
1131                     axesDrawer.update(id, property);
1132                     legendDrawer.update(id, property);
1133                     fecDrawer.update(id, property);
1134                     datatipTextDrawer.update(id, property);
1135                 }
1136
1137                 if (GraphicObjectProperties.__GO_ANTIALIASING__ == property) {
1138                     canvas.setAntiAliasingLevel(figure.getAntialiasing());
1139                 }
1140
1141                 Figure parentFigure = (Figure) GraphicController.getController().getObjectFromId(figure.getParentFigure());
1142                 if (figure.getVisible() && parentFigure != null && parentFigure.getVisible()) {
1143                     if (isImmediateDrawing(id)) {
1144                         if (GraphicObjectProperties.__GO_IMMEDIATE_DRAWING__ == property) {
1145                             canvas.redrawAndWait();
1146                         } else {
1147                             canvas.redraw();
1148                         }
1149                     }
1150                 }
1151             }
1152
1153             if (GraphicObjectProperties.__GO_IMMEDIATE_DRAWING__ == property && !isImmediateDrawing(id)) {
1154                 canvas.waitImage();
1155             }
1156
1157         } catch (OutOfMemoryException e) {
1158             invalidate(GraphicController.getController().getObjectFromId(id), e);
1159         } catch (ObjectRemovedException e) {
1160             // Object has been removed before draw : do nothing.
1161         }
1162     }
1163
1164     /**
1165      * Check if the given changed property make the figure out of date.
1166      * @param id the object updated
1167      * @param property the changed property.
1168      * @return true id the given changed property make the figure out of date.
1169      */
1170     protected boolean needUpdate(Integer id, int property) {
1171         GraphicObject object = GraphicController.getController().getObjectFromId(id);
1172         int objectType = (Integer) GraphicController.getController().getProperty(id, GraphicObjectProperties.__GO_TYPE__);
1173         int objectStyle = (objectType == GraphicObjectProperties.__GO_UICONTROL__ ? (Integer) GraphicController.getController().getProperty(id, GraphicObjectProperties.__GO_STYLE__) : -1);
1174         if ((object != null) && (isFigureChild(id) || isFigureParent(id)) || (objectType == GraphicObjectProperties.__GO_UICONTROL__ && objectStyle == GraphicObjectProperties.__GO_UI_FRAME__)
1175                 && objectType != GraphicObjectProperties.__GO_UIMENU__ && objectType != GraphicObjectProperties.__GO_UI_FRAME_BORDER__) {
1176
1177             if (GraphicObjectProperties.__GO_VALID__ == property) {
1178                 return false;
1179             }
1180
1181             if (object instanceof Axes) {
1182                 Axes axes = (Axes) object;
1183
1184                 if ((axes.getXAxisAutoTicks() && X_AXIS_TICKS_PROPERTIES.contains(property)) ||
1185                         (axes.getYAxisAutoTicks() && Y_AXIS_TICKS_PROPERTIES.contains(property)) ||
1186                         (axes.getZAxisAutoTicks() && Z_AXIS_TICKS_PROPERTIES.contains(property))) {
1187                     return false;
1188                 }
1189
1190                 if ((!axes.getXAxisAutoTicks() && X_AXIS_TICKS_PROPERTIES.contains(property)) ||
1191                         (!axes.getYAxisAutoTicks() && Y_AXIS_TICKS_PROPERTIES.contains(property)) ||
1192                         (!axes.getZAxisAutoTicks() && Z_AXIS_TICKS_PROPERTIES.contains(property))) {
1193                     axesDrawer.computeMargins(axes);
1194                     return true;
1195                 }
1196
1197                 if (property != GraphicObjectProperties.__GO_CHILDREN__) {
1198                     axesDrawer.computeRulers(axes);
1199                 }
1200             }
1201
1202             if (object instanceof Label || object instanceof Legend) {
1203                 GraphicObject parent = GraphicController.getController().getObjectFromId(object.getParent());
1204                 if (parent instanceof Axes) {
1205                     Axes axes = (Axes) parent;
1206                     if (axes.getXAxisLabel().equals(id) ||
1207                             axes.getYAxisLabel().equals(id) ||
1208                             axes.getZAxisLabel().equals(id) ||
1209                             axes.getTitle().equals(id)) {
1210                         labelManager.update(id, property);
1211                         axesDrawer.computeMargins(axes);
1212                     } else if (object instanceof Legend && (property == GraphicObjectProperties.__GO_LEGEND_LOCATION__ || property == GraphicObjectProperties.__GO_LINE_WIDTH__)) {
1213                         legendDrawer.update(id, property);
1214                         axesDrawer.computeMargins(axes);
1215                     }
1216                 }
1217             } else if (object instanceof Figure) {
1218                 if (property == GraphicObjectProperties.__GO_SIZE__
1219                         || property == GraphicObjectProperties.__GO_AXES_SIZE__
1220                         || property == GraphicObjectProperties.__GO_CHILDREN__
1221                         || property == GraphicObjectProperties.__GO_POSITION__
1222                         || property == GraphicObjectProperties.__GO_VISIBLE__) {
1223                     for (Integer gid : figure.getChildren()) {
1224                         GraphicObject go = GraphicController.getController().getObjectFromId(gid);
1225                         if (go instanceof Axes) {
1226                             axesDrawer.computeMargins((Axes) go);
1227                             axesDrawer.computeRulers((Axes) go);
1228                         }
1229                     }
1230                 }
1231
1232                 if (SILENT_FIGURE_PROPERTIES.contains(property)) {
1233                     return false;
1234                 }
1235             } else if (object instanceof Frame
1236                        && id.intValue() == figure.getIdentifier().intValue()
1237                        && property == GraphicObjectProperties.__GO_POSITION__) {
1238                 Frame fig = (Frame) object;
1239                 for (Integer gid : fig.getChildren()) {
1240                     GraphicObject go = GraphicController.getController().getObjectFromId(gid);
1241                     if (go instanceof Axes) {
1242                         axesDrawer.computeRulers((Axes) go);
1243                     }
1244                 }
1245
1246             } else if (object instanceof Axes && property == GraphicObjectProperties.__GO_X_AXIS_LOCATION__ ||
1247                        property == GraphicObjectProperties.__GO_Y_AXIS_LOCATION__ || property == GraphicObjectProperties.__GO_AUTO_MARGINS__) {
1248                 axesDrawer.computeMargins((Axes) object);
1249             }
1250
1251             if (!object.isValid()) {
1252                 GraphicController.getController().setProperty(id, GraphicObjectProperties.__GO_VALID__, true);
1253             }
1254
1255             return true;
1256         }
1257         // Special case if top level figure colormap/immediate_drawing has been updated, force redraw
1258         if ((property == GraphicObjectProperties.__GO_COLORMAP__ ||  property == GraphicObjectProperties.__GO_IMMEDIATE_DRAWING__)
1259                 && id.intValue() == figure.getParentFigure().intValue()) {
1260             return true;
1261         }
1262         return false;
1263     }
1264
1265     private boolean isImmediateDrawing(Integer id) {
1266         Integer parentId = (Integer) GraphicController.getController().getProperty(id, GraphicObjectProperties.__GO_PARENT_FIGURE__);
1267         if (figure instanceof Frame) {
1268             parentId = figure.getParentFigure();
1269         }
1270         if (figure instanceof Figure && (parentId == null || !parentId.equals(figure.getIdentifier()))) {
1271             return false;
1272         } else {
1273             Boolean b =  (Boolean) GraphicController.getController().getProperty(parentId, GraphicObjectProperties.__GO_IMMEDIATE_DRAWING__);
1274             return (b == null) ? false : b;
1275         }
1276     }
1277
1278     @Override
1279     public void createObject(Integer id) {
1280     }
1281
1282     @Override
1283     public void deleteObject(Integer id) {
1284         Integer type = (Integer) GraphicController.getController().getProperty(id, GraphicObjectProperties.__GO_TYPE__);
1285         if (!figure.getIdentifier().equals(id) && type == GraphicObjectProperties.__GO_UICONTROL__ || type == GraphicObjectProperties.__GO_UIMENU__) {
1286             return; // Not of my managed openGL children
1287         }
1288
1289         openGLChildren.remove(id);
1290
1291         if (isImmediateDrawing(id)) {
1292             canvas.redraw();
1293         }
1294
1295         dataManager.dispose(id);
1296         markManager.dispose(id);
1297         textManager.dispose(id);
1298         labelManager.dispose(id);
1299         axesDrawer.dispose(id);
1300         legendDrawer.dispose(id);
1301         fecDrawer.dispose(id);
1302         textureManager.dispose(id);
1303         /*
1304          * Check we are deleting Figure managed by DrawerVisitor(this)
1305          * Otherwise do nothing on deletion.
1306          */
1307         if (!figure.getIdentifier().equals(id)) {
1308             return;
1309         }
1310
1311         visitorMap.remove(id);
1312         GraphicController.getController().unregister(this);
1313         if (SwingUtilities.isEventDispatchThread()) {
1314             canvas.destroy();
1315         } else {
1316             try {
1317                 SwingUtilities.invokeAndWait(new Runnable() {
1318                     public void run() {
1319                         canvas.destroy();
1320                     }
1321                 });
1322             } catch (Exception e) { }
1323         }
1324     }
1325
1326     /**
1327      * Check if the given id correspond to a parent of the current {@see Figure}.
1328      * @param id the given id.
1329      * @return true if the given id correspond to a parent of the current {@see Figure}.
1330      */
1331     private boolean isFigureParent(Integer id) {
1332         GraphicObject object = GraphicController.getController().getObjectFromId(id);
1333         if (object != null) {
1334             Object parentObject = GraphicController.getController().getProperty(figure.getIdentifier(), GraphicObjectProperties.__GO_PARENT__);
1335             Integer parentUID = parentObject == null ? 0 : (Integer) parentObject;
1336             while (parentUID.intValue() != 0) {
1337                 if (parentUID.intValue() == id.intValue()) {
1338                     return true;
1339                 }
1340                 parentObject = GraphicController.getController().getProperty(parentUID, GraphicObjectProperties.__GO_PARENT__);
1341                 parentUID = parentObject == null ? 0 : (Integer) parentObject;
1342             }
1343         }
1344
1345         return false;
1346     }
1347
1348     /**
1349      * Check if the given id correspond to a child of the current {@see Figure}.
1350      * @param id the given id.
1351      * @return true if the given id correspond to a child of the current {@see Figure}.
1352      */
1353     private boolean isFigureChild(Integer id) {
1354         if (id.intValue() == figure.getIdentifier().intValue()) {
1355             return true;
1356         }
1357
1358         Object parentObject = GraphicController.getController().getProperty(id, GraphicObjectProperties.__GO_PARENT__);
1359         Integer parentUID = parentObject == null ? 0 : (Integer) parentObject;
1360         while (parentUID != 0) {
1361
1362             if (figure.getIdentifier().intValue() == parentUID.intValue()) {
1363                 return true;
1364             }
1365
1366             Integer parentStyle = (Integer) GraphicController.getController().getProperty(parentUID, GraphicObjectProperties.__GO_STYLE__);
1367             if (parentStyle != null && parentStyle.intValue() == GraphicObjectProperties.__GO_UI_FRAME__) {
1368                 // Drop drawing if parent is a Frame and I'm not the dedicated visitor.
1369                 return false;
1370             }
1371
1372             parentObject = GraphicController.getController().getProperty(parentUID, GraphicObjectProperties.__GO_PARENT__);
1373             parentUID = parentObject == null ? 0 : (Integer) parentObject;
1374
1375         }
1376         return false;
1377     }
1378
1379     /**
1380      * Invalidate the given graphic object and inform the user.
1381      * @param graphicObject the graphic object to invalidate
1382      * @param exception the cause of invalidation.
1383      */
1384     public void invalidate(GraphicObject graphicObject, Exception exception) {
1385         if (DEBUG_MODE) {
1386             System.err.println("The " + graphicObject.getType() + " \"" + graphicObject.getIdentifier()
1387                                + "\" has been invalidated: " + exception.getMessage());
1388             exception.printStackTrace();
1389         }
1390         GraphicController.getController().setProperty(graphicObject.getIdentifier(), GraphicObjectProperties.__GO_VALID__, false);
1391     }
1392
1393     public LabelManager getLabelManager() {
1394         return labelManager;
1395     }
1396
1397     public Texture getColorMapTexture() {
1398         if (colorMapTexture == null) {
1399             colorMapTexture = canvas.getTextureManager().createTexture();
1400             colorMapTexture.setMagnificationFilter(Texture.Filter.NEAREST);
1401             colorMapTexture.setMinifyingFilter(Texture.Filter.NEAREST);
1402             colorMapTexture.setSWrappingMode(Texture.Wrap.CLAMP);
1403             colorMapTexture.setTWrappingMode(Texture.Wrap.CLAMP);
1404             colorMapTexture.setDataProvider(colorMapTextureDataProvider);
1405         }
1406         return colorMapTexture;
1407     }
1408
1409     /**
1410      * Figure getter.
1411      * @return the figure this visitor draw.
1412      */
1413     public AxesContainer getFigure() {
1414         return figure;
1415     }
1416
1417     public Axes getAxes() {
1418         return currentAxes;
1419     }
1420
1421     private Geometry cube;
1422     public Geometry getCube() {
1423         if (cube == null) {
1424             cube = CubeFactory.createCube(canvas);
1425         }
1426         return cube;
1427     }
1428
1429     /**
1430      * Component getter.
1431      * @return return the attached component.
1432      */
1433     public Component getComponent() {
1434         return component;
1435     }
1436
1437     /**
1438      * Interaction manager getter
1439      * @return the interaction manager.
1440      */
1441     public InteractionManager getInteractionManager() {
1442         return interactionManager;
1443     }
1444
1445     private class ColorMapTextureDataProvider extends AbstractTextureDataProvider {
1446         byte[] whiteColor = {(byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF};
1447         byte[] blackColor = {0x00, 0x00, 0x00, (byte) 0xFF};
1448
1449         public ColorMapTextureDataProvider() {
1450             super();
1451             this.imageType = ImageType.RGBA_BYTE;
1452         }
1453
1454         @Override
1455         public Dimension getTextureSize() {
1456             return new Dimension(colorMap.getSize() + 2, 1);
1457         }
1458
1459         @Override
1460         public ByteBuffer getData() {
1461             Double[] data = colorMap.getData();
1462             ByteBuffer buffer = ByteBuffer.allocate(4 * ((data.length / 3) + 2));
1463
1464             /* White and black are written in the first and second positions */
1465             buffer.put(whiteColor);
1466             buffer.put(blackColor);
1467
1468             for (int i = 0 ; i < data.length / 3 ; i++) {
1469                 buffer.put(toByte(data[i]));
1470                 buffer.put(toByte(data[i + colorMap.getSize()].floatValue()));
1471                 buffer.put(toByte(data[i + 2 * colorMap.getSize()].floatValue()));
1472                 buffer.put(toByte(1));
1473             }
1474             buffer.rewind();
1475             return buffer;
1476         }
1477
1478         @Override
1479         public ByteBuffer getSubData(int x, int y, int width, int height) {
1480             /*
1481              * For the moment, we presuppose that x and y are 0 and that
1482              * width is equal to the colormap's total size (with height == 1).
1483              * To be correctly implemented.
1484              */
1485             return getData();
1486         }
1487
1488         @Override
1489         public boolean isValid() {
1490             return true;
1491         }
1492
1493         public void update() {
1494             fireUpdate();
1495         }
1496     }
1497 }