2c8063111b3c02f4a06f5bf7c1703ccb74bafe23
[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-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> colorBufferMap = new ConcurrentHashMap<String, ElementsBuffer>();
149     private final Map<String, ElementsBuffer> texturesCoordinatesBufferMap = new HashMap<String, ElementsBuffer>();
150     private final Map<String, IndicesBuffer> indexBufferMap = new HashMap<String, IndicesBuffer>();
151     private final Map<String, IndicesBuffer> wireIndexBufferMap = new HashMap<String, IndicesBuffer>();
152     private final Canvas canvas;
153
154
155     /**
156      * Default constructor.
157      * @param canvas the canvas where managed data live.
158      */
159     public DataManager(Canvas canvas) {
160         this.canvas = canvas;
161     }
162
163     /**
164      * Return the vertex buffer of the given object.
165      * @param id the given object Id.
166      * @return the vertex buffer of the given object.
167      * @throws ObjectRemovedException if the object is now longer present.
168      */
169     public ElementsBuffer getVertexBuffer(String id) throws ObjectRemovedException, OutOfMemoryException {
170         if (vertexBufferMap.containsKey(id)) {
171             return vertexBufferMap.get(id);
172         } else {
173             ElementsBuffer vertexBuffer = canvas.getBuffersManager().createElementsBuffer();
174             fillVertexBuffer(vertexBuffer, id);
175             vertexBufferMap.put(id, vertexBuffer);
176             return vertexBuffer;
177         }
178     }
179
180     /**
181      * Texture coordinates getter.
182      * @param identifier the graphic object id.
183      * @return the texture coordinates corresponding to the given graphic object.
184      * @throws ObjectRemovedException if the object is now longer present.
185      */
186     public ElementsBuffer getTextureCoordinatesBuffer(String identifier) throws ObjectRemovedException, OutOfMemoryException {
187         if (texturesCoordinatesBufferMap.containsKey(identifier)) {
188             return texturesCoordinatesBufferMap.get(identifier);
189         } else {
190             ElementsBuffer texturesCoordinatesBuffer = canvas.getBuffersManager().createElementsBuffer();
191             fillTextureCoordinatesBuffer(texturesCoordinatesBuffer, identifier);
192             texturesCoordinatesBufferMap.put(identifier, texturesCoordinatesBuffer);
193             return texturesCoordinatesBuffer;
194         }
195     }
196
197     /**
198      * Return the color buffer of the given object.
199      * @param id the given object Id.
200      * @return the color buffer of the given object.
201      * @throws ObjectRemovedException if the object is now longer present.
202      */
203     public ElementsBuffer getColorBuffer(String id) throws ObjectRemovedException, OutOfMemoryException {
204         if (colorBufferMap.containsKey(id)) {
205             return colorBufferMap.get(id);
206         } else {
207             ElementsBuffer colorBuffer = canvas.getBuffersManager().createElementsBuffer();
208             fillColorBuffer(colorBuffer, id);
209             colorBufferMap.put(id, colorBuffer);
210             return colorBuffer;
211         }
212     }
213
214     /**
215      * Return the index buffer of the given object.
216      * @param id the given object Id.
217      * @return the index buffer of the given object.
218      * @throws ObjectRemovedException if the object is now longer present.
219      */
220     public IndicesBuffer getIndexBuffer(String id) throws ObjectRemovedException, OutOfMemoryException {
221         if (indexBufferMap.containsKey(id)) {
222             return indexBufferMap.get(id);
223         } else {
224             IndicesBuffer indexBuffer = canvas.getBuffersManager().createIndicesBuffer();
225             fillIndexBuffer(indexBuffer, id);
226             indexBufferMap.put(id, indexBuffer);
227             return indexBuffer;
228         }
229     }
230
231     /**
232      * Return the wire index buffer of the given object.
233      * @param id the given object Id.
234      * @return the wire index buffer of the given object.
235      * @throws ObjectRemovedException if the object is now longer present.
236      */
237     public IndicesBuffer getWireIndexBuffer(String id) throws ObjectRemovedException, OutOfMemoryException {
238         if (wireIndexBufferMap.containsKey(id)) {
239             return wireIndexBufferMap.get(id);
240         } else {
241             IndicesBuffer indexBuffer = canvas.getBuffersManager().createIndicesBuffer();
242             fillWireIndexBuffer(indexBuffer, id);
243             wireIndexBufferMap.put(id, indexBuffer);
244             return indexBuffer;
245         }
246     }
247
248     /**
249      * Update texture coordinate buffer for the given object.
250      * @param id given object id.
251      * @throws ObjectRemovedException if the object is now longer present.
252      */
253     public void updateTextureCoordinatesBuffer(String id) throws ObjectRemovedException, OutOfMemoryException {
254         ElementsBuffer textureCoordinatesBuffer = texturesCoordinatesBufferMap.get(id);
255         if (textureCoordinatesBuffer != null) {
256             fillTextureCoordinatesBuffer(textureCoordinatesBuffer, id);
257         }
258     }
259
260     /**
261      * Update the data if needed.
262      * @param id the modified object.
263      * @param property the changed property.
264      */
265     public void update(String id, int property) throws OutOfMemoryException {
266         Integer type = (Integer) GraphicController.getController().getProperty(id, GraphicObjectProperties.__GO_TYPE__);
267
268         try {
269             if (vertexBufferMap.containsKey(id)) {
270                 if ((type.equals(GraphicObjectProperties.__GO_FAC3D__) && FAC3D_DATA_PROPERTIES.contains(property))
271                         || (type.equals(GraphicObjectProperties.__GO_FEC__) && FEC_DATA_PROPERTIES.contains(property))
272                         || (type.equals(GraphicObjectProperties.__GO_GRAYPLOT__) && GRAYPLOT_DATA_PROPERTIES.contains(property))
273                         || (type.equals(GraphicObjectProperties.__GO_MATPLOT__) && MATPLOT_DATA_PROPERTIES.contains(property))
274                         || (type.equals(GraphicObjectProperties.__GO_POLYLINE__) && POLYLINE_DATA_PROPERTIES.contains(property))
275                         || (type.equals(GraphicObjectProperties.__GO_PLOT3D__) && PLOT3D_DATA_PROPERTIES.contains(property))
276                         || (type.equals(GraphicObjectProperties.__GO_ARC__) && ARC_DATA_PROPERTIES.contains(property))
277                         || (type.equals(GraphicObjectProperties.__GO_CHAMP__) && CHAMP_DATA_PROPERTIES.contains(property))
278                         || (type.equals(GraphicObjectProperties.__GO_RECTANGLE__) && RECTANGLE_DATA_PROPERTIES.contains(property))
279                         || (type.equals(GraphicObjectProperties.__GO_SEGS__) && SEGS_DATA_PROPERTIES.contains(property))) {
280                     fillBuffers(id);
281                 }
282             }
283             if (property == GraphicObjectProperties.__GO_X_AXIS_LOG_FLAG__) {
284                 updateChildrenVertexIndex(id, 0x01);
285             }
286
287             if (property == GraphicObjectProperties.__GO_Y_AXIS_LOG_FLAG__) {
288                 updateChildrenVertexIndex(id, 0x02);
289             }
290
291             if (property == GraphicObjectProperties.__GO_Z_AXIS_LOG_FLAG__) {
292                 updateChildrenVertexIndex(id, 0x04);
293             }
294         } catch (ObjectRemovedException e) {
295             // Object has been removed before drawing : do nothing.
296         }
297     }
298
299     /**
300      * Update the vertex buffer and index buffers of the given object and its descendants.
301      * @param id the id of the object.
302      * @param coordinateMask the coordinateMask to use.
303      * @throws ObjectRemovedException if the object is no longer present.
304      * @throws OutOfMemoryException if there was not enough memory.
305      */
306     private void updateChildrenVertexIndex(String id, int coordinateMask) throws ObjectRemovedException, OutOfMemoryException {
307         ElementsBuffer vertexBuffer = vertexBufferMap.get(id);
308         if (vertexBuffer != null) {
309             updateVertexBuffer(vertexBuffer, id, coordinateMask);
310         }
311
312         /*
313          * To update the index and wire index buffers, on the contrary to updateVertexBuffer, we must perform a complete fill.
314          * That is because IndicesBuffer's getData method returns a read-only buffer, which cannot be written to, as is
315          * done by updateVertexBuffer, whereas the fill methods allocate new buffers (see the implementations of getData in
316          * SciRenderer's ElementsBuffer and IndicesBuffer). To allow an allocation-free update would require modifying
317          * IndicesBuffer's getData method.
318          */
319         IndicesBuffer indexBuffer = indexBufferMap.get(id);
320         if (indexBuffer != null) {
321             fillIndexBuffer(indexBuffer, id);
322         }
323
324         IndicesBuffer wireIndexBuffer = wireIndexBufferMap.get(id);
325         if (wireIndexBuffer != null) {
326             fillWireIndexBuffer(wireIndexBuffer, id);
327         }
328
329         for (String childId : (String []) GraphicController.getController().getProperty(id, GraphicObjectProperties.__GO_CHILDREN__)) {
330             updateChildrenVertexIndex(childId, coordinateMask);
331         }
332     }
333
334     /**
335      * Clear the buffer corresponding to the given object.
336      * @param id object id.
337      */
338     public void dispose(String id) {
339         if (vertexBufferMap.containsKey(id)) {
340             canvas.getBuffersManager().dispose(vertexBufferMap.get(id));
341             vertexBufferMap.remove(id);
342         }
343
344         if (colorBufferMap.containsKey(id)) {
345             canvas.getBuffersManager().dispose(colorBufferMap.get(id));
346             colorBufferMap.remove(id);
347         }
348
349         if (texturesCoordinatesBufferMap.containsKey(id)) {
350             canvas.getBuffersManager().dispose(texturesCoordinatesBufferMap.get(id));
351             texturesCoordinatesBufferMap.remove(id);
352         }
353
354         if (indexBufferMap.containsKey(id)) {
355             canvas.getBuffersManager().dispose(indexBufferMap.get(id));
356             indexBufferMap.remove(id);
357         }
358
359         if (wireIndexBufferMap.containsKey(id)) {
360             canvas.getBuffersManager().dispose(wireIndexBufferMap.get(id));
361             wireIndexBufferMap.remove(id);
362         }
363     }
364
365     /**
366      * Clears all the color buffers.
367      */
368     public void disposeAllColorBuffers() {
369         canvas.getBuffersManager().dispose(colorBufferMap.values());
370         colorBufferMap.clear();
371     }
372
373     /**
374      * Clears all the texture coordinates buffers.
375      */
376     public void disposeAllTextureCoordinatesBuffers() {
377         canvas.getBuffersManager().dispose(texturesCoordinatesBufferMap.values());
378         texturesCoordinatesBufferMap.clear();
379     }
380
381     /**
382      * Fill the vertex, color, index and wire index buffers
383      * of a given object.
384      * @param id the object id.
385      * @throws ObjectRemovedException if the object is now longer present.
386      */
387     private void fillBuffers(String id) throws ObjectRemovedException, OutOfMemoryException {
388         ElementsBuffer vertexBuffer = vertexBufferMap.get(id);
389         if (vertexBuffer != null) {
390             fillVertexBuffer(vertexBuffer, id);
391         }
392
393         ElementsBuffer colorBuffer = colorBufferMap.get(id);
394         if (colorBuffer != null) {
395             fillColorBuffer(colorBuffer, id);
396         }
397
398         ElementsBuffer textureCoordinatesBuffer = texturesCoordinatesBufferMap.get(id);
399         if (textureCoordinatesBuffer != null) {
400             fillTextureCoordinatesBuffer(textureCoordinatesBuffer, id);
401         }
402
403         IndicesBuffer indexBuffer = indexBufferMap.get(id);
404         if (indexBuffer != null) {
405             fillIndexBuffer(indexBuffer, id);
406         }
407
408         IndicesBuffer wireIndexBuffer = wireIndexBufferMap.get(id);
409         if (wireIndexBuffer != null) {
410             fillWireIndexBuffer(wireIndexBuffer, id);
411         }
412     }
413
414     private void fillVertexBuffer(ElementsBuffer vertexBuffer, String id) throws ObjectRemovedException, OutOfMemoryException {
415         fillVertexBuffer(vertexBuffer, id, 0x01 | 0x02 | 0x04 | 0x08);
416     }
417
418     private void fillVertexBuffer(ElementsBuffer vertexBuffer, String id, int coordinateMask) throws ObjectRemovedException, OutOfMemoryException {
419         int logMask = MainDataLoader.getLogMask(id);
420         int length = MainDataLoader.getDataSize(id);
421         FloatBuffer data = BufferAllocation.newFloatBuffer(length * 4);
422         MainDataLoader.fillVertices(id, data, 4, coordinateMask, DEFAULT_SCALE, DEFAULT_TRANSLATE, logMask);
423         vertexBuffer.setData(data, 4);
424     }
425
426     private void updateVertexBuffer(ElementsBuffer vertexBuffer, String id, int coordinateMask) throws ObjectRemovedException {
427         int logMask = MainDataLoader.getLogMask(id);
428         FloatBuffer data = vertexBuffer.getData();
429         MainDataLoader.fillVertices(id, data, 4, coordinateMask, DEFAULT_SCALE, DEFAULT_TRANSLATE, logMask);
430         vertexBuffer.setData(data, 4);
431     }
432
433     private void fillTextureCoordinatesBuffer(ElementsBuffer colorBuffer, String id) throws ObjectRemovedException, OutOfMemoryException {
434         int length = MainDataLoader.getDataSize(id);
435         FloatBuffer data = BufferAllocation.newFloatBuffer(length * 4);
436         MainDataLoader.fillTextureCoordinates(id, data, length);
437         colorBuffer.setData(data, 4);
438     }
439
440     private void fillColorBuffer(ElementsBuffer colorBuffer, String id) throws ObjectRemovedException, OutOfMemoryException {
441             int length = MainDataLoader.getDataSize(id);
442             FloatBuffer data = BufferAllocation.newFloatBuffer(length * 4);
443             MainDataLoader.fillColors(id, data, 4);
444             colorBuffer.setData(data, 4);
445     }
446
447     private void fillIndexBuffer(IndicesBuffer indexBuffer, String id) throws ObjectRemovedException, OutOfMemoryException {
448         int length = MainDataLoader.getIndicesSize(id);
449         IntBuffer data = BufferAllocation.newIntBuffer(length);
450
451         int actualLength = 0;
452         if (length != 0) {
453             /* Do not call JNI when the buffer is empty */
454             /* Because under Mac OS X, GetDirectBufferAddress returns a NULL pointer in this case */
455             /* This generates an exception in DataLoader_wrap.c */
456             int logMask = MainDataLoader.getLogMask(id);
457             actualLength = MainDataLoader.fillIndices(id, data, logMask);
458         }
459
460         /* Set the buffer size to the actual number of indices */
461         data.limit(actualLength);
462
463         indexBuffer.setData(data);
464     }
465
466     private void fillWireIndexBuffer(IndicesBuffer indexBuffer, String id) throws ObjectRemovedException, OutOfMemoryException {
467         int length = MainDataLoader.getWireIndicesSize(id);
468         IntBuffer data = BufferAllocation.newIntBuffer(length);
469
470         int actualLength = 0;
471         if (length != 0) {
472             /* Do not call JNI when the buffer is empty */
473             /* Because under Mac OS X, GetDirectBufferAddress returns a NULL pointer in this case */
474             /* This generates an exception in DataLoader_wrap.c */
475             int logMask = MainDataLoader.getLogMask(id);
476             actualLength = MainDataLoader.fillWireIndices(id, data, logMask);
477         }
478
479         /* Set the buffer size to the actual number of indices */
480         data.limit(actualLength);
481
482         indexBuffer.setData(data);
483     }
484 }