8499c7c551999b2b06fd40abd1055257f1bf29b0
[scilab.git] / scilab / modules / renderer / src / java / org / scilab / modules / renderer / JoGLView / DataManager.java
1 /*
2  * Scilab ( http://www.scilab.org/ ) - This file is part of Scilab
3  * Copyright (C) 2009-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 org.scilab.forge.scirenderer.Canvas;
15 import org.scilab.forge.scirenderer.buffers.ElementsBuffer;
16 import org.scilab.forge.scirenderer.buffers.IndicesBuffer;
17 import org.scilab.modules.graphic_objects.MainDataLoader;
18 import org.scilab.modules.graphic_objects.ObjectRemovedException;
19 import org.scilab.modules.graphic_objects.graphicController.GraphicController;
20 import org.scilab.modules.graphic_objects.graphicObject.GraphicObjectProperties;
21 import org.scilab.modules.renderer.JoGLView.util.BufferAllocation;
22 import org.scilab.modules.renderer.JoGLView.util.OutOfMemoryException;
23
24 import java.nio.FloatBuffer;
25 import java.nio.IntBuffer;
26 import java.util.Arrays;
27 import java.util.HashMap;
28 import java.util.HashSet;
29 import java.util.Map;
30 import java.util.Set;
31 import java.util.concurrent.ConcurrentHashMap;
32
33 /**
34  * @author Pierre Lando
35  */
36 public class DataManager {
37
38     /**
39      * Set of properties that affect Fac3d data.
40      */
41     private static final Set<Integer> FAC3D_DATA_PROPERTIES = new HashSet<Integer>(Arrays.asList(
42                 GraphicObjectProperties.__GO_DATA_MODEL__,
43                 GraphicObjectProperties.__GO_COLOR_FLAG__,
44                 GraphicObjectProperties.__GO_COLOR_MODE__,
45                 GraphicObjectProperties.__GO_DATA_MAPPING__
46             ));
47
48     /**
49      * Set of properties that affect Fec data.
50      */
51     private static final Set<Integer> FEC_DATA_PROPERTIES = new HashSet<Integer>(Arrays.asList(
52                 GraphicObjectProperties.__GO_DATA_MODEL__,
53                 GraphicObjectProperties.__GO_Z_BOUNDS__,
54                 GraphicObjectProperties.__GO_COLOR_RANGE__,
55                 GraphicObjectProperties.__GO_OUTSIDE_COLOR__
56             ));
57
58     /**
59      * Set of properties that affect Grayplot data.
60      */
61     private static final Set<Integer> GRAYPLOT_DATA_PROPERTIES = new HashSet<Integer>(Arrays.asList(
62                 GraphicObjectProperties.__GO_DATA_MODEL__,
63                 GraphicObjectProperties.__GO_DATA_MAPPING__
64             ));
65
66     /**
67      * Set of properties that affect Matplot data.
68      */
69     private static final Set<Integer> MATPLOT_DATA_PROPERTIES = new HashSet<Integer>(Arrays.asList(
70                 GraphicObjectProperties.__GO_DATA_MODEL__
71             ));
72
73     /**
74      * Set of properties that affect polyline data.
75      */
76     private static final Set<Integer> POLYLINE_DATA_PROPERTIES = new HashSet<Integer>(Arrays.asList(
77                 GraphicObjectProperties.__GO_DATA_MODEL__,
78                 GraphicObjectProperties.__GO_POLYLINE_STYLE__,
79                 GraphicObjectProperties.__GO_LINE_MODE__,
80                 GraphicObjectProperties.__GO_BAR_WIDTH__,
81                 GraphicObjectProperties.__GO_CLOSED__,
82                 GraphicObjectProperties.__GO_FILL_MODE__,
83                 GraphicObjectProperties.__GO_INTERP_COLOR_VECTOR__,
84                 GraphicObjectProperties.__GO_INTERP_COLOR_MODE__
85             ));
86
87     /**
88      * Set of properties that affect Plot3d data.
89      */
90     private static final Set<Integer> PLOT3D_DATA_PROPERTIES = new HashSet<Integer>(Arrays.asList(
91                 GraphicObjectProperties.__GO_DATA_MODEL__
92             ));
93
94     /**
95      * Set of properties that affect Arc data.
96      */
97     private static final Set<Integer> ARC_DATA_PROPERTIES = new HashSet<Integer>(Arrays.asList(
98                 GraphicObjectProperties.__GO_UPPER_LEFT_POINT__,
99                 GraphicObjectProperties.__GO_WIDTH__,
100                 GraphicObjectProperties.__GO_HEIGHT__,
101                 GraphicObjectProperties.__GO_START_ANGLE__,
102                 GraphicObjectProperties.__GO_END_ANGLE__
103             ));
104
105     /**
106      * Set of properties that affect Champ data.
107      */
108     private static final Set<Integer> CHAMP_DATA_PROPERTIES = new HashSet<Integer>(Arrays.asList(
109                 GraphicObjectProperties.__GO_BASE_X__,
110                 GraphicObjectProperties.__GO_BASE_Y__,
111                 GraphicObjectProperties.__GO_BASE_Z__,
112                 GraphicObjectProperties.__GO_DIRECTION_X__,
113                 GraphicObjectProperties.__GO_DIRECTION_Y__,
114                 GraphicObjectProperties.__GO_DIRECTION_Z__,
115                 GraphicObjectProperties.__GO_COLORED__
116             ));
117
118     /**
119      * Set of properties that affect Rectangle data.
120      */
121     private static final Set<Integer> RECTANGLE_DATA_PROPERTIES = new HashSet<Integer>(Arrays.asList(
122                 GraphicObjectProperties.__GO_UPPER_LEFT_POINT__,
123                 GraphicObjectProperties.__GO_WIDTH__,
124                 GraphicObjectProperties.__GO_HEIGHT__
125             ));
126
127     /**
128      * Set of properties that affect Segs data.
129      */
130     private static final Set<Integer> SEGS_DATA_PROPERTIES = new HashSet<Integer>(Arrays.asList(
131                 GraphicObjectProperties.__GO_BASE__,
132                 GraphicObjectProperties.__GO_DIRECTION__,
133                 GraphicObjectProperties.__GO_SEGS_COLORS__
134             ));
135
136     private static final double[] DEFAULT_SCALE     = new double[] {1, 1, 1};
137     private static final double[] DEFAULT_TRANSLATE = new double[] {0, 0, 0};
138
139     /*
140      * Bit mask specifying whether logarithmic coordinates are used.
141      * Temporarily defined as a constant for now and set to 0 (linear x, y and z coordinates).
142      * To do: pass it as an argument of fillVertexBuffer and fillWireIndexBuffer, when updating data.
143      */
144     private static final int DEFAULT_LOG_MASK = 0;
145
146
147     private final Map<String, ElementsBuffer> vertexBufferMap = new HashMap<String, ElementsBuffer>();
148     private final Map<String, ElementsBuffer> normalBufferMap = new HashMap<String, ElementsBuffer>();
149     private final Map<String, ElementsBuffer> colorBufferMap = new ConcurrentHashMap<String, ElementsBuffer>();
150     private final Map<String, ElementsBuffer> texturesCoordinatesBufferMap = new HashMap<String, ElementsBuffer>();
151     private final Map<String, IndicesBuffer> indexBufferMap = new HashMap<String, IndicesBuffer>();
152     private final Map<String, IndicesBuffer> wireIndexBufferMap = new HashMap<String, IndicesBuffer>();
153     private final Canvas canvas;
154
155
156     /**
157      * Default constructor.
158      * @param canvas the canvas where managed data live.
159      */
160     public DataManager(Canvas canvas) {
161         this.canvas = canvas;
162     }
163
164     /**
165      * Return the vertex buffer of the given object.
166      * @param id the given object Id.
167      * @return the vertex buffer of the given object.
168      * @throws ObjectRemovedException if the object is now longer present.
169      */
170     public ElementsBuffer getVertexBuffer(String id) throws ObjectRemovedException, OutOfMemoryException {
171         if (vertexBufferMap.containsKey(id)) {
172             return vertexBufferMap.get(id);
173         } else {
174             ElementsBuffer vertexBuffer = canvas.getBuffersManager().createElementsBuffer();
175             fillVertexBuffer(vertexBuffer, id);
176             vertexBufferMap.put(id, vertexBuffer);
177             return vertexBuffer;
178         }
179     }
180
181     /**
182      * Return the normal buffer of the given object.
183      * @param id the given object Id.
184      * @return the vertex buffer of the given object.
185      * @throws ObjectRemovedException if the object is now longer present.
186      */
187     public ElementsBuffer getNormalBuffer(String id) throws ObjectRemovedException, OutOfMemoryException {
188         if (normalBufferMap.containsKey(id)) {
189             return normalBufferMap.get(id);
190         } else {
191             ElementsBuffer normalBuffer = canvas.getBuffersManager().createElementsBuffer();
192             fillNormalBuffer(normalBuffer, id);
193             normalBufferMap.put(id, normalBuffer);
194             return normalBuffer;
195         }
196     }
197
198     /**
199      * Texture coordinates getter.
200      * @param identifier the graphic object id.
201      * @return the texture coordinates corresponding to the given graphic object.
202      * @throws ObjectRemovedException if the object is now longer present.
203      */
204     public ElementsBuffer getTextureCoordinatesBuffer(String identifier) throws ObjectRemovedException, OutOfMemoryException {
205         if (texturesCoordinatesBufferMap.containsKey(identifier)) {
206             return texturesCoordinatesBufferMap.get(identifier);
207         } else {
208             ElementsBuffer texturesCoordinatesBuffer = canvas.getBuffersManager().createElementsBuffer();
209             fillTextureCoordinatesBuffer(texturesCoordinatesBuffer, identifier);
210             texturesCoordinatesBufferMap.put(identifier, texturesCoordinatesBuffer);
211             return texturesCoordinatesBuffer;
212         }
213     }
214
215     /**
216      * Return the color buffer of the given object.
217      * @param id the given object Id.
218      * @return the color buffer of the given object.
219      * @throws ObjectRemovedException if the object is now longer present.
220      */
221     public ElementsBuffer getColorBuffer(String id) throws ObjectRemovedException, OutOfMemoryException {
222         if (colorBufferMap.containsKey(id)) {
223             return colorBufferMap.get(id);
224         } else {
225             ElementsBuffer colorBuffer = canvas.getBuffersManager().createElementsBuffer();
226             fillColorBuffer(colorBuffer, id);
227             colorBufferMap.put(id, colorBuffer);
228             return colorBuffer;
229         }
230     }
231
232     /**
233      * Return the index buffer of the given object.
234      * @param id the given object Id.
235      * @return the index buffer of the given object.
236      * @throws ObjectRemovedException if the object is now longer present.
237      */
238     public IndicesBuffer getIndexBuffer(String id) throws ObjectRemovedException, OutOfMemoryException {
239         if (indexBufferMap.containsKey(id)) {
240             return indexBufferMap.get(id);
241         } else {
242             IndicesBuffer indexBuffer = canvas.getBuffersManager().createIndicesBuffer();
243             fillIndexBuffer(indexBuffer, id);
244             indexBufferMap.put(id, indexBuffer);
245             return indexBuffer;
246         }
247     }
248
249     /**
250      * Return the wire index buffer of the given object.
251      * @param id the given object Id.
252      * @return the wire index buffer of the given object.
253      * @throws ObjectRemovedException if the object is now longer present.
254      */
255     public IndicesBuffer getWireIndexBuffer(String id) throws ObjectRemovedException, OutOfMemoryException {
256         if (wireIndexBufferMap.containsKey(id)) {
257             return wireIndexBufferMap.get(id);
258         } else {
259             IndicesBuffer indexBuffer = canvas.getBuffersManager().createIndicesBuffer();
260             fillWireIndexBuffer(indexBuffer, id);
261             wireIndexBufferMap.put(id, indexBuffer);
262             return indexBuffer;
263         }
264     }
265
266     /**
267      * Update texture coordinate buffer for the given object.
268      * @param id given object id.
269      * @throws ObjectRemovedException if the object is now longer present.
270      */
271     public void updateTextureCoordinatesBuffer(String id) throws ObjectRemovedException, OutOfMemoryException {
272         ElementsBuffer textureCoordinatesBuffer = texturesCoordinatesBufferMap.get(id);
273         if (textureCoordinatesBuffer != null) {
274             fillTextureCoordinatesBuffer(textureCoordinatesBuffer, id);
275         }
276     }
277
278     /**
279      * Update the data if needed.
280      * @param id the modified object.
281      * @param property the changed property.
282      */
283     public void update(String id, int property) throws OutOfMemoryException {
284         Integer type = (Integer) GraphicController.getController().getProperty(id, GraphicObjectProperties.__GO_TYPE__);
285
286         try {
287             if (vertexBufferMap.containsKey(id)) {
288                 if ((type.equals(GraphicObjectProperties.__GO_FAC3D__) && FAC3D_DATA_PROPERTIES.contains(property))
289                         || (type.equals(GraphicObjectProperties.__GO_FEC__) && FEC_DATA_PROPERTIES.contains(property))
290                         || (type.equals(GraphicObjectProperties.__GO_GRAYPLOT__) && GRAYPLOT_DATA_PROPERTIES.contains(property))
291                         || (type.equals(GraphicObjectProperties.__GO_MATPLOT__) && MATPLOT_DATA_PROPERTIES.contains(property))
292                         || (type.equals(GraphicObjectProperties.__GO_POLYLINE__) && POLYLINE_DATA_PROPERTIES.contains(property))
293                         || (type.equals(GraphicObjectProperties.__GO_PLOT3D__) && PLOT3D_DATA_PROPERTIES.contains(property))
294                         || (type.equals(GraphicObjectProperties.__GO_ARC__) && ARC_DATA_PROPERTIES.contains(property))
295                         || (type.equals(GraphicObjectProperties.__GO_CHAMP__) && CHAMP_DATA_PROPERTIES.contains(property))
296                         || (type.equals(GraphicObjectProperties.__GO_RECTANGLE__) && RECTANGLE_DATA_PROPERTIES.contains(property))
297                         || (type.equals(GraphicObjectProperties.__GO_SEGS__) && SEGS_DATA_PROPERTIES.contains(property))) {
298                     fillBuffers(id);
299                 }
300             }
301             if (property == GraphicObjectProperties.__GO_X_AXIS_LOG_FLAG__) {
302                 updateChildrenVertexIndex(id, 0x01);
303             }
304
305             if (property == GraphicObjectProperties.__GO_Y_AXIS_LOG_FLAG__) {
306                 updateChildrenVertexIndex(id, 0x02);
307             }
308
309             if (property == GraphicObjectProperties.__GO_Z_AXIS_LOG_FLAG__) {
310                 updateChildrenVertexIndex(id, 0x04);
311             }
312         } catch (ObjectRemovedException e) {
313             // Object has been removed before drawing : do nothing.
314         }
315     }
316
317     /**
318      * Update the vertex buffer and index buffers of the given object and its descendants.
319      * @param id the id of the object.
320      * @param coordinateMask the coordinateMask to use.
321      * @throws ObjectRemovedException if the object is no longer present.
322      * @throws OutOfMemoryException if there was not enough memory.
323      */
324     private void updateChildrenVertexIndex(String id, int coordinateMask) throws ObjectRemovedException, OutOfMemoryException {
325         ElementsBuffer vertexBuffer = vertexBufferMap.get(id);
326         if (vertexBuffer != null) {
327             updateVertexBuffer(vertexBuffer, id, coordinateMask);
328         }
329
330         ElementsBuffer normalBuffer = normalBufferMap.get(id);
331         if (normalBuffer != null) {
332             fillNormalBuffer(normalBuffer, id);
333         }
334
335         /*
336          * To update the index and wire index buffers, on the contrary to updateVertexBuffer, we must perform a complete fill.
337          * That is because IndicesBuffer's getData method returns a read-only buffer, which cannot be written to, as is
338          * done by updateVertexBuffer, whereas the fill methods allocate new buffers (see the implementations of getData in
339          * SciRenderer's ElementsBuffer and IndicesBuffer). To allow an allocation-free update would require modifying
340          * IndicesBuffer's getData method.
341          */
342         IndicesBuffer indexBuffer = indexBufferMap.get(id);
343         if (indexBuffer != null) {
344             fillIndexBuffer(indexBuffer, id);
345         }
346
347         IndicesBuffer wireIndexBuffer = wireIndexBufferMap.get(id);
348         if (wireIndexBuffer != null) {
349             fillWireIndexBuffer(wireIndexBuffer, id);
350         }
351
352         for (String childId : (String []) GraphicController.getController().getProperty(id, GraphicObjectProperties.__GO_CHILDREN__)) {
353             updateChildrenVertexIndex(childId, coordinateMask);
354         }
355     }
356
357     /**
358      * Clear the buffer corresponding to the given object.
359      * @param id object id.
360      */
361     public void dispose(String id) {
362         if (vertexBufferMap.containsKey(id)) {
363             canvas.getBuffersManager().dispose(vertexBufferMap.get(id));
364             vertexBufferMap.remove(id);
365         }
366
367         if (normalBufferMap.containsKey(id)) {
368             canvas.getBuffersManager().dispose(normalBufferMap.get(id));
369             normalBufferMap.remove(id);
370         }
371
372         if (colorBufferMap.containsKey(id)) {
373             canvas.getBuffersManager().dispose(colorBufferMap.get(id));
374             colorBufferMap.remove(id);
375         }
376
377         if (texturesCoordinatesBufferMap.containsKey(id)) {
378             canvas.getBuffersManager().dispose(texturesCoordinatesBufferMap.get(id));
379             texturesCoordinatesBufferMap.remove(id);
380         }
381
382         if (indexBufferMap.containsKey(id)) {
383             canvas.getBuffersManager().dispose(indexBufferMap.get(id));
384             indexBufferMap.remove(id);
385         }
386
387         if (wireIndexBufferMap.containsKey(id)) {
388             canvas.getBuffersManager().dispose(wireIndexBufferMap.get(id));
389             wireIndexBufferMap.remove(id);
390         }
391     }
392
393     /**
394      * Clears all the color buffers.
395      */
396     public void disposeAllColorBuffers() {
397         canvas.getBuffersManager().dispose(colorBufferMap.values());
398         colorBufferMap.clear();
399     }
400
401     /**
402      * Clears all the texture coordinates buffers.
403      */
404     public void disposeAllTextureCoordinatesBuffers() {
405         canvas.getBuffersManager().dispose(texturesCoordinatesBufferMap.values());
406         texturesCoordinatesBufferMap.clear();
407     }
408
409     /**
410      * Fill the vertex, color, index and wire index buffers
411      * of a given object.
412      * @param id the object id.
413      * @throws ObjectRemovedException if the object is now longer present.
414      */
415     private void fillBuffers(String id) throws ObjectRemovedException, OutOfMemoryException {
416         ElementsBuffer vertexBuffer = vertexBufferMap.get(id);
417         if (vertexBuffer != null) {
418             fillVertexBuffer(vertexBuffer, id);
419         }
420
421         ElementsBuffer colorBuffer = colorBufferMap.get(id);
422         if (colorBuffer != null) {
423             fillColorBuffer(colorBuffer, id);
424         }
425
426         ElementsBuffer textureCoordinatesBuffer = texturesCoordinatesBufferMap.get(id);
427         if (textureCoordinatesBuffer != null) {
428             fillTextureCoordinatesBuffer(textureCoordinatesBuffer, id);
429         }
430
431         IndicesBuffer indexBuffer = indexBufferMap.get(id);
432         if (indexBuffer != null) {
433             fillIndexBuffer(indexBuffer, id);
434         }
435
436         IndicesBuffer wireIndexBuffer = wireIndexBufferMap.get(id);
437         if (wireIndexBuffer != null) {
438             fillWireIndexBuffer(wireIndexBuffer, id);
439         }
440     }
441
442     private void fillVertexBuffer(ElementsBuffer vertexBuffer, String id) throws ObjectRemovedException, OutOfMemoryException {
443         fillVertexBuffer(vertexBuffer, id, 0x01 | 0x02 | 0x04 | 0x08);
444     }
445
446     private void fillVertexBuffer(ElementsBuffer vertexBuffer, String id, int coordinateMask) throws ObjectRemovedException, OutOfMemoryException {
447         int logMask = MainDataLoader.getLogMask(id);
448         int length = MainDataLoader.getDataSize(id);
449         FloatBuffer data = BufferAllocation.newFloatBuffer(length * 4);
450         MainDataLoader.fillVertices(id, data, 4, coordinateMask, DEFAULT_SCALE, DEFAULT_TRANSLATE, logMask);
451         vertexBuffer.setData(data, 4);
452     }
453
454     private void fillNormalBuffer(ElementsBuffer normalBuffer, String id) throws ObjectRemovedException, OutOfMemoryException {
455         int length = MainDataLoader.getDataSize(id);
456         FloatBuffer data = BufferAllocation.newFloatBuffer(length * 4);
457         MainDataLoader.fillNormals(id, getVertexBuffer(id).getData(), data, 4);
458         normalBuffer.setData(data, 4);
459     }
460
461     private void updateVertexBuffer(ElementsBuffer vertexBuffer, String id, int coordinateMask) throws ObjectRemovedException {
462         int logMask = MainDataLoader.getLogMask(id);
463         FloatBuffer data = vertexBuffer.getData();
464         MainDataLoader.fillVertices(id, data, 4, coordinateMask, DEFAULT_SCALE, DEFAULT_TRANSLATE, logMask);
465         vertexBuffer.setData(data, 4);
466     }
467
468     private void fillTextureCoordinatesBuffer(ElementsBuffer colorBuffer, String id) throws ObjectRemovedException, OutOfMemoryException {
469         int length = MainDataLoader.getDataSize(id);
470         FloatBuffer data = BufferAllocation.newFloatBuffer(length * 4);
471         MainDataLoader.fillTextureCoordinates(id, data, length);
472         colorBuffer.setData(data, 4);
473     }
474
475     private void fillColorBuffer(ElementsBuffer colorBuffer, String id) throws ObjectRemovedException, OutOfMemoryException {
476         int length = MainDataLoader.getDataSize(id);
477         FloatBuffer data = BufferAllocation.newFloatBuffer(length * 4);
478         MainDataLoader.fillColors(id, data, 4);
479         colorBuffer.setData(data, 4);
480     }
481
482     private void fillIndexBuffer(IndicesBuffer indexBuffer, String id) throws ObjectRemovedException, OutOfMemoryException {
483         int length = MainDataLoader.getIndicesSize(id);
484         IntBuffer data = BufferAllocation.newIntBuffer(length);
485
486         int actualLength = 0;
487         if (length != 0) {
488             /* Do not call JNI when the buffer is empty */
489             /* Because under Mac OS X, GetDirectBufferAddress returns a NULL pointer in this case */
490             /* This generates an exception in DataLoader_wrap.c */
491             int logMask = MainDataLoader.getLogMask(id);
492             actualLength = MainDataLoader.fillIndices(id, data, logMask);
493         }
494
495         /* Set the buffer size to the actual number of indices */
496         data.limit(actualLength);
497
498         indexBuffer.setData(data);
499     }
500
501     private void fillWireIndexBuffer(IndicesBuffer indexBuffer, String id) throws ObjectRemovedException, OutOfMemoryException {
502         int length = MainDataLoader.getWireIndicesSize(id);
503         IntBuffer data = BufferAllocation.newIntBuffer(length);
504
505         int actualLength = 0;
506         if (length != 0) {
507             /* Do not call JNI when the buffer is empty */
508             /* Because under Mac OS X, GetDirectBufferAddress returns a NULL pointer in this case */
509             /* This generates an exception in DataLoader_wrap.c */
510             int logMask = MainDataLoader.getLogMask(id);
511             actualLength = MainDataLoader.fillWireIndices(id, data, logMask);
512         }
513
514         /* Set the buffer size to the actual number of indices */
515         data.limit(actualLength);
516
517         indexBuffer.setData(data);
518     }
519 }