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