Gamp v0.0.7-54-gccdc599
Gamp: Graphics, Audio, Multimedia and Processing
Loading...
Searching...
No Matches
GLPixelBuffer.hpp
Go to the documentation of this file.
1/*
2 * Author: Sven Gothel <sgothel@jausoft.com>
3 * Copyright Gothel Software e.K.
4 *
5 * SPDX-License-Identifier: MIT
6 *
7 * This Source Code Form is subject to the terms of the MIT License
8 * If a copy of the MIT was not distributed with this file,
9 * you can obtain one at https://opensource.org/license/mit/.
10 */
11#ifndef GAMP_RENDER_GL_PIXEL_GLPIXELBUFFER_HPP_
12#define GAMP_RENDER_GL_PIXEL_GLPIXELBUFFER_HPP_
13
14#include <jau/string_util.hpp>
15
16#include <gamp/GampTypes.hpp>
19#include <memory>
20
22 /** \addtogroup Gamp_GL
23 *
24 * @{
25 */
26
28
29 class GLPixelAttributes;
30 class GLPixelBuffer;
31 typedef std::shared_ptr<GLPixelBuffer> GLPixelBufferRef;
32
33 /** Allows user to interface with another toolkit to define {@link GLPixelAttributes} and memory buffer to produce {@link TextureData}. */
35 /** Allow {@link GL2ES3#GL_PACK_ROW_LENGTH}, or {@link GL2ES2#GL_UNPACK_ROW_LENGTH}. */
36 virtual bool getAllowRowStride() = 0;
37
38 /**
39 * Returns RGB[A] {@link GLPixelAttributes} matching {@link GL}, {@code componentCount} and {@code pack}.
40 *
41 * @param gl the corresponding current {@link GL} context object
42 * @param componentCount RGBA component count, i.e. 1 (luminance, alpha or red), 3 (RGB) or 4 (RGBA)
43 * @param pack {@code true} for read mode GPU -> CPU, e.g. {@link GL#glReadPixels(int, int, int, int, int, int, Buffer) glReadPixels}.
44 * {@code false} for write mode CPU -> GPU, e.g. {@link GL#glTexImage2D(int, int, int, int, int, int, int, int, Buffer) glTexImage2D}.
45 */
46 virtual const GLPixelAttributes& getAttributes(const GL& gl, int componentCount, bool pack) const noexcept = 0;
47
48 /**
49 * Returns the host {@link PixelFormat.Composition} matching {@link GL} and {@code componentCount}
50 * if required by implementation, otherwise {@code null}.
51 *
52 * @param glp the corresponding current {@link GL} context object
53 * @param componentCount RGBA component count, i.e. 1 (luminance, alpha or red), 3 (RGB) or 4 (RGBA)
54 */
55 virtual PixelFormat getHostPixelComp(const GLProfile& glp, int componentCount) const noexcept = 0;
56
57 /**
58 * Allocates a new {@link GLPixelBuffer} object.
59 * <p>
60 * The minimum required {@link Buffer#remaining() remaining} byte size equals to <code>minByteSize</code>, if &gt; 0,
61 * otherwise utilize {@link GLBuffers#sizeof(GL, int[], int, int, int, int, int, boolean)}
62 * to calculate it.
63 * </p>
64 *
65 * @param gl the corresponding current {@link GL} context object
66 * @param hostPixComp host {@link PixelFormat pixel format}, i.e. of the source or sink depending on {@code pack},
67 * e.g. fetched via {@link #getHostPixelComp(GLProfile, int)}.
68 * If {@code null}, {@code pixelAttributes} instance maybe used or an exception is thrown,
69 * depending on implementation semantics.
70 * @param pixelAttributes the desired {@link GLPixelAttributes}, e.g. fetched via {@link #getAttributes(GL, int, boolean)}
71 * @param pack {@code true} for read mode GPU -> CPU, e.g. {@link GL#glReadPixels(int, int, int, int, int, int, Buffer) glReadPixels}.
72 * {@code false} for write mode CPU -> GPU, e.g. {@link GL#glTexImage2D(int, int, int, int, int, int, int, int, Buffer) glTexImage2D}.
73 * @param width in pixels
74 * @param height in pixels
75 * @param depth in pixels
76 * @param minByteSize if &gt; 0, the pre-calculated minimum byte-size for the resulting buffer, otherwise ignore.
77 * @see #getHostPixelComp(GLProfile, int)
78 * @see #getAttributes(GL, int, boolean)
79 */
80 virtual GLPixelBufferRef allocate(const GL& gl, const PixelFormat& hostPixComp, const GLPixelAttributes& pixelAttributes,
81 bool pack, int width, int height, int depth, int minByteSize);
82 };
83
84 /**
85 * OpenGL pixel data buffer, allowing user to provide buffers via their {@link GLPixelBufferProvider} implementation.
86 * <p>
87 * {@link GLPixelBufferProvider} produces a {@link GLPixelBuffer}.
88 * </p>
89 * <p>
90 * You may use {@link #defaultProviderNoRowStride}.
91 * </p>
92 */
94
95
96 /** Pixel attributes. */
97 public static class GLPixelAttributes {
98 /** Undefined instance of {@link GLPixelAttributes}, having componentCount:=0, format:=0 and type:= 0. */
99 public static final GLPixelAttributes UNDEF = new GLPixelAttributes(null, PixelFormat.LUMINANCE, 0, 0, true, false);
100
101 /**
102 * Returns the matching {@link PixelFormat} for the given GL format and type if exists,
103 * otherwise returns <code>null</code>.
104 */
105 public static final PixelFormat getPixelFormat(final int glFormat, final int glDataType) {
106 PixelFormat pixFmt = null;
107
108 switch(glFormat) {
109 case GL.GL_ALPHA:
110 case GL.GL_LUMINANCE:
111 case GL2ES2.GL_RED:
112 pixFmt = PixelFormat.LUMINANCE;
113 break;
114 case GL.GL_RGB:
115 switch(glDataType) {
116 case GL2GL3.GL_UNSIGNED_SHORT_5_6_5_REV:
117 pixFmt = PixelFormat.RGB565;
118 break;
119 case GL.GL_UNSIGNED_SHORT_5_6_5:
120 pixFmt = PixelFormat.BGR565;
121 break;
122 case GL.GL_UNSIGNED_BYTE:
123 pixFmt = PixelFormat.RGB888;
124 break;
125 }
126 break;
127 case GL.GL_RGBA:
128 switch(glDataType) {
129 case GL2GL3.GL_UNSIGNED_SHORT_1_5_5_5_REV:
130 pixFmt = PixelFormat.RGBA5551;
131 break;
132 case GL.GL_UNSIGNED_SHORT_5_5_5_1:
133 pixFmt = PixelFormat.ABGR1555;
134 break;
135 case GL2GL3.GL_UNSIGNED_INT_8_8_8_8_REV:
136 // fall through intended
137 case GL.GL_UNSIGNED_BYTE:
138 pixFmt = PixelFormat.RGBA8888;
139 break;
140 case GL2GL3.GL_UNSIGNED_INT_8_8_8_8:
141 pixFmt = PixelFormat.ABGR8888;
142 break;
143 }
144 break;
145 case GL.GL_BGR:
146 if( GL.GL_UNSIGNED_BYTE == glDataType ) {
147 pixFmt = PixelFormat.BGR888;
148 }
149 break;
150 case GL.GL_BGRA:
151 switch(glDataType) {
152 case GL2GL3.GL_UNSIGNED_INT_8_8_8_8:
153 pixFmt = PixelFormat.ARGB8888;
154 break;
155 case GL2GL3.GL_UNSIGNED_INT_8_8_8_8_REV:
156 // fall through intended
157 case GL.GL_UNSIGNED_BYTE:
158 pixFmt = PixelFormat.BGRA8888;
159 break;
160 }
161 break;
162 }
163 return pixFmt;
164 }
165
166 /**
167 * Returns the matching {@link GLPixelAttributes} for the given byte sized RGBA {@code componentCount} and {@link GL} if exists,
168 * otherwise returns {@code null}.
169 *
170 * @param gl the corresponding current {@link GL} context object
171 * @param componentCount RGBA component count, i.e. 1 (luminance, alpha or red), 3 (RGB) or 4 (RGBA)
172 * @param pack {@code true} for read mode GPU -> CPU, e.g. {@link GL#glReadPixels(int, int, int, int, int, int, Buffer) glReadPixels}.
173 * {@code false} for write mode CPU -> GPU, e.g. {@link GL#glTexImage2D(int, int, int, int, int, int, int, int, Buffer) glTexImage2D}.
174 */
175 public static GLPixelAttributes convert(final GL gl, final int componentCount, final boolean pack) {
176 final int dFormat, dType;
177 final boolean glesReadMode = pack && gl.isGLES();
178
179 if( 1 == componentCount && !glesReadMode ) {
180 if( gl.isGL3ES3() ) {
181 // RED is supported on ES3 and >= GL3 [core]; ALPHA is deprecated on core
182 dFormat = GL2ES2.GL_RED;
183 } else {
184 // ALPHA is supported on ES2 and GL2, i.e. <= GL3 [core] or compatibility
185 dFormat = GL.GL_ALPHA;
186 }
187 dType = GL.GL_UNSIGNED_BYTE;
188 } else if( 3 == componentCount && !glesReadMode ) {
189 dFormat = GL.GL_RGB;
190 dType = GL.GL_UNSIGNED_BYTE;
191 } else if( 4 == componentCount || glesReadMode ) {
192 final GLContext ctx = gl.getContext();
193 final int _dFormat = ctx.getDefaultPixelDataFormat();
194 final int _dComps = GLBuffers.componentCount(_dFormat);
195 if( _dComps == componentCount || 4 == _dComps ) { // accept if desired component count or 4 components
196 // pre-check whether default is supported by implementation
197 final int _dType = ctx.getDefaultPixelDataType();
198 final PixelFormat _pixFmt = getPixelFormat(_dFormat, _dType);
199 if( null != _pixFmt) {
200 return new GLPixelAttributes(null, _pixFmt, _dFormat, _dType, pack, true);
201 }
202 if( GLContext.DEBUG ) {
203 System.err.println("GLPixelAttributes.convert("+gl.getGLProfile()+", comps "+componentCount+", pack "+pack+
204 "): GL-impl default unsupported: "+
205 "[fmt 0x"+Integer.toHexString(_dFormat)+", type 0x"+Integer.toHexString(_dType)+"]: Using std RGBA+UBYTE");
206 Thread.dumpStack();
207 }
208 // fall-through intended to set dFormat/dType to std values
209 }
210 dFormat = GL.GL_RGBA;
211 dType = GL.GL_UNSIGNED_BYTE;
212 } else {
213 return null;
214 }
215 return new GLPixelAttributes(dFormat, dType);
216 }
217
218 /**
219 * Returns the matching {@link GLPixelAttributes} for the given {@link GLProfile}, {@link PixelFormat} and {@code pack} if exists,
220 * otherwise returns {@code null}.
221 * @param glp the corresponding {@link GLProfile}
222 * @param pixFmt the to be matched {@link PixelFormat pixel format}
223 * @param pack {@code true} for read mode GPU -> CPU, e.g. {@link GL#glReadPixels(int, int, int, int, int, int, Buffer) glReadPixels}.
224 * {@code false} for write mode CPU -> GPU, e.g. {@link GL#glTexImage2D(int, int, int, int, int, int, int, int, Buffer) glTexImage2D}.
225 */
226 public static final GLPixelAttributes convert(final GLProfile glp, final PixelFormat pixFmt, final boolean pack) {
227 final int[] df = new int[1];
228 final int[] dt = new int[1];
229 convert(glp, pixFmt, pack, df, dt);
230 if( 0 != df[0] ) {
231 return new GLPixelAttributes(null, pixFmt, df[0], dt[0], true /* not used */, true);
232 }
233 return null;
234 }
235 private static final int convert(final GLProfile glp, final PixelFormat pixFmt, final boolean pack,
236 final int[] dfRes, final int[] dtRes) {
237 final boolean glesReadMode = pack && glp.isGLES();
238 int df = 0; // format
239 int dt = GL.GL_UNSIGNED_BYTE; // data type
240 switch(pixFmt) {
241 case LUMINANCE:
242 if( !glesReadMode ) {
243 if( glp.isGL3ES3() ) {
244 // RED is supported on ES3 and >= GL3 [core]; ALPHA/LUMINANCE is deprecated on core
245 df = GL2ES2.GL_RED;
246 } else {
247 // ALPHA/LUMINANCE is supported on ES2 and GL2, i.e. <= GL3 [core] or compatibility
248 df = GL.GL_LUMINANCE;
249 }
250 }
251 break;
252 case RGB565:
253 if( glp.isGL2GL3() ) {
254 df = GL.GL_RGB; dt = GL2GL3.GL_UNSIGNED_SHORT_5_6_5_REV;
255 }
256 break;
257 case BGR565:
258 if( glp.isGL2GL3() ) {
259 df = GL.GL_RGB; dt = GL.GL_UNSIGNED_SHORT_5_6_5;
260 }
261 break;
262 case RGBA5551:
263 if( glp.isGL2GL3() ) {
264 df = GL.GL_RGBA; dt = GL2GL3.GL_UNSIGNED_SHORT_1_5_5_5_REV;
265 }
266 break;
267 case ABGR1555:
268 if( glp.isGL2GL3() ) {
269 df = GL.GL_RGBA; dt = GL.GL_UNSIGNED_SHORT_5_5_5_1;
270 }
271 break;
272 case RGB888:
273 if( !glesReadMode ) {
274 df = GL.GL_RGB;
275 }
276 break;
277 case BGR888:
278 if( glp.isGL2GL3() ) {
279 df = GL.GL_BGR;
280 }
281 break;
282 case RGBx8888:
283 case RGBA8888:
284 df = GL.GL_RGBA;
285 break;
286 case ABGR8888:
287 if( glp.isGL2GL3() ) {
288 df = GL.GL_RGBA; dt = GL2GL3.GL_UNSIGNED_INT_8_8_8_8;
289 }
290 break;
291 case ARGB8888:
292 if( glp.isGL2GL3() ) {
293 df = GL.GL_BGRA; dt = GL2GL3.GL_UNSIGNED_INT_8_8_8_8;
294 }
295 break;
296 case BGRx8888:
297 case BGRA8888:
298 if( glp.isGL2GL3() ) { // FIXME: or if( !glesReadMode ) ? BGRA n/a on GLES
299 df = GL.GL_BGRA;
300 }
301 break;
302 }
303 dfRes[0] = df;
304 dtRes[0] = dt;
305 return df;
306 }
307
308 /** The OpenGL pixel data format */
309 public final int format;
310 /** The OpenGL pixel data type */
311 public final int type;
312
313 /** {@link PixelFormat} describing the {@link PixelFormat.Composition component} layout */
314 public final PixelFormat pfmt;
315
316 @Override
317 public final int hashCode() {
318 // 31 * x == (x << 5) - x
319 int hash = pfmt.hashCode();
320 hash = ((hash << 5) - hash) + format;
321 return ((hash << 5) - hash) + type;
322 }
323
324 @Override
325 public final boolean equals(final Object obj) {
326 if(this == obj) { return true; }
327 if( obj instanceof GLPixelAttributes ) {
328 final GLPixelAttributes other = (GLPixelAttributes) obj;
329 return format == other.format &&
330 type == other.type &&
331 pfmt.equals(other.pfmt);
332 } else {
333 return false;
334 }
335 }
336
337 /**
338 * Create a new {@link GLPixelAttributes} instance based on GL format and type.
339 * @param dataFormat GL data format
340 * @param dataType GL data type
341 * @throws GLException if {@link PixelFormat} could not be determined, see {@link #getPixelFormat(int, int)}.
342 */
343 public GLPixelAttributes(final int dataFormat, final int dataType) throws GLException {
344 this(null, null, dataFormat, dataType, true /* not used */, true);
345 }
346
347 /**
348 * Create a new {@link GLPixelAttributes} instance based on {@link GLProfile}, {@link PixelFormat} and {@code pack}.
349 * @param glp the corresponding {@link GLProfile}
350 * @param pixFmt the to be matched {@link PixelFormat pixel format}
351 * @param pack {@code true} for read mode GPU -> CPU, e.g. {@link GL#glReadPixels(int, int, int, int, int, int, Buffer) glReadPixels}.
352 * {@code false} for write mode CPU -> GPU, e.g. {@link GL#glTexImage2D(int, int, int, int, int, int, int, int, Buffer) glTexImage2D}.
353 * @throws GLException if GL format or type could not be determined, see {@link #convert(GLProfile, PixelFormat, boolean)}.
354 */
355 public GLPixelAttributes(final GLProfile glp, final PixelFormat pixFmt, final boolean pack) throws GLException {
356 this(glp, pixFmt, 0, 0, pack, true);
357 }
358
359 private GLPixelAttributes(final GLProfile glp, final PixelFormat pixFmt,
360 final int dataFormat, final int dataType, final boolean pack, final boolean checkArgs) throws GLException {
361 if( checkArgs && ( 0 == dataFormat || 0 == dataType ) ) {
362 if( null == pixFmt || null == glp ) {
363 throw new GLException("Zero format and/or type w/o pixFmt or glp: "+this);
364 }
365 final int[] df = new int[1];
366 final int[] dt = new int[1];
367 if( 0 == convert(glp, pixFmt, pack, df, dt) ) {
368 throw new GLException("Could not find format and type for "+pixFmt+" and "+glp+", "+this);
369 }
370 this.format = df[0];
371 this.type = dt[0];
372 this.pfmt = pixFmt;
373 } else {
374 this.format = dataFormat;
375 this.type = dataType;
376 this.pfmt = null != pixFmt ? pixFmt : getPixelFormat(dataFormat, dataType);
377 if( null == this.pfmt ) {
378 throw new GLException("Could not find PixelFormat for format and/or type: "+this);
379 }
380 }
381 if( checkArgs ) {
382 final int bytesPerPixel = GLBuffers.bytesPerPixel(this.format, this.type);
383 if( 0 == bytesPerPixel ) {
384 throw new GLException("Zero bytesPerPixel: "+this);
385 }
386 }
387 }
388
389 @Override
390 public String toString() {
391 return "PixelAttributes[fmt 0x"+Integer.toHexString(format)+", type 0x"+Integer.toHexString(type)+", "+pfmt+"]";
392 }
393 }
394
395 /** The {@link GLPixelAttributes}. */
397 /**
398 * Width in pixels, representing {@link #buffer}'s {@link #byteSize}.
399 * <p>
400 * May not represent actual image width as user may re-use buffer for different dimensions, see {@link #requiresNewBuffer(GL, int, int, int)}.
401 * </p>
402 */
403 public final int width;
404 /**
405 * Height in pixels, representing {@link #buffer}'s {@link #byteSize}.
406 * <p>
407 * May not represent actual image height as user may re-use buffer for different dimensions, see {@link #requiresNewBuffer(GL, int, int, int)}.
408 * </p>
409 */
410 public final int height;
411 /** Depth in pixels. */
412 public final int depth;
413 /**
414 * Data packing direction.
415 * <p>{@code true} for read mode GPU -> CPU, e.g. {@link GL#glReadPixels(int, int, int, int, int, int, Buffer) glReadPixels}.</p>
416 * <p>{@code false} for write mode CPU -> GPU, e.g. {@link GL#glTexImage2D(int, int, int, int, int, int, int, int, Buffer) glTexImage2D}.</p>
417 */
418 public final boolean pack;
419 /** Byte size of the buffer. Actually the number of {@link Buffer#remaining()} bytes when passed in ctor. */
420 public final int byteSize;
421 /**
422 * Buffer holding the pixel data. If {@link #rewind()}, it holds <code>byteSize</code> {@link Buffer#remaining()} bytes.
423 * <p>
424 * By default the {@link Buffer} is a {@link ByteBuffer}, due to {@link DefProvider#allocate(GL, PixelFormat.Composition, GLPixelAttributes, boolean, int, int, int, int)}.
425 * However, other {@link GLPixelBufferProvider} may utilize different {@link Buffer} types.
426 * </p>
427 */
428 public final Buffer buffer;
429 /** Buffer element size in bytes. */
430 public final int bufferElemSize;
431
432 /** Allow {@link GL2ES3#GL_PACK_ROW_LENGTH}, or {@link GL2ES2#GL_UNPACK_ROW_LENGTH}. See {@link #requiresNewBuffer(GL, int, int, int)}. */
433 public final boolean allowRowStride;
434
435 private boolean disposed = false;
436
437 public StringBuilder toString(StringBuilder sb) {
438 if(null == sb) {
439 sb = new StringBuilder();
440 }
441 sb.append(pixelAttributes).append(", dim ").append(width).append("x").append(height).append("x").append(depth).append(", pack ").append(pack)
442 .append(", disposed ").append(disposed).append(", valid ").append(isValid())
443 .append(", buffer[bytes ").append(byteSize).append(", elemSize ").append(bufferElemSize).append(", ").append(buffer).append("]");
444 return sb;
445 }
446 @Override
447 public String toString() {
448 return "GLPixelBuffer["+toString(null).toString()+"]";
449 }
450
451 /**
452 * @param pixelAttributes the desired {@link GLPixelAttributes}
453 * @param pack {@code true} for read mode GPU -> CPU, e.g. {@link GL#glReadPixels(int, int, int, int, int, int, Buffer) glReadPixels}.
454 * {@code false} for write mode CPU -> GPU, e.g. {@link GL#glTexImage2D(int, int, int, int, int, int, int, int, Buffer) glTexImage2D}.
455 * @param width in pixels
456 * @param height in pixels
457 * @param depth in pixels
458 * @param buffer the backing array
459 * @param allowRowStride If <code>true</code>, allow row-stride, otherwise not. See {@link #requiresNewBuffer(GL, int, int, int)}.
460 * @param hostPixelComp the host {@link PixelFormat.Composition}
461 */
462 public GLPixelBuffer(final GLPixelAttributes pixelAttributes, final boolean pack, final int width, final int height, final int depth, final Buffer buffer, final boolean allowRowStride) {
463 this.pixelAttributes = pixelAttributes;
464 this.width = width;
465 this.height = height;
466 this.depth = depth;
467 this.pack = pack;
468 this.buffer = buffer;
469 this.byteSize = Buffers.remainingBytes(buffer);
470 this.bufferElemSize = Buffers.sizeOfBufferElem(buffer);
471 this.allowRowStride = allowRowStride;
472 }
473
474 /** Allow {@link GL2ES3#GL_PACK_ROW_LENGTH}, or {@link GL2ES2#GL_UNPACK_ROW_LENGTH}. */
475 public final boolean getAllowRowStride() { return allowRowStride; }
476
477 /** Is not {@link #dispose() disposed} and has {@link #byteSize} &gt; 0. */
478 public boolean isValid() {
479 return !disposed && 0 < byteSize;
480 }
481
482 /** See {@link Buffer#rewind()}. */
483 public Buffer rewind() {
484 return buffer.rewind();
485 }
486
487 /** Returns the byte position of the {@link #buffer}. */
488 public int position() {
489 return buffer.position() * bufferElemSize;
490 }
491
492 /** Sets the byte position of the {@link #buffer}. */
493 public Buffer position(final int bytePos) {
494 return buffer.position( bytePos / bufferElemSize );
495 }
496
497 /** Returns the byte capacity of the {@link #buffer}. */
498 public int capacity() {
499 return buffer.capacity() * bufferElemSize;
500 }
501
502 /** Returns the byte limit of the {@link #buffer}. */
503 public int limit() {
504 return buffer.limit() * bufferElemSize;
505 }
506
507 /** See {@link Buffer#flip()}. */
508 public Buffer flip() {
509 return buffer.flip();
510 }
511
512 /** See {@link Buffer#clear()}. */
513 public Buffer clear() {
514 return buffer.clear();
515 }
516
517 /**
518 * Returns true, if {@link #isValid() invalid} or implementation requires a new buffer based on the new size
519 * due to pixel alignment or byte size, otherwise false.
520 * <p>
521 * It is assumed that <code>pixelAttributes</code>, <code>depth</code> and <code>pack</code> stays the same!
522 * </p>
523 * <p>
524 * The minimum required byte size equals to <code>minByteSize</code>, if &gt; 0,
525 * otherwise {@link GLBuffers#sizeof(GL, int[], int, int, int, int, int, boolean) GLBuffers.sizeof(..)}
526 * is being used to calculate it. This value is referred to <i>newByteSize</i>.
527 * </p>
528 * <p>
529 * If <code>{@link #allowRowStride} = false</code>,
530 * method returns <code>true</code> if the <i>newByteSize</i> &gt; <i>currentByteSize</i>
531 * or the <code>newWidth</code> != <code>currentWidth</code>.
532 * </p>
533 * <p>
534 * If <code>{@link #allowRowStride} = true</code>, see {@link GLPixelBufferProvider#getAllowRowStride()},
535 * method returns <code>true</code> only if the <i>newByteSize</i> &gt; <i>currentByteSize</i>.
536 * Assuming user utilizes the row-stride when dealing w/ the data, i.e. {@link GL2ES3#GL_PACK_ROW_LENGTH}.
537 * </p>
538 * @param gl the corresponding current GL context object
539 * @param newWidth new width in pixels
540 * @param newHeight new height in pixels
541 * @param newByteSize if &gt; 0, the pre-calculated minimum byte-size for the resulting buffer, otherwise ignore.
542 * @see GLPixelBufferProvider#allocate(GL, PixelFormat.Composition, GLPixelAttributes, boolean, int, int, int, int)
543 */
544 public boolean requiresNewBuffer(final GL gl, final int newWidth, final int newHeight, int newByteSize) {
545 if( !isValid() ) {
546 return true;
547 }
548 if( 0 >= newByteSize ) {
549 final int[] tmp = { 0 };
550 newByteSize = GLBuffers.sizeof(gl, tmp, pixelAttributes.pfmt.comp.bytesPerPixel(), newWidth, newHeight, 1, true);
551 }
552 if( allowRowStride ) {
553 return byteSize < newByteSize;
554 }
555 return byteSize < newByteSize || width != newWidth;
556 }
557
558 /** Dispose resources. See {@link #isValid()}. */
559 public void dispose() {
560 disposed = true;
561 buffer.clear();
562 }
563 };
564
566 private:
567 bool m_allowRowStride;
568
569 public:
570 /**
571 * @param allowRowStride If <code>true</code>, allow row-stride, otherwise not.
572 * See {@link #getAllowRowStride()} and {@link GLPixelBuffer#requiresNewBuffer(GL, int, int, int)}.
573 */
574 DefaultGLPixelBufferProvider(bool allowRowStride)
575 : m_allowRowStride(allowRowStride) {}
576
577 bool getAllowRowStride() const noexcept override { return m_allowRowStride; }
578
579 @Override
580 public GLPixelAttributes getAttributes(final GL gl, final int componentCount, final boolean pack) {
581 final GLPixelAttributes res = GLPixelAttributes.convert(gl, componentCount, pack);
582 if( null == res ) {
583 throw new GLException("Unsupported componentCount "+componentCount+", contact maintainer to enhance");
584 } else {
585 return res;
586 }
587 }
588
589 /**
590 * {@inheritDoc}
591 * <p>
592 * Returns {@code null}!
593 * </p>
594 */
595 @Override
596 public PixelFormat.Composition getHostPixelComp(final GLProfile glp, final int componentCount) {
597 return null;
598 }
599
600 /**
601 * {@inheritDoc}
602 * <p>
603 * Returns an NIO {@link ByteBuffer}.
604 * </p>
605 */
606 @Override
607 public GLPixelBuffer allocate(final GL gl, final PixelFormat.Composition hostPixComp, final GLPixelAttributes pixelAttributes,
608 final boolean pack, final int width, final int height, final int depth, final int minByteSize) {
609 // unused: hostPixComp
610 if( minByteSize > 0 ) {
611 return new GLPixelBuffer(pixelAttributes, pack, width, height, depth, Buffers.newDirectByteBuffer(minByteSize), getAllowRowStride());
612 } else {
613 final int[] tmp = { 0 };
614 final int byteSize = GLBuffers.sizeof(gl, tmp, pixelAttributes.pfmt.comp.bytesPerPixel(), width, height, depth, pack);
615 return new GLPixelBuffer(pixelAttributes, pack, width, height, depth, Buffers.newDirectByteBuffer(byteSize), getAllowRowStride());
616 }
617 }
618 }
619
620 /**
621 * Default {@link GLPixelBufferProvider} with {@link GLPixelBufferProvider#getAllowRowStride()} == <code>false</code>,
622 * utilizing best match for {@link GLPixelAttributes}
623 * and {@link GLPixelBufferProvider#allocate(GL, PixelFormat.Composition, GLPixelAttributes, boolean, int, int, int, int) allocating} a {@link ByteBuffer}.
624 */
626
627 /**
628 * Default {@link GLPixelBufferProvider} with {@link GLPixelBufferProvider#getAllowRowStride()} == <code>true</code>,
629 * utilizing best match for {@link GLPixelAttributes}
630 * and {@link GLPixelBufferProvider#allocate(GL, PixelFormat.Composition, GLPixelAttributes, boolean, int, int, int, int) allocating} a {@link ByteBuffer}.
631 */
633
634} // namespace gamp::render::pixel::pixel
635
636#endif /* GAMP_RENDER_GL_PIXEL_GLPIXELBUFFER_HPP_ */
OpenGL Rendering Context.
Specifies the OpenGL profile.
Definition GLContext.hpp:42
constexpr bool isGLES() const noexcept
Indicates whether this profile is capable of GLES.
constexpr bool isGL2GL3() const noexcept
Indicates whether this profile is capable of GL2GL3.
constexpr bool isGL3ES3() const noexcept
Indicates whether this profile is capable of GL3ES3.
Allows user to interface with another toolkit to define GLPixelAttributes and memory buffer to produc...
OpenGL pixel data buffer, allowing user to provide buffers via their GLPixelBufferProvider implementa...
Packed pixel composition, i.e.
boolean requiresNewBuffer(final GL gl, final int newWidth, final int newHeight, int newByteSize)
Returns true, if invalid or implementation requires a new buffer based on the new size due to pixel a...
int capacity()
Returns the byte capacity of the buffer.
final int byteSize
Byte size of the buffer.
final int bufferElemSize
Buffer element size in bytes.
final int height
Height in pixels, representing buffer's byteSize.
final boolean pack
Data packing direction.
GLPixelAttributes getAttributes(final GL gl, final int componentCount, final boolean pack)
int position()
Returns the byte position of the buffer.
gamp::render::gl::pixel::DefaultGLPixelBufferProvider defaultProviderNoRowStride
Default GLPixelBufferProvider with GLPixelBufferProvider#getAllowRowStride() == false,...
GLPixelAttributes(final int dataFormat, final int dataType)
Create a new GLPixelAttributes instance based on GL format and type.
GLPixelBuffer(final GLPixelAttributes pixelAttributes, final boolean pack, final int width, final int height, final int depth, final Buffer buffer, final boolean allowRowStride)
StringBuilder toString(StringBuilder sb)
final PixelFormat pfmt
PixelFormat describing the component layout
boolean isValid()
Is not disposed and has byteSize > 0.
std::shared_ptr< GLPixelBuffer > GLPixelBufferRef
static GLPixelAttributes convert(final GL gl, final int componentCount, final boolean pack)
Returns the matching GLPixelAttributes for the given byte sized RGBA componentCount and GL if exists,...
Buffer rewind()
See Buffer#rewind().
static final GLPixelBufferProvider defaultProviderWithRowStride
Default GLPixelBufferProvider with GLPixelBufferProvider#getAllowRowStride() == true,...
static final GLPixelAttributes UNDEF
Undefined instance of GLPixelAttributes, having componentCount:=0, format:=0 and type:= 0.
GLPixelBuffer allocate(final GL gl, final PixelFormat.Composition hostPixComp, final GLPixelAttributes pixelAttributes, final boolean pack, final int width, final int height, final int depth, final int minByteSize)
static class gamp::render::gl::pixel::GLPixelBuffer::GLPixelAttributes pixelAttributes
The GLPixelAttributes.
final int width
Width in pixels, representing buffer's byteSize.
int limit()
Returns the byte limit of the buffer.
GLPixelAttributes(final GLProfile glp, final PixelFormat pixFmt, final boolean pack)
Create a new GLPixelAttributes instance based on GLProfile, PixelFormat and pack.
Buffer position(final int bytePos)
Sets the byte position of the buffer.
final Buffer buffer
Buffer holding the pixel data.
final boolean getAllowRowStride()
Allow GL2ES3#GL_PACK_ROW_LENGTH, or GL2ES2#GL_UNPACK_ROW_LENGTH.
final boolean allowRowStride
Allow GL2ES3#GL_PACK_ROW_LENGTH, or GL2ES2#GL_UNPACK_ROW_LENGTH.
static final GLPixelAttributes convert(final GLProfile glp, final PixelFormat pixFmt, final boolean pack)
Returns the matching GLPixelAttributes for the given GLProfile, PixelFormat and pack if exists,...
PixelFormat Composition getHostPixelComp(final GLProfile glp, final int componentCount)
static final PixelFormat getPixelFormat(final int glFormat, final int glDataType)
Returns the matching PixelFormat for the given GL format and type if exists, otherwise returns null.
Buffer clear()
See Buffer#clear().