JOGL v2.6.0-rc-20250706
JOGL, High-Performance Graphics Binding for Java™ (public API).
GLReadBufferUtil.java
Go to the documentation of this file.
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
29package com.jogamp.opengl.util;
30
31import java.io.File;
32import java.io.IOException;
33
34import com.jogamp.nativewindow.util.PixelFormat;
35import com.jogamp.opengl.GL;
36import com.jogamp.opengl.GL2ES3;
37import com.jogamp.opengl.GLAutoDrawable;
38import com.jogamp.opengl.GLDrawable;
39import com.jogamp.opengl.GLException;
40
41import com.jogamp.common.nio.Buffers;
42import com.jogamp.opengl.util.texture.Texture;
43import com.jogamp.opengl.util.texture.TextureData;
44import com.jogamp.opengl.util.GLPixelBuffer;
45import com.jogamp.opengl.util.GLPixelBuffer.GLPixelAttributes;
46import com.jogamp.opengl.util.GLPixelBuffer.GLPixelBufferProvider;
47import com.jogamp.opengl.util.texture.TextureIO;
48
49/**
50 * Utility to read out the current FB to TextureData, optionally writing the data back to a texture object.
51 * <p>May be used directly to write the TextureData to file (screenshot).</p>
52 */
53public class GLReadBufferUtil {
55 protected final Texture readTexture;
56 protected final GLPixelStorageModes psm;
57 protected final boolean alphaRequested;
58
59 protected boolean hasAlpha;
61 protected TextureData readTextureData = null;
62 protected int readBuffer = -1;
63
64 /**
65 * Using the default {@link GLPixelBuffer}: {@link GLPixelBuffer#defaultProviderNoRowStride}.
66 *
67 * @param requestAlpha true for RGBA readPixels, otherwise RGB readPixels. Disclaimer: {@link #hasAlpha()}==true maybe forced depending on the used {@link GLPixelBufferProvider}, i.e. on ES platforms, when calling {@link #readPixels(GL, int, int, int, int, boolean) readPixels}.
68 * @param write2Texture true if readPixel's TextureData shall be written to a 2d Texture
69 */
70 public GLReadBufferUtil(final boolean requestAlpha, final boolean write2Texture) {
71 this(GLPixelBuffer.defaultProviderNoRowStride, requestAlpha, write2Texture);
72 }
73
74 /**
75 * @param pixelBufferProvider custom {@link GLPixelBuffer}
76 * @param requestAlpha true for RGBA readPixels, otherwise RGB readPixels. Disclaimer: {@link #hasAlpha()}==true maybe forced depending on the used {@link GLPixelBufferProvider}, i.e. on ES platforms, when calling {@link #readPixels(GL, int, int, int, int, boolean) readPixels}.
77 * @param write2Texture true if readPixel's TextureData shall be written to a 2d Texture
78 */
79 public GLReadBufferUtil(final GLPixelBufferProvider pixelBufferProvider, final boolean requestAlpha, final boolean write2Texture) {
80 this.pixelBufferProvider = pixelBufferProvider;
81 this.readTexture = write2Texture ? new Texture(GL.GL_TEXTURE_2D) : null ;
82 this.psm = new GLPixelStorageModes();
83 this.alphaRequested = requestAlpha;
84 this.hasAlpha = requestAlpha; // preset
85 }
86
87 public void setReadBuffer(final int name) { readBuffer = name; }
88
89 /** Returns the {@link GLPixelBufferProvider} used by this instance. */
91
92 public boolean isValid() {
93 return null!=readTextureData && null!=readPixelBuffer && readPixelBuffer.isValid();
94 }
95
96 /** Returns true if the OpenGL read data contains alpha. This value is lazily determined after the first call of {@link #readPixels(GL, int, int, int, int, boolean) readPixels} */
97 public boolean hasAlpha() { return hasAlpha; }
98
100
101 /**
102 * Returns the {@link GLPixelBuffer}, created and filled by {@link #readPixels(GLAutoDrawable, boolean)}.
103 */
105
106 /**
107 * rewind the raw pixel ByteBuffer
108 */
109 public void rewindPixelBuffer() { if( null != readPixelBuffer ) { readPixelBuffer.rewind(); } }
110
111 /**
112 * @return the resulting TextureData, filled by {@link #readPixels(GLAutoDrawable, boolean)}
113 */
115
116 /**
117 * @return the Texture object filled by {@link #readPixels(GLAutoDrawable, boolean)},
118 * if this instance writes to a 2d Texture, otherwise null.
119 * @see #GLReadBufferUtil(boolean, boolean)
120 */
121 public Texture getTexture() { return readTexture; }
122
123 /**
124 * Write the TextureData filled by {@link #readPixels(GLAutoDrawable, boolean)} to file
125 */
126 public void write(final File dest) {
127 try {
130 } catch (final IOException ex) {
131 throw new RuntimeException("can not write to file: " + dest.getAbsolutePath(), ex);
132 }
133 }
134
135 /**
136 * Read the drawable's pixels to TextureData and Texture, if requested at construction.
137 *
138 * @param gl the current GL context object. It's read drawable is being used as the pixel source.
139 * @param mustFlipVertically indicates whether to flip the data vertically or not.
140 * The context's drawable {@link GLDrawable#isGLOriented()} state
141 * is taken into account.
142 * Vertical flipping is propagated to TextureData
143 * and handled in a efficient manner there (TextureCoordinates and TextureIO writer).
144 *
145 * @see #GLReadBufferUtil(boolean, boolean)
146 */
147 public boolean readPixels(final GL gl, final boolean mustFlipVertically) {
148 return readPixels(gl, 0, 0, 0, 0, mustFlipVertically);
149 }
150
151 /**
152 * Read the drawable's pixels to TextureData and Texture, if requested at construction.
153 *
154 * @param gl the current GL context object. It's read drawable is being used as the pixel source.
155 * @param inX readPixel x offset
156 * @param inY readPixel y offset
157 * @param inWidth optional readPixel width value, used if [1 .. drawable.width], otherwise using drawable.width
158 * @param inHeight optional readPixel height, used if [1 .. drawable.height], otherwise using drawable.height
159 * @param mustFlipVertically indicates whether to flip the data vertically or not.
160 * The context's drawable {@link GLDrawable#isGLOriented()} state
161 * is taken into account.
162 * Vertical flipping is propagated to TextureData
163 * and handled in a efficient manner there (TextureCoordinates and TextureIO writer).
164 * @see #GLReadBufferUtil(boolean, boolean)
165 */
166 public boolean readPixels(final GL gl, final int inX, final int inY, final int inWidth, final int inHeight, final boolean mustFlipVertically) {
167 final GLDrawable drawable = gl.getContext().getGLReadDrawable();
168 final int width, height;
169 if( 0 >= inWidth || drawable.getSurfaceWidth() < inWidth ) {
170 width = drawable.getSurfaceWidth();
171 } else {
172 width = inWidth;
173 }
174 if( 0 >= inHeight || drawable.getSurfaceHeight() < inHeight ) {
175 height = drawable.getSurfaceHeight();
176 } else {
177 height= inHeight;
178 }
179 return readPixelsImpl(drawable, gl, inX, inY, width, height, mustFlipVertically);
180 }
181
182 protected boolean readPixelsImpl(final GLDrawable drawable, final GL gl,
183 final int inX, final int inY, final int width, final int height,
184 final boolean mustFlipVertically) {
185 final int glerr0 = gl.glGetError();
186 if(GL.GL_NO_ERROR != glerr0) {
187 System.err.println("Info: GLReadBufferUtil.readPixels: pre-exisiting GL error 0x"+Integer.toHexString(glerr0));
188 }
189 final int reqCompCount = alphaRequested ? 4 : 3; // see Bug 1381: we keep host PixelFormat functional using requested immutable alphaRequested
190 final PixelFormat.Composition hostPixelComp = pixelBufferProvider.getHostPixelComp(gl.getGLProfile(), reqCompCount);
191 final GLPixelAttributes pixelAttribs = pixelBufferProvider.getAttributes(gl, reqCompCount, true);
192 final int componentCount = pixelAttribs.pfmt.comp.componentCount();
193 hasAlpha = 0 <= pixelAttribs.pfmt.comp.find(PixelFormat.CType.A);
194 final int alignment, internalFormat;
195 if( 4 == componentCount ) {
196 alignment = 4;
197 internalFormat = GL.GL_RGBA;
198 } else {
199 alignment = 1;
200 internalFormat = GL.GL_RGB;
201 }
202 final boolean flipVertically;
203 if( drawable.isGLOriented() ) {
204 flipVertically = mustFlipVertically;
205 } else {
206 flipVertically = !mustFlipVertically;
207 }
208
209 final int tmp[] = new int[1];
210 final int readPixelSize = GLBuffers.sizeof(gl, tmp, pixelAttribs.pfmt.comp.bytesPerPixel(), width, height, 1, true);
211
212 boolean newData = false;
213 if( null == readPixelBuffer || readPixelBuffer.requiresNewBuffer(gl, width, height, readPixelSize) ) {
214 readPixelBuffer = pixelBufferProvider.allocate(gl, hostPixelComp, pixelAttribs, true, width, height, 1, readPixelSize);
215 Buffers.rangeCheckBytes(readPixelBuffer.buffer, readPixelSize);
216 try {
218 gl.getGLProfile(),
219 internalFormat,
220 width, height,
221 0,
222 pixelAttribs,
223 false, false,
224 flipVertically,
226 null /* Flusher */);
227 newData = true;
228 } catch (final Exception e) {
229 readTextureData = null;
230 readPixelBuffer = null;
231 throw new RuntimeException("can not fetch offscreen texture", e);
232 }
233 } else {
234 readTextureData.setInternalFormat(internalFormat);
238 }
239 boolean res = null!=readPixelBuffer && readPixelBuffer.isValid();
240 if(res) {
241 psm.setPackAlignment(gl, alignment);
242 if(gl.isGL2ES3()) {
243 final GL2ES3 gl2es3 = gl.getGL2ES3();
244 psm.setPackRowLength(gl2es3, width);
245 if( 0 > readBuffer ) {
246 gl2es3.glReadBuffer(gl2es3.getDefaultReadBuffer());
247 } else {
248 gl2es3.glReadBuffer(readBuffer);
249 }
250 }
252 try {
253 gl.glReadPixels(inX, inY, width, height, pixelAttribs.format, pixelAttribs.type, readPixelBuffer.buffer);
254 } catch(final GLException gle) { res = false; gle.printStackTrace(); }
255 readPixelBuffer.position( readPixelSize );
257 final int glerr1 = gl.glGetError();
258 if(GL.GL_NO_ERROR != glerr1) {
259 System.err.println("GLReadBufferUtil.readPixels: readPixels error 0x"+Integer.toHexString(glerr1)+
260 " "+width+"x"+height+
261 ", "+pixelAttribs+
262 ", "+readPixelBuffer+", sz "+readPixelSize);
263 res = false;
264 }
265 if(res && null != readTexture) {
266 if(newData) {
268 } else {
270 inX, inY, // dst offset
271 0, 0, // src offset
272 width, height);
273 }
275 }
276 psm.restore(gl);
277 }
278 return res;
279 }
280
281 public void dispose(final GL gl) {
282 if(null != readTexture) {
284 readTextureData = null;
285 }
286 if(null != readPixelBuffer) {
288 readPixelBuffer = null;
289 }
290 }
291
292}
abstract GLDrawable getGLReadDrawable()
Returns the read-Drawable this context uses for read framebuffer operations.
A generic exception for OpenGL errors used throughout the binding as a substitute for RuntimeExceptio...
Utility routines for dealing with direct buffers.
Definition: GLBuffers.java:60
static final int sizeof(final GL gl, final int tmp[], final int bytesPerPixel, int width, int height, int depth, final boolean pack)
Returns the number of bytes required to read/write a memory buffer via OpenGL using the current GL pi...
Definition: GLBuffers.java:364
final PixelFormat pfmt
PixelFormat describing the component layout
final int format
The OpenGL pixel data format.
OpenGL pixel data buffer, allowing user to provide buffers via their GLPixelBufferProvider implementa...
int position()
Returns the byte position of the buffer.
Buffer flip()
See Buffer#flip().
void dispose()
Dispose resources.
static final GLPixelBufferProvider defaultProviderNoRowStride
Default GLPixelBufferProvider with GLPixelBufferProvider#getAllowRowStride() == false,...
Buffer rewind()
See Buffer#rewind().
Buffer clear()
See Buffer#clear().
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...
boolean isValid()
Is not disposed and has byteSize > 0.
final Buffer buffer
Buffer holding the pixel data.
Utility to safely set and restore the PACK and UNPACK pixel storage mode, regardless of the GLProfile...
final void setPackRowLength(final GL2ES3 gl, final int packRowLength)
Sets the GL2ES3#GL_PACK_ROW_LENGTH.
final void restore(final GL gl)
Restores PACK and UNPACK pixel storage mode previously saved w/ saveAll(GL) or savePack(GL) and saveU...
final void setPackAlignment(final GL gl, final int packAlignment)
Sets the GL#GL_PACK_ALIGNMENT.
Utility to read out the current FB to TextureData, optionally writing the data back to a texture obje...
boolean hasAlpha()
Returns true if the OpenGL read data contains alpha.
void rewindPixelBuffer()
rewind the raw pixel ByteBuffer
void write(final File dest)
Write the TextureData filled by readPixels(GLAutoDrawable, boolean) to file.
boolean readPixels(final GL gl, final int inX, final int inY, final int inWidth, final int inHeight, final boolean mustFlipVertically)
Read the drawable's pixels to TextureData and Texture, if requested at construction.
GLPixelBufferProvider getPixelBufferProvider()
Returns the GLPixelBufferProvider used by this instance.
boolean readPixelsImpl(final GLDrawable drawable, final GL gl, final int inX, final int inY, final int width, final int height, final boolean mustFlipVertically)
GLPixelBuffer getPixelBuffer()
Returns the GLPixelBuffer, created and filled by readPixels(GLAutoDrawable, boolean).
GLReadBufferUtil(final boolean requestAlpha, final boolean write2Texture)
Using the default GLPixelBuffer: GLPixelBuffer#defaultProviderNoRowStride.
GLReadBufferUtil(final GLPixelBufferProvider pixelBufferProvider, final boolean requestAlpha, final boolean write2Texture)
boolean readPixels(final GL gl, final boolean mustFlipVertically)
Read the drawable's pixels to TextureData and Texture, if requested at construction.
final GLPixelBufferProvider pixelBufferProvider
Represents the data for an OpenGL texture.
void setHeight(final int height)
Sets the height in pixels of the texture data.
void setPixelAttributes(final GLPixelAttributes pixelAttributes)
Sets the intended OpenGL pixel format of the texture data.
void setInternalFormat(final int internalFormat)
Sets the intended OpenGL internal format of the texture data.
void setWidth(final int width)
Sets the width in pixels of the texture data.
static void write(final Texture texture, final File file)
Writes the given texture to a file.
Definition: TextureIO.java:607
Represents an OpenGL texture object.
Definition: Texture.java:173
void updateImage(final GL gl, final TextureData data)
Updates the entire content area incl.
Definition: Texture.java:524
void destroy(final GL gl)
Destroys and nulls the underlying native texture used by this Texture instance if owned,...
Definition: Texture.java:388
void updateSubImage(final GL gl, final TextureData data, final int mipmapLevel, final int x, final int y)
Updates a subregion of the content area of this texture using the given data.
Definition: Texture.java:818
final Composition comp
Unique Pixel Composition, i.e.
int componentCount()
Number of components per pixel, e.g.
int bytesPerPixel()
Number of bytes per pixel, i.e.
int find(final PixelFormat.CType s)
Returns the index of given CType within componentOrder(), -1 if not exists.
void glReadBuffer(int mode)
Entry point to C language function: void {@native glReadBuffer}(GLenum mode) Part of GL_ES_VERSION...
boolean isGL2ES3()
Indicates whether this GL object conforms to a either a GL2GL3 or GL3ES3 compatible profile.
GLProfile getGLProfile()
Returns the GLProfile associated with this GL object.
GLContext getContext()
Returns the GLContext associated which this GL object.
GL2ES3 getGL2ES3()
Casts this object to the GL2ES3 interface.
int getDefaultReadBuffer()
Returns the default color buffer within the current bound getDefaultReadFramebuffer(),...
An abstraction for an OpenGL rendering target.
Definition: GLDrawable.java:51
int getSurfaceWidth()
Returns the width of this GLDrawable's surface client area in pixel units.
boolean isGLOriented()
Returns true if the drawable is rendered in OpenGL's coordinate system, origin at bottom left.
int getSurfaceHeight()
Returns the height of this GLDrawable's surface client area in pixel units.
void glReadPixels(int x, int y, int width, int height, int format, int type, Buffer pixels)
Entry point to C language function: void {@native glReadPixels}(GLint x, GLint y,...
static final int GL_RGB
GL_ES_VERSION_2_0, GL_VERSION_1_1, GL_VERSION_1_0, GL_VERSION_ES_1_0 Define "GL_RGB" with expression ...
Definition: GL.java:374
static final int GL_TEXTURE_2D
GL_ES_VERSION_2_0, GL_VERSION_1_1, GL_VERSION_1_0, GL_VERSION_ES_1_0 Define "GL_TEXTURE_2D" with expr...
Definition: GL.java:491
static final int GL_NO_ERROR
GL_ES_VERSION_2_0, GL_VERSION_1_1, GL_VERSION_1_0, GL_VERSION_ES_1_0 Define "GL_NO_ERROR" with expres...
Definition: GL.java:481
int glGetError()
Entry point to C language function: GLenum {@native glGetError}() Part of GL_ES_VERSION_2_0,...
static final int GL_RGBA
GL_ES_VERSION_2_0, GL_VERSION_1_1, GL_VERSION_1_0, GL_VERSION_ES_1_0 Define "GL_RGBA" with expression...
Definition: GL.java:150
Allows user to interface with another toolkit to define GLPixelAttributes and memory buffer to produc...
GLPixelBuffer allocate(GL gl, PixelFormat.Composition hostPixComp, GLPixelAttributes pixelAttributes, boolean pack, int width, int height, int depth, int minByteSize)
Allocates a new GLPixelBuffer object.
GLPixelAttributes getAttributes(GL gl, int componentCount, boolean pack)
Returns RGB[A] GLPixelAttributes matching GL, componentCount and pack.
PixelFormat.Composition getHostPixelComp(final GLProfile glp, final int componentCount)
Returns the host PixelFormat.Composition matching GL and componentCount if required by implementation...