1 /**
2  * Copyright 2010 JogAmp Community. All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without modification, are
5  * permitted provided that the following conditions are met:
6  *
7  *    1. Redistributions of source code must retain the above copyright notice, this list of
8  *       conditions and the following disclaimer.
9  *
10  *    2. Redistributions in binary form must reproduce the above copyright notice, this list
11  *       of conditions and the following disclaimer in the documentation and/or other materials
12  *       provided with the distribution.
13  *
14  * THIS SOFTWARE IS PROVIDED BY JogAmp Community ``AS IS'' AND ANY EXPRESS OR IMPLIED
15  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
16  * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JogAmp Community OR
17  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
18  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
19  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
20  * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
21  * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
22  * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
23  *
24  * The views and conclusions contained in the software and documentation are those of the
25  * authors and should not be interpreted as representing official policies, either expressed
26  * or implied, of JogAmp Community.
27  */
28 
29 package com.jogamp.opengl.util;
30 
31 import java.nio.Buffer;
32 import java.nio.ByteBuffer;
33 import java.nio.FloatBuffer;
34 import java.nio.IntBuffer;
35 import java.nio.ShortBuffer;
36 
37 import com.jogamp.opengl.GL;
38 import com.jogamp.opengl.GL2ES2;
39 import com.jogamp.opengl.GLArrayData;
40 import com.jogamp.opengl.GLBufferStorage;
41 import com.jogamp.opengl.GLException;
42 import com.jogamp.opengl.fixedfunc.GLPointerFuncUtil;
43 
44 import com.jogamp.common.nio.Buffers;
45 
46 import jogamp.opengl.util.GLArrayHandler;
47 import jogamp.opengl.util.GLArrayHandlerInterleaved;
48 import jogamp.opengl.util.GLDataArrayHandler;
49 import jogamp.opengl.util.GLFixedArrayHandler;
50 import jogamp.opengl.util.GLFixedArrayHandlerFlat;
51 import jogamp.opengl.util.glsl.GLSLArrayHandler;
52 import jogamp.opengl.util.glsl.GLSLArrayHandlerFlat;
53 import jogamp.opengl.util.glsl.GLSLArrayHandlerInterleaved;
54 
55 
56 public class GLArrayDataServer extends GLArrayDataClient implements GLArrayDataEditable {
57 
58   //
59   // lifetime matters
60   //
61 
62   /**
63    * Create a VBO, using a predefined fixed function array index
64    * and starting with a given Buffer object incl it's stride
65    *
66    * On profiles GL2 and ES1 the fixed function pipeline behavior is as expected.
67    * On profile ES2 the fixed function emulation will transform these calls to
68    * EnableVertexAttribArray and VertexAttribPointer calls,
69    * and a predefined vertex attribute variable name will be chosen.
70    *
71    * The default name mapping will be used,
72    * see {@link GLPointerFuncUtil#getPredefinedArrayIndexName(int)}.
73    *
74    * @param index The GL array index
75    * @param compsPerElement component count per element
76    * @param dataType The component's OpenGL data type
77    * @param normalized Whether the data shall be normalized
78    * @param stride in bytes from one element to the other. If zero, compsPerElement * compSizeInBytes
79    * @param buffer the user define data
80    * @param vboUsage {@link GL2ES2#GL_STREAM_DRAW}, {@link GL#GL_STATIC_DRAW} or {@link GL#GL_DYNAMIC_DRAW}
81    *
82    * @see com.jogamp.opengl.GLContext#getPredefinedArrayIndexName(int)
83    */
createFixed(final int index, final int compsPerElement, final int dataType, final boolean normalized, final int stride, final Buffer buffer, final int vboUsage)84   public static GLArrayDataServer createFixed(final int index, final int compsPerElement, final int dataType, final boolean normalized, final int stride,
85                                               final Buffer buffer, final int vboUsage)
86     throws GLException
87   {
88     final GLArrayDataServer ads = new GLArrayDataServer();
89     final GLArrayHandler glArrayHandler = new GLFixedArrayHandler(ads);
90     ads.init(null, index, compsPerElement, dataType, normalized, stride, buffer, buffer.limit(), 0 /* mappedElementCount */, false,
91              glArrayHandler, 0, 0, vboUsage, GL.GL_ARRAY_BUFFER, false);
92     return ads;
93   }
94 
95   /**
96    * Create a VBO, using a predefined fixed function array index
97    * and starting with a new created Buffer object with initialElementCount size
98    *
99    * On profiles GL2 and ES1 the fixed function pipeline behavior is as expected.
100    * On profile ES2 the fixed function emulation will transform these calls to
101    * EnableVertexAttribArray and VertexAttribPointer calls,
102    * and a predefined vertex attribute variable name will be chosen.
103    *
104    * The default name mapping will be used,
105    * see {@link GLPointerFuncUtil#getPredefinedArrayIndexName(int)}.
106    *
107    * @param index The GL array index
108    * @param compsPerElement component count per element
109    * @param dataType The component's OpenGL data type
110    * @param normalized Whether the data shall be normalized
111    * @param initialElementCount
112    * @param vboUsage {@link GL2ES2#GL_STREAM_DRAW}, {@link GL#GL_STATIC_DRAW} or {@link GL#GL_DYNAMIC_DRAW}
113    *
114    * @see com.jogamp.opengl.GLContext#getPredefinedArrayIndexName(int)
115    */
createFixed(final int index, final int compsPerElement, final int dataType, final boolean normalized, final int initialElementCount, final int vboUsage)116   public static GLArrayDataServer createFixed(final int index, final int compsPerElement, final int dataType, final boolean normalized, final int initialElementCount,
117                                               final int vboUsage)
118     throws GLException
119   {
120     final GLArrayDataServer ads = new GLArrayDataServer();
121     final GLArrayHandler glArrayHandler = new GLFixedArrayHandler(ads);
122     ads.init(null, index, compsPerElement, dataType, normalized, 0, null, initialElementCount, 0 /* mappedElementCount */, false,
123              glArrayHandler, 0, 0, vboUsage, GL.GL_ARRAY_BUFFER, false);
124     return ads;
125   }
126 
127   /**
128    * Create a VBO, using a custom GLSL array attribute name
129    * and starting with a new created Buffer object with initialElementCount size
130    * @param name  The custom name for the GL attribute
131    * @param compsPerElement component count per element
132    * @param dataType The component's OpenGL data type
133    * @param normalized Whether the data shall be normalized
134    * @param initialElementCount
135    * @param vboUsage {@link GL2ES2#GL_STREAM_DRAW}, {@link GL#GL_STATIC_DRAW} or {@link GL#GL_DYNAMIC_DRAW}
136    */
createGLSL(final String name, final int compsPerElement, final int dataType, final boolean normalized, final int initialElementCount, final int vboUsage)137   public static GLArrayDataServer createGLSL(final String name, final int compsPerElement,
138                                              final int dataType, final boolean normalized, final int initialElementCount, final int vboUsage)
139     throws GLException
140   {
141     final GLArrayDataServer ads = new GLArrayDataServer();
142     final GLArrayHandler glArrayHandler = new GLSLArrayHandler(ads);
143     ads.init(name, -1, compsPerElement, dataType, normalized, 0, null, initialElementCount,
144              0 /* mappedElementCount */, true, glArrayHandler, 0, 0, vboUsage, GL.GL_ARRAY_BUFFER, true);
145     return ads;
146   }
147 
148   /**
149    * Create a VBO, using a custom GLSL array attribute name
150    * intended for GPU buffer storage mapping, see {@link GLBufferStorage}, via {@link #mapStorage(GL, int)} and {@link #mapStorage(GL, long, long, int)}.
151    * @param name  The custom name for the GL attribute
152    * @param compsPerElement component count per element
153    * @param dataType The component's OpenGL data type
154    * @param normalized Whether the data shall be normalized
155    * @param mappedElementCount
156    * @param vboUsage {@link GL2ES2#GL_STREAM_DRAW}, {@link GL#GL_STATIC_DRAW} or {@link GL#GL_DYNAMIC_DRAW}
157    */
createGLSLMapped(final String name, final int compsPerElement, final int dataType, final boolean normalized, final int mappedElementCount, final int vboUsage)158   public static GLArrayDataServer createGLSLMapped(final String name, final int compsPerElement,
159                                                    final int dataType, final boolean normalized, final int mappedElementCount, final int vboUsage)
160     throws GLException
161   {
162     final GLArrayDataServer ads = new GLArrayDataServer();
163     final GLArrayHandler glArrayHandler = new GLSLArrayHandler(ads);
164     ads.init(name, -1, compsPerElement, dataType, normalized, 0, null, 0 /* initialElementCount */,
165              mappedElementCount, true, glArrayHandler, 0, 0, vboUsage, GL.GL_ARRAY_BUFFER, true);
166     ads.seal(true);
167     return ads;
168   }
169 
170   /**
171    * Create a VBO, using a custom GLSL array attribute name
172    * and starting with a given Buffer object incl it's stride
173    * @param name  The custom name for the GL attribute
174    * @param compsPerElement component count per element
175    * @param dataType The component's OpenGL data type
176    * @param normalized Whether the data shall be normalized
177    * @param stride in bytes from one element to the other. If zero, compsPerElement * compSizeInBytes
178    * @param buffer the user define data
179    * @param vboUsage {@link GL2ES2#GL_STREAM_DRAW}, {@link GL#GL_STATIC_DRAW} or {@link GL#GL_DYNAMIC_DRAW}
180    */
createGLSL(final String name, final int compsPerElement, final int dataType, final boolean normalized, final int stride, final Buffer buffer, final int vboUsage)181   public static GLArrayDataServer createGLSL(final String name, final int compsPerElement,
182                                              final int dataType, final boolean normalized, final int stride, final Buffer buffer,
183                                              final int vboUsage)
184     throws GLException
185   {
186     final GLArrayDataServer ads = new GLArrayDataServer();
187     final GLArrayHandler glArrayHandler = new GLSLArrayHandler(ads);
188     ads.init(name, -1, compsPerElement, dataType, normalized, stride, buffer, buffer.limit(), 0 /* mappedElementCount */, true,
189              glArrayHandler, 0, 0, vboUsage, GL.GL_ARRAY_BUFFER, true);
190     return ads;
191   }
192 
193   /**
194    * Create a VBO data object for any target w/o render pipeline association, ie {@link GL#GL_ELEMENT_ARRAY_BUFFER}.
195    *
196    * Hence no index, name for a fixed function pipeline nor vertex attribute is given.
197    *
198    * @param compsPerElement component count per element
199    * @param dataType The component's OpenGL data type
200    * @param stride in bytes from one element to the other. If zero, compsPerElement * compSizeInBytes
201    * @param buffer the user define data
202    * @param vboUsage {@link GL2ES2#GL_STREAM_DRAW}, {@link GL#GL_STATIC_DRAW} or {@link GL#GL_DYNAMIC_DRAW}
203    * @param vboTarget {@link GL#GL_ELEMENT_ARRAY_BUFFER}, ..
204    * {@link GL#glGenBuffers(int, int[], int)
205    */
createData(final int compsPerElement, final int dataType, final int stride, final Buffer buffer, final int vboUsage, final int vboTarget)206   public static GLArrayDataServer createData(final int compsPerElement, final int dataType, final int stride,
207                                              final Buffer buffer, final int vboUsage, final int vboTarget)
208     throws GLException
209   {
210     final GLArrayDataServer ads = new GLArrayDataServer();
211     final GLArrayHandler glArrayHandler = new GLDataArrayHandler(ads);
212     ads.init(null, -1, compsPerElement, dataType, false, stride, buffer, buffer.limit(), 0 /* mappedElementCount */, false,
213              glArrayHandler, 0, 0, vboUsage, vboTarget, false);
214     return ads;
215   }
216 
217   /**
218    * Create a VBO data object for any target w/o render pipeline association, ie {@link GL#GL_ELEMENT_ARRAY_BUFFER}.
219    *
220    * Hence no index, name for a fixed function pipeline nor vertex attribute is given.
221    *
222    * @param compsPerElement component count per element
223    * @param dataType The component's OpenGL data type
224    * @param initialElementCount
225    * @param vboUsage {@link GL2ES2#GL_STREAM_DRAW}, {@link GL#GL_STATIC_DRAW} or {@link GL#GL_DYNAMIC_DRAW}
226    * @param vboTarget {@link GL#GL_ELEMENT_ARRAY_BUFFER}, ..
227    */
createData(final int compsPerElement, final int dataType, final int initialElementCount, final int vboUsage, final int vboTarget)228   public static GLArrayDataServer createData(final int compsPerElement, final int dataType, final int initialElementCount,
229                                              final int vboUsage, final int vboTarget)
230     throws GLException
231   {
232     final GLArrayDataServer ads = new GLArrayDataServer();
233     final GLArrayHandler glArrayHandler = new GLDataArrayHandler(ads);
234     ads.init(null, -1, compsPerElement, dataType, false, 0, null, initialElementCount, 0 /* mappedElementCount */, false,
235              glArrayHandler, 0, 0, vboUsage, vboTarget, false);
236     return ads;
237   }
238 
239   /**
240    * Create a VBO data object for any target w/o render pipeline association, i.e. {@link GL#GL_ELEMENT_ARRAY_BUFFER},
241    * intended for GPU buffer storage mapping, see {@link GLBufferStorage}, via {@link #mapStorage(GL, int)} and {@link #mapStorage(GL, long, long, int)}.
242    * <p>
243    * No index, name for a fixed function pipeline nor vertex attribute is given.
244    * </p>
245    *
246    * @param compsPerElement component count per element
247    * @param dataType The component's OpenGL data type
248    * @param initialElementCount
249    * @param vboUsage {@link GL2ES2#GL_STREAM_DRAW}, {@link GL#GL_STATIC_DRAW} or {@link GL#GL_DYNAMIC_DRAW}
250    * @param vboTarget {@link GL#GL_ELEMENT_ARRAY_BUFFER}, ..
251    */
createDataMapped(final int compsPerElement, final int dataType, final int mappedElementCount, final int vboUsage, final int vboTarget)252   public static GLArrayDataServer createDataMapped(final int compsPerElement, final int dataType, final int mappedElementCount,
253                                                    final int vboUsage, final int vboTarget)
254     throws GLException
255   {
256     final GLArrayDataServer ads = new GLArrayDataServer();
257     final GLArrayHandler glArrayHandler = new GLDataArrayHandler(ads);
258     ads.init(null, -1, compsPerElement, dataType, false, 0, null, 0 /* initialElementCount */, mappedElementCount, false,
259              glArrayHandler, 0, 0, vboUsage, vboTarget, false);
260     return ads;
261   }
262 
263   /**
264    * Create a VBO for fixed function interleaved array data
265    * starting with a new created Buffer object with initialElementCount size.
266    * <p>User needs to <i>configure</i> the interleaved segments via {@link #addFixedSubArray(int, int, int)}.</p>
267    *
268    * @param compsPerElement The total number of all interleaved components per element.
269    * @param dataType The component's OpenGL data type
270    * @param normalized Whether the data shall be normalized
271    * @param initialElementCount The initial number of all interleaved elements
272    * @param vboUsage {@link GL2ES2#GL_STREAM_DRAW}, {@link GL#GL_STATIC_DRAW} or {@link GL#GL_DYNAMIC_DRAW}
273    */
createFixedInterleaved(final int compsPerElement, final int dataType, final boolean normalized, final int initialElementCount, final int vboUsage)274   public static GLArrayDataServer createFixedInterleaved(final int compsPerElement, final int dataType, final boolean normalized, final int initialElementCount,
275                                               final int vboUsage)
276     throws GLException
277   {
278     final GLArrayDataServer ads = new GLArrayDataServer();
279     final GLArrayHandler glArrayHandler = new GLArrayHandlerInterleaved(ads);
280     ads.init(GLPointerFuncUtil.mgl_InterleaveArray, -1, compsPerElement, dataType, false, 0, null, initialElementCount, 0 /* mappedElementCount */, false,
281              glArrayHandler, 0, 0, vboUsage, GL.GL_ARRAY_BUFFER, false);
282     return ads;
283   }
284 
285   /**
286    * Create a VBO for fixed function interleaved array data
287    * intended for GPU buffer storage mapping, see {@link GLBufferStorage}, via {@link #mapStorage(GL, int)} and {@link #mapStorage(GL, long, long, int)}.
288    * <p>User needs to <i>configure</i> the interleaved segments via {@link #addFixedSubArray(int, int, int)}.</p>
289    *
290    * @param compsPerElement The total number of all interleaved components per element.
291    * @param dataType The component's OpenGL data type
292    * @param normalized Whether the data shall be normalized
293    * @param mappedElementCount The total number of all interleaved elements
294    * @param vboUsage {@link GL2ES2#GL_STREAM_DRAW}, {@link GL#GL_STATIC_DRAW} or {@link GL#GL_DYNAMIC_DRAW}
295    */
createFixedInterleavedMapped(final int compsPerElement, final int dataType, final boolean normalized, final int mappedElementCount, final int vboUsage)296   public static GLArrayDataServer createFixedInterleavedMapped(final int compsPerElement, final int dataType, final boolean normalized, final int mappedElementCount,
297                                                                final int vboUsage)
298     throws GLException
299   {
300     final GLArrayDataServer ads = new GLArrayDataServer();
301     final GLArrayHandler glArrayHandler = new GLArrayHandlerInterleaved(ads);
302     ads.init(GLPointerFuncUtil.mgl_InterleaveArray, -1, compsPerElement, dataType, false, 0, null, 0 /* initialElementCount */, mappedElementCount, false,
303              glArrayHandler, 0, 0, vboUsage, GL.GL_ARRAY_BUFFER, false);
304     ads.seal(true);
305     return ads;
306   }
307 
308   /**
309    * Create a VBO for fixed function interleaved array data
310    * starting with a given Buffer object incl it's stride
311    * <p>User needs to <i>configure</i> the interleaved segments via {@link #addFixedSubArray(int, int, int)}.</p>
312    *
313    * @param compsPerElement The total number of all interleaved components per element.
314    * @param dataType The component's OpenGL data type
315    * @param normalized Whether the data shall be normalized
316    * @param stride in bytes from one element of a sub-array to the other. If zero, compsPerElement * compSizeInBytes
317    * @param buffer The user define data of all interleaved elements
318    * @param vboUsage {@link GL2ES2#GL_STREAM_DRAW}, {@link GL#GL_STATIC_DRAW} or {@link GL#GL_DYNAMIC_DRAW}
319    */
createFixedInterleaved(final int compsPerElement, final int dataType, final boolean normalized, final int stride, final Buffer buffer, final int vboUsage)320   public static GLArrayDataServer createFixedInterleaved(final int compsPerElement, final int dataType, final boolean normalized, final int stride, final Buffer buffer,
321                                               final int vboUsage)
322     throws GLException
323   {
324     final GLArrayDataServer ads = new GLArrayDataServer();
325     final GLArrayHandler glArrayHandler = new GLArrayHandlerInterleaved(ads);
326     ads.init(GLPointerFuncUtil.mgl_InterleaveArray, -1, compsPerElement, dataType, normalized, stride, buffer, buffer.limit(), 0 /* mappedElementCount */, false,
327              glArrayHandler, 0, 0, vboUsage, GL.GL_ARRAY_BUFFER, false);
328     return ads;
329   }
330 
331   /**
332    * Configure a segment of this fixed function interleaved array (see {@link #createFixedInterleaved(int, int, boolean, int, int)}).
333    * <p>
334    * This method may be called several times as long the sum of interleaved components does not
335    * exceed the total component count of the created interleaved array.</p>
336    * <p>
337    * The memory of the the interleaved array is being used.</p>
338    * <p>
339    * Must be called before using the array, eg: {@link #seal(boolean)}, {@link #putf(float)}, .. </p>
340    *
341    * @param index The GL array index, maybe -1 if vboTarget is {@link GL#GL_ELEMENT_ARRAY_BUFFER}
342    * @param comps This interleaved array segment's component count per element
343    * @param vboTarget {@link GL#GL_ARRAY_BUFFER} or {@link GL#GL_ELEMENT_ARRAY_BUFFER}
344    */
addFixedSubArray(final int index, final int comps, final int vboTarget)345   public GLArrayData addFixedSubArray(final int index, final int comps, final int vboTarget) {
346       if(interleavedOffset >= getComponentCount() * getComponentSizeInBytes()) {
347           final int iOffC = interleavedOffset / getComponentSizeInBytes();
348           throw new GLException("Interleaved offset > total components ("+iOffC+" > "+getComponentCount()+")");
349       }
350       if(usesGLSL) {
351           throw new GLException("buffer uses GLSL");
352       }
353       final int subStrideB = ( 0 == getStride() ) ? getComponentCount() * getComponentSizeInBytes() : getStride();
354       final GLArrayDataWrapper ad;
355       if( 0 < mappedElementCount ) {
356           ad = GLArrayDataWrapper.createFixed(
357                   index, comps, getComponentType(),
358                   getNormalized(), subStrideB, mappedElementCount,
359                   getVBOName(), interleavedOffset, getVBOUsage(), vboTarget);
360       } else {
361           ad = GLArrayDataWrapper.createFixed(
362                   index, comps, getComponentType(),
363                   getNormalized(), subStrideB, getBuffer(),
364                   getVBOName(), interleavedOffset, getVBOUsage(), vboTarget);
365       }
366       ad.setVBOEnabled(isVBO());
367       interleavedOffset += comps * getComponentSizeInBytes();
368       if(GL.GL_ARRAY_BUFFER == vboTarget) {
369           glArrayHandler.addSubHandler(new GLFixedArrayHandlerFlat(ad));
370       }
371       return ad;
372   }
373 
374   /**
375    * Create a VBO for GLSL interleaved array data
376    * starting with a new created Buffer object with initialElementCount size.
377    * <p>User needs to <i>configure</i> the interleaved segments via {@link #addGLSLSubArray(int, int, int)}.</p>
378    *
379    * @param compsPerElement The total number of all interleaved components per element.
380    * @param dataType The component's OpenGL data type
381    * @param normalized Whether the data shall be normalized
382    * @param initialElementCount The initial number of all interleaved elements
383    * @param vboUsage {@link GL2ES2#GL_STREAM_DRAW}, {@link GL#GL_STATIC_DRAW} or {@link GL#GL_DYNAMIC_DRAW}
384    */
createGLSLInterleaved(final int compsPerElement, final int dataType, final boolean normalized, final int initialElementCount, final int vboUsage)385   public static GLArrayDataServer createGLSLInterleaved(final int compsPerElement, final int dataType, final boolean normalized, final int initialElementCount,
386                                                         final int vboUsage)
387     throws GLException
388   {
389     final GLArrayDataServer ads = new GLArrayDataServer();
390     final GLArrayHandler glArrayHandler = new GLSLArrayHandlerInterleaved(ads);
391     ads.init(GLPointerFuncUtil.mgl_InterleaveArray, -1, compsPerElement, dataType, normalized, 0, null, initialElementCount, 0 /* mappedElementCount */, false,
392              glArrayHandler, 0, 0, vboUsage, GL.GL_ARRAY_BUFFER, true);
393     return ads;
394   }
395 
396   /**
397    * Create a VBO for GLSL interleaved array data
398    * intended for GPU buffer storage mapping, see {@link GLBufferStorage}, via {@link #mapStorage(GL, int)} and {@link #mapStorage(GL, long, long, int)}.
399    * <p>User needs to <i>configure</i> the interleaved segments via {@link #addGLSLSubArray(int, int, int)}.</p>
400    *
401    * @param compsPerElement The total number of all interleaved components per element.
402    * @param dataType The component's OpenGL data type
403    * @param normalized Whether the data shall be normalized
404    * @param mappedElementCount The total number of all interleaved elements
405    * @param vboUsage {@link GL2ES2#GL_STREAM_DRAW}, {@link GL#GL_STATIC_DRAW} or {@link GL#GL_DYNAMIC_DRAW}
406    */
createGLSLInterleavedMapped(final int compsPerElement, final int dataType, final boolean normalized, final int mappedElementCount, final int vboUsage)407   public static GLArrayDataServer createGLSLInterleavedMapped(final int compsPerElement, final int dataType, final boolean normalized, final int mappedElementCount, final int vboUsage)
408     throws GLException
409   {
410     final GLArrayDataServer ads = new GLArrayDataServer();
411     final GLArrayHandler glArrayHandler = new GLSLArrayHandlerInterleaved(ads);
412     ads.init(GLPointerFuncUtil.mgl_InterleaveArray, -1, compsPerElement, dataType, normalized, 0, null, 0 /* initialElementCount */, mappedElementCount, false,
413              glArrayHandler, 0, 0, vboUsage, GL.GL_ARRAY_BUFFER, true);
414     ads.seal(true);
415     return ads;
416   }
417 
418   /**
419    * Create a VBO for GLSL interleaved array data
420    * starting with a given Buffer object incl it's stride
421    * <p>User needs to <i>configure</i> the interleaved segments via {@link #addGLSLSubArray(int, int, int)}.</p>
422    *
423    * @param compsPerElement The total number of all interleaved components per element.
424    * @param dataType The component's OpenGL data type
425    * @param normalized Whether the data shall be normalized
426    * @param stride in bytes from one element of a sub-array to the other. If zero, compsPerElement * compSizeInBytes
427    * @param buffer The user define data of all interleaved elements
428    * @param vboUsage {@link GL2ES2#GL_STREAM_DRAW}, {@link GL#GL_STATIC_DRAW} or {@link GL#GL_DYNAMIC_DRAW}
429    */
createGLSLInterleaved(final int compsPerElement, final int dataType, final boolean normalized, final int stride, final Buffer buffer, final int vboUsage)430   public static GLArrayDataServer createGLSLInterleaved(final int compsPerElement, final int dataType, final boolean normalized, final int stride, final Buffer buffer,
431                                                         final int vboUsage)
432     throws GLException
433   {
434     final GLArrayDataServer ads = new GLArrayDataServer();
435     final GLArrayHandler glArrayHandler = new GLSLArrayHandlerInterleaved(ads);
436     ads.init(GLPointerFuncUtil.mgl_InterleaveArray, -1, compsPerElement, dataType, normalized, stride, buffer, buffer.limit(), 0 /* mappedElementCount */, false,
437              glArrayHandler, 0, 0, vboUsage, GL.GL_ARRAY_BUFFER, true);
438     return ads;
439   }
440 
441   /**
442    * Configure a segment of this GLSL interleaved array (see {@link #createGLSLInterleaved(int, int, boolean, int, int)}).
443    * <p>
444    * This method may be called several times as long the sum of interleaved components does not
445    * exceed the total component count of the created interleaved array.</p>
446    * <p>
447    * The memory of the the interleaved array is being used.</p>
448    * <p>
449    * Must be called before using the array, eg: {@link #seal(boolean)}, {@link #putf(float)}, .. </p>
450    * @param name  The custom name for the GL attribute, maybe null if vboTarget is {@link GL#GL_ELEMENT_ARRAY_BUFFER}
451    * @param comps This interleaved array segment's component count per element
452    * @param vboTarget {@link GL#GL_ARRAY_BUFFER} or {@link GL#GL_ELEMENT_ARRAY_BUFFER}
453    */
addGLSLSubArray(final String name, final int comps, final int vboTarget)454   public GLArrayData addGLSLSubArray(final String name, final int comps, final int vboTarget) {
455       if(interleavedOffset >= getComponentCount() * getComponentSizeInBytes()) {
456           final int iOffC = interleavedOffset / getComponentSizeInBytes();
457           throw new GLException("Interleaved offset > total components ("+iOffC+" > "+getComponentCount()+")");
458       }
459       if(!usesGLSL) {
460           throw new GLException("buffer uses fixed function");
461       }
462       final int subStrideB = ( 0 == getStride() ) ? getComponentCount() * getComponentSizeInBytes() : getStride();
463       final GLArrayDataWrapper ad;
464       if( 0 < mappedElementCount ) {
465           ad = GLArrayDataWrapper.createGLSL(
466                   name, comps, getComponentType(),
467                   getNormalized(), subStrideB, mappedElementCount,
468                   getVBOName(), interleavedOffset, getVBOUsage(), vboTarget);
469       } else {
470           ad = GLArrayDataWrapper.createGLSL(
471                   name, comps, getComponentType(),
472                   getNormalized(), subStrideB, getBuffer(),
473                   getVBOName(), interleavedOffset, getVBOUsage(), vboTarget);
474       }
475       ad.setVBOEnabled(isVBO());
476       interleavedOffset += comps * getComponentSizeInBytes();
477       if(GL.GL_ARRAY_BUFFER == vboTarget) {
478           glArrayHandler.addSubHandler(new GLSLArrayHandlerFlat(ad));
479       }
480       return ad;
481   }
482 
setInterleavedOffset(final int interleavedOffset)483   public final void setInterleavedOffset(final int interleavedOffset) {
484     this.interleavedOffset = interleavedOffset;
485   }
486 
getInterleavedOffset()487   public final int getInterleavedOffset() {
488     return interleavedOffset;
489   }
490 
491   //
492   // Data matters GLArrayData
493   //
494 
495   //
496   // Data and GL state modification ..
497   //
498 
499   @Override
destroy(final GL gl)500   public void destroy(final GL gl) {
501     // super.destroy(gl):
502     // - GLArrayDataClient.destroy(gl): disables & clears client-side buffer
503     //   - GLArrayDataWrapper.destroy(gl) (clears all values 'vboName' ..)
504     final int _vboName = vboName;
505     super.destroy(gl);
506     if(_vboName!=0) {
507         final int[] tmp = new int[] { _vboName } ;
508         gl.glDeleteBuffers(1, tmp, 0);
509         vboName = 0;
510     }
511   }
512 
513   //
514   // data matters
515   //
516 
517   /**
518    * Convenient way do disable the VBO behavior and
519    * switch to client side data one
520    * Only possible if buffer is defined.
521    */
522   @Override
setVBOEnabled(final boolean vboUsage)523   public void setVBOEnabled(final boolean vboUsage) {
524     checkSeal(false);
525     super.setVBOEnabled(vboUsage);
526   }
527 
mapStorage(final GL gl, final int access)528   public GLBufferStorage mapStorage(final GL gl, final int access) {
529       if( null != this.getBuffer() ) {
530           throw new IllegalStateException("user buffer not null");
531       }
532       if( null != mappedStorage ) {
533           throw new IllegalStateException("already mapped: "+mappedStorage);
534       }
535       checkSeal(true);
536       bindBuffer(gl, true);
537       gl.glBufferData(getVBOTarget(), getSizeInBytes(), null, getVBOUsage());
538       final GLBufferStorage storage = gl.mapBuffer(getVBOTarget(), access);
539       setMappedBuffer(storage);
540       bindBuffer(gl, false);
541       seal(false);
542       rewind();
543       return storage;
544   }
mapStorage(final GL gl, final long offset, final long length, final int access)545   public GLBufferStorage mapStorage(final GL gl, final long offset, final long length, final int access) {
546       if( null != this.getBuffer() ) {
547           throw new IllegalStateException("user buffer not null");
548       }
549       if( null != mappedStorage ) {
550           throw new IllegalStateException("already mapped: "+mappedStorage);
551       }
552       checkSeal(true);
553       bindBuffer(gl, true);
554       gl.glBufferData(getVBOTarget(), getSizeInBytes(), null, getVBOUsage());
555       final GLBufferStorage storage = gl.mapBufferRange(getVBOTarget(), offset, length, access);
556       setMappedBuffer(storage);
557       bindBuffer(gl, false);
558       seal(false);
559       rewind();
560       return storage;
561   }
setMappedBuffer(final GLBufferStorage storage)562   private final void setMappedBuffer(final GLBufferStorage storage) {
563       mappedStorage = storage;
564       final ByteBuffer bb = storage.getMappedBuffer();
565       if(componentClazz==ByteBuffer.class) {
566           buffer = bb;
567       } else if(componentClazz==ShortBuffer.class) {
568           buffer = bb.asShortBuffer();
569       } else if(componentClazz==IntBuffer.class) {
570           buffer = bb.asIntBuffer();
571       } else if(componentClazz==FloatBuffer.class) {
572           buffer = bb.asFloatBuffer();
573       } else {
574           throw new GLException("Given Buffer Class not supported: "+componentClazz+":\n\t"+this);
575       }
576   }
577 
unmapStorage(final GL gl)578   public void unmapStorage(final GL gl) {
579       if( null == mappedStorage ) {
580           throw new IllegalStateException("not mapped");
581       }
582       mappedStorage = null;
583       buffer = null;
584       seal(true);
585       bindBuffer(gl, true);
586       gl.glUnmapBuffer(getVBOTarget());
587       bindBuffer(gl, false);
588   }
589 
590   @Override
toString()591   public String toString() {
592     return "GLArrayDataServer["+name+
593                        ", index "+index+
594                        ", location "+location+
595                        ", isVertexAttribute "+isVertexAttribute+
596                        ", usesGLSL "+usesGLSL+
597                        ", usesShaderState "+(null!=shaderState)+
598                        ", dataType 0x"+Integer.toHexString(componentType)+
599                        ", bufferClazz "+componentClazz+
600                        ", elements "+getElementCount()+
601                        ", components "+componentsPerElement+
602                        ", stride "+strideB+"b "+strideL+"c"+
603                        ", initialElementCount "+initialElementCount+
604                        ", mappedElementCount "+mappedElementCount+
605                        ", mappedStorage "+mappedStorage+
606                        ", vboEnabled "+vboEnabled+
607                        ", vboName "+vboName+
608                        ", vboUsage 0x"+Integer.toHexString(vboUsage)+
609                        ", vboTarget 0x"+Integer.toHexString(vboTarget)+
610                        ", vboOffset "+vboOffset+
611                        ", sealed "+sealed+
612                        ", bufferEnabled "+bufferEnabled+
613                        ", bufferWritten "+bufferWritten+
614                        ", buffer "+buffer+
615                        ", alive "+alive+
616                        "]";
617   }
618 
619   //
620   // non public matters ..
621   //
622 
623   @Override
init(final String name, final int index, final int comps, final int dataType, final boolean normalized, final int stride, final Buffer data, final int initialElementCount, final int mappedElementCount, final boolean isVertexAttribute, final GLArrayHandler glArrayHandler, final int vboName, final long vboOffset, final int vboUsage, final int vboTarget, final boolean usesGLSL)624   protected void init(final String name, final int index, final int comps, final int dataType, final boolean normalized,
625                       final int stride, final Buffer data, final int initialElementCount, final int mappedElementCount,
626                       final boolean isVertexAttribute,
627                       final GLArrayHandler glArrayHandler, final int vboName, final long vboOffset, final int vboUsage, final int vboTarget, final boolean usesGLSL)
628     throws GLException
629   {
630     super.init(name, index, comps, dataType, normalized, stride, data, initialElementCount, mappedElementCount, isVertexAttribute,
631                glArrayHandler, vboName, vboOffset, vboUsage, vboTarget, usesGLSL);
632 
633     vboEnabled=true;
634   }
635 
636   @Override
init_vbo(final GL gl)637   protected void init_vbo(final GL gl) {
638     super.init_vbo(gl);
639     if(vboEnabled && vboName==0) {
640         final int[] tmp = new int[1];
641         gl.glGenBuffers(1, tmp, 0);
642         vboName = tmp[0];
643         if(0 < interleavedOffset) {
644             glArrayHandler.setSubArrayVBOName(vboName);
645         }
646     }
647   }
648 
GLArrayDataServer()649   protected GLArrayDataServer() { }
650 
651   /**
652    * Copy Constructor
653    * <p>
654    * Buffer is {@link Buffers#slice(Buffer) sliced}, i.e. sharing content but using own state.
655    * </p>
656    * <p>
657    * All other values are simply copied.
658    * </p>
659    */
GLArrayDataServer(final GLArrayDataServer src)660   public GLArrayDataServer(final GLArrayDataServer src) {
661     super(src);
662     this.interleavedOffset = src.interleavedOffset;
663     this.mappedStorage = src.mappedStorage;
664   }
665 
666   private int interleavedOffset = 0;
667   private GLBufferStorage mappedStorage = null;
668 }
669 
670