I have an application that uses GLSurfaceView to do some 3-D goodness in Android. I'd like the user to be able to take a screenshot. I think this snippet of code should be storing the pixel colors and storing them inside a bitmap. However, does anyone know how to access the gl10 element that the screen is using, so I can feed it into this function?
public static Bitmap savePixelsOnScreen(int x, int y, int width, int height, GL10 gl){
int b[]=new int[w*(y+h)];
int bt[]=new int[w*h];
IntBuffer ib=IntBuffer.wrap(b);
ib.position(0);
//gl.glReadPixels(x, y, w, h, GL10.GL_RGBA, GL10.GL_UNSIGNED_BYTE, ib);
gl.glReadPixels(x, 0, w, y+h, GL10.GL_RGBA, GL10.GL_UNSIGNED_BYTE, ib);
for(int i=0, k=0; i<h; i++, k++)
{//remember, that OpenGL bitmap is incompatible with Android bitmap
//and so, some correction need.
for(int j=0; j<w; j++)
{
int pix=b[i*w+j];
int pb=(pix>>16)&0xff;
int pr=(pix<<16)&0x00ff0000;
int pix1=(pix&0xff00ff00) | pr | pb;
bt[(h-k-1)*w+j]=pix1;
}
}
Bitmap sb=Bitmap.createBitmap(bt, w, h, Bitmap.Config.ARGB_8888);
return sb;
return bitmap;
I had tried to do this from within the Activity that calls the GLSurfaceView:
EGL10 egl = (EGL10)EGLContext.getEGL();
GL10 gl = (GL10)egl.eglGetCurrentContext().getGL();
But every element of the int buffer is zero so I think this is not correct.
put the code under draw(GL10 gl) method of your CClayer/CCNode class and also maintain boolean variable to draw it only once. Draw method will be called 60+ times per second.
Related
i can use the follow code to achieve convert OpenGL RGBA int array to android ARGB int array.
int b[]=new int[(int) (w*h)];
int bt[]=new int[(int) (w*h)];
IntBuffer buffer=IntBuffer.wrap(b);
buffer.position(0);
GLES20.glReadPixels(0, 0, w, h,GLES20.GL_RGBA,GLES20.GL_UNSIGNED_BYTE, buffer);
for(int i=0; i<h; i++)
{
//remember, that OpenGL bitmap is incompatible with Android bitmap
//and so, some correction need.
for(int j=0; j<w; j++)
{
int pix=b[i*w+j];
int pb=(pix>>16)&0xff;
int pr=(pix<<16)&0x00ff0000;
int pix1=(pix&0xff00ff00) | pr | pb;
bt[(h-i-1)*w+j]=pix1;
}
}
through i can use convert int array to byte array to achieve my goal,but efficiency is little low,so i want to use the follow code to achieve the same goal:
final ByteBuffer rgbaData = ByteBuffer.allocateDirect(WIDTH * HEIGHT * 4);
GLES20.glReadPixels(0, 0, WIDTH, HEIGHT, GLES20.GL_RGBA, GLES20.GL_UNSIGNED_BYTE, rgbaData),
I am using OpenGL render method to capture screenshot.but take it takes 7 to 8 seconds on NEXUS 7 to read pixel information. I am using this code to read pixel information and save it as Bitmap.
public Bitmap grabPixels(GL10 mGL) {
final int mWidth = mViewWidth;
final int mHeight = mViewHeight;
IntBuffer ib = IntBuffer.allocate(mWidth * mHeight);
IntBuffer ibt = IntBuffer.allocate(mWidth * mHeight);
mGL.glReadPixels(0, 0, mWidth, mHeight, GL10.GL_RGBA, GL10.GL_UNSIGNED_BYTE, ib);
for (int i = 0; i < mHeight; i++) {
for (int j = 0; j < mWidth; j++) {
ibt.put((mHeight - i - 1) * mWidth + j, ib.get(i * mWidth + j));
}
}
Bitmap mBitmap = Bitmap.createBitmap(mWidth, mHeight, Bitmap.Config.ARGB_8888);
mBitmap.copyPixelsFromBuffer(ibt);
return mBitmap;
}
How can i increase speed of reading the pixel information and convert it into the Bitmap ?
I wrote another answer about saving GIFs on gamedev, which might be useful.
You can't call glReadPixels() on another thread. But it's most likely (as you said) the process of saving the image that takes the majority of time. As such the solution is to do the saving on a separate thread.
new Thread(new Runnable() {
#Override
public void run() {
... save screenshot ...
}
}).start();
Before anybody comes at me with pitchforks. Then yes you can call glReadPixels() on another thread. It however requires a shared context, which can be specified when calling eglCreateContext().
EGLContext shared = ...
EGLDisplay display = ...
EGLConfig eglConfig = ...
int[] attrib_list = { EGL_CONTEXT_CLIENT_VERSION, 2, EGL10.EGL_NONE };
EGLContext context = egl.eglCreateContext(display, eglConfig, shared, attrib_list);
But before you start digging into shared contexts (which can be a pain in themselves) then make sure your bottleneck isn't the saving the image, which it most likely is.
I'd like to get access to the main (OpenGL) screen in Android to implement some overlay 3D effects.
Is it possible to do so?
If yes, how can I do it?
When amending this context, my application should be a service, right?
You cannot get access to the framebuffer, for obvious security reasons.
What you will probably want to do is research the glReadPixels() function. I ran a test where I had the screen split with a glsurfaceview and image view and wanted to see if I could grab the pixels from the glview and create a Bitmap and then apply that to the ImageView. After some research, I found using glReadPixels() works, but you have to tranform the pixels before using them for an android bitmap. This is the method I ended up using. I'm confident that I found it exactly this way on another forum.
public Bitmap SaveGLPixels(int x, int y, int w, int h, GL10 gl)
{
int b[]=new int[w*h];
int bt[]=new int[w*h];
IntBuffer ib=IntBuffer.wrap(b);
ib.position(0);
gl.glReadPixels(x, y, w, h, GL10.GL_RGBA, GL10.GL_UNSIGNED_BYTE, ib);
for(int i=0; i<h; i++)
{//remember, that OpenGL bitmap is incompatible with Android bitmap
//and so, some correction need.
for(int j=0; j<w; j++)
{
int pix=b[i*w+j];
int pb=(pix>>16)&0xff;
int pr=(pix<<16)&0x00ff0000;
int pix1=(pix&0xff00ff00) | pr | pb;
bt[(h-i-1)*w+j]=pix1;
}
}
Bitmap.Config bconfig = Bitmap.Config.RGB_565;
Bitmap sb=Bitmap.createBitmap(bt, w, h, bconfig);
return sb;
}
I'm currently developing an augmented reality application in android. Textured openGL object is drawn over the camera view. I had tried so many methods to take the screen shot of android openGL view (GLSurfaceview). But no success. I want the screenshot with transparent background so that I could draw it over camera image to produce an ARImage. Can any one help me? I know that I have to read the pixels of opengl using glReadPixels() function. I tried it using GL_RGBA mode and created bitmap (used ARGB_8888 and RGB_565). Using ARGB_8888 format I'll get a transparent image with no object and in RGB_565 mode I'll get a image filled with black color. Can any one guide me? Thanks in advance.
Thanks,
Midhun
Hi I found the solution to my question and I'll paste the code here. It may be useful for others who need alpha support.
public static Bitmap SavePixels(int x, int y, int w, int h, GL10 gl)
{
int b[]=new int[w*(y+h)];
int bt[]=new int[w*h];
IntBuffer ib=IntBuffer.wrap(b);
ib.position(0);
gl.glReadPixels(x, 0, w, y+h, GL10.GL_RGBA, GL10.GL_UNSIGNED_BYTE, ib);
for(int i=0, k=0; i<h; i++, k++)
{//remember, that OpenGL bitmap is incompatible with Android bitmap
//and so, some correction need.
for(int j=0; j<w; j++)
{
int pix=b[i*w+j];
int pb=(pix>>16)&0xff;
int pr=(pix<<16)&0x00ff0000;
int pix1=(pix&0xff00ff00) | pr | pb;
bt[(h-k-1)*w+j]=pix1;
}
}
Bitmap sb=Bitmap.createBitmap(bt, w, h, Bitmap.Config.ARGB_8888);
return sb;
}
This so called "solution" is simply making a screen shot. Alpha values that you get from glReadPixels are up to full 255 although you didn't draw anything to those pixels. If it's possible it will be an OpenGL-settings solution.
I've searched a lot about taking screenshot of my OpenGL object on Android and come up with this solution. It worked great but in my case I have camera view and opengl view(with transparent background) on top of camera view. So what I want to do is to get opengl screenshot with transparent background instead of black.
As I said I have tried link above and it worked but I'm stuck with black background. It's little bit complicated to figure out how to get rid of the black background in this particular case.
Hope somebody could help me and asap if it's possible(also I think the solution is easy, I'm just missing something simple).
Thank you.
I used following method and worked like a champ.
public static Bitmap SavePixels(int x, int y, int w, int h, GL10 gl)
{
int b[]=new int[w*(y+h)];
int bt[]=new int[w*h];
IntBuffer ib=IntBuffer.wrap(b);
ib.position(0);
gl.glReadPixels(x, 0, w, y+h, GL10.GL_RGBA, GL10.GL_UNSIGNED_BYTE, ib);
for(int i=0, k=0; i<h; i++, k++)
{//remember, that OpenGL bitmap is incompatible with Android bitmap
//and so, some correction need.
for(int j=0; j<w; j++)
{
int pix=b[i*w+j];
int pb=(pix>>16)&0xff;
int pr=(pix<<16)&0x00ff0000;
int pix1=(pix&0xff00ff00) | pr | pb;
bt[(h-k-1)*w+j]=pix1;
}
}
Bitmap sb=Bitmap.createBitmap(bt, w, h, Bitmap.Config.ARGB_8888);
return sb;
}
You just need to call
YourClass.SavePixels(0,0,width,height,gl);
I hope this will work for you...
Thanks,
Midhun
The solution you mentioned is using a Bitmap.Config.RGB_565 which doesn't support alpha channels.
Bitmap bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.RGB_565);
Instead you should use Bitmap.Config.ARGB_8888 or Bitmap.Config.ARGB_4444.