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