Java Libgdx get screenshot very slow - java

I write a game for android using libgdx. If the user opens the pause menu I take a screenshot of the current game, blur it and use it as background for the options menu. This works fine but the code for getting the screenshot is very slow. It takes about 0.8 seconds on average using the code below...
Is there another way to take a screenshot in libgdx which is much faster?
If not, when the user opens the options menu I could try to just keep rendering the game, pause the game logic and blur the screen and draw the options on top.. If this is the only fast way, how could one blur the screen? I found this link but I didn't get it to work.
If it is possible I prefer the solution with the screenshot because it is much easier...
Code to get the screenshot (from official wiki):
public static Pixmap getScreenshot(){
long start = TimeUtils.millis();
byte[] pixels = ScreenUtils.getFrameBufferPixels(0, 0, Gdx.graphics.getBackBufferWidth(), Gdx.graphics.getBackBufferHeight(), true);
Pixmap pixmap = new Pixmap(Gdx.graphics.getBackBufferWidth(), Gdx.graphics.getBackBufferHeight(), Pixmap.Format.RGBA8888);
BufferUtils.copy(pixels, 0, pixmap.getPixels(), pixels.length);
long time = TimeUtils.millis()-start;
Gdx.app.log("INFO", "Time for screenshot in sec.: " + time); // about 0.8 seconds
return pixmap;
}
I use the resulting Pixmap to draw my texture.
EDIT:
My code now with the answer of Deniz Yılmaz for getting the screenshot fast:
public Texture getScreenshot(){
Texture texture = new Texture(Gdx.graphics.getWidth(), Gdx.graphics.getHeight(), Pixmap.Format.RGB888);
Gdx.gl.glEnable(GL20.GL_TEXTURE_2D);
Gdx.gl.glActiveTexture(GL20.GL_TEXTURE0);
texture.bind();
Gdx.gl.glCopyTexImage2D(GL20.GL_TEXTURE_2D, 0, GL20.GL_RGB, 0, 0,Gdx.graphics.getWidth(), Gdx.graphics.getHeight(), 0);
Gdx.gl.glDisable(GL20.GL_TEXTURE_2D);
return texture;
}

Actually taking screenshot is not slow.
Slow part is data transfer between GPU and CPU so any other way to get pixels wont be faster so much.
But also there are openGl codes helping us right here.
You can use opengl codes via Gdx.gl class.
void glCopyTexImage2D(
GLenum target, //Target Opengl Texture
GLint level, //Mipmap level
GLenum internalformat, //Color format
GLint x,
GLint y,
GLsizei width,
GLsizei height,
GLint border);
This function copy pixels into a 2D texture image but not bringing them to CPU.
You just belong a FBO at GPU.
In libgdx first you must bind texture to openGl's texture with a method.
This texture can be empty screen sized texture or you can use old texture you wont use again.
Texture.bind();
or
Gdx.gl.glBindTexture(Opengltexture, texture.getTextureObjectHandle());
For bounding and taking screen
Enable GPUtexture type.
Activate for exact GPUtexture
Call texture bind method
Call opengl function for active GPUtexture
Disable GPUtexture type.
Here is what code look like :
Gdx.gl.glEnable(GL20.GL_TEXTURE_2D);
Gdx.gl.glActiveTexture(GL20.GL_TEXTURE0);
texture.bind();
Gdx.gl.glCopyTexImage2D(GL20.GL_TEXTURE_2D, 0, GL20.GL_RGBA,0, 0,width , height, 0);
Gdx.gl.glDisable(GL20.GL_TEXTURE_2D);
Be aware binding is only active in 1 and 5. My fault was here because i tried to bind texture in create method and had got black screen.
BE AWARE!!!
On android, it needs opengl es 2.0 . You can edit manifest to make sure unsupported devices cant download your game.
< uses-feature android:glEsVersion="0x00020000"
android:required="true" >
RGBA format color space doesnt supported. So make sure you are
using Format.RGB for both opengl function and texture creation.
Result texture will be flipped vertically because of openGl matrix
system. So you have to fix it manually.
I also suggest you to look at fragments and shaders.
It seems like hard but actually enjoyable.

Related

LibGDX - Basic 2D lighting, don't know what to do

It's my first time attempting to create a basic light system that uses a black texture with a white circle on top. I read various threads about the issue but I just don't know what I am doing wrong.
What I want is the ambient to be dark and the light to be well white but changing the spritebatch color to something darker will cause the light to be darker to EVEN if I reset the color when drawing the light texture
So this is what I want (did this by forcing the light texture draw 5 times but that isn't a solution, it's an hack):
This is what I get (only 1 light texture is drawn but isn't very visible):
This is what I get without darkening the spritebatch:
Main code:
Game.sb.begin();
//Make stuff darker
Game.sb.setColor(0.1f, 0.1f, 0.1f,1f);
sb.setBlendFunction(GL20.GL_SRC_ALPHA, GL20.GL_ONE_MINUS_SRC_ALPHA);
lvl.render();
//Reset color
Game.sb.setColor(1f, 1f, 1f,1f);
sb.setBlendFunction(GL20.GL_DST_COLOR, GL20.GL_SRC_ALPHA);
//This draws all lights by drawing a texture with the above blending function
lightM.render();
Game.sb.end();
Light object draw method:
Game.sb.setColor(c.r,c.b,c.g, 1f);
Utils.drawTexture(Assets.get("sprites/lightcircle2.png", Texture.class), pos, size, true);
Game.sb.setColor(1,1,1,1);
Am I making some kind of error with the setcolor? I been considering using a FrameBuffer but I am not sure if it will give me the light effect I want
By the way this is my light texture (it's CC0):
You can achieve your requirement by these ways :
By using Shaders. Here is a small video and article on that video.
By use FBO and Blending, Here is one of my answer on this topic.
You can use box2dlight, even without using box2dbody(if you don't want any shadows)
World world = new World(new Vector2(0,0),false);
RayHandler rayHandler = new RayHandler(world);
rayHandler.setCombinedMatrix(stage.getCamera().combined); //<-- pass your camera combined matrix
new PointLight(rayHandler,1000, Color.WHITE,radius,x_position,y_position);
And at last call rayHandler.updateAndRender(); after all your rendering in your render() method.

Stereo rendering a sphere with cardboard

I'm making a 360 media player with Cardboard SDK in android (actually I'm using the new GoogleVR SDK, but it works pretty much alike). To do this I'm following this code:
Everything works great with a monocular vision and with a stereo one when not distorted (cardboardView.setDistortionCorrectionEnabled(false)). But when I try to use the distortion correction it draws this:
I've found this in the GVR API:
If distortion correction is enabled the GL context will be set to draw
into a framebuffer backed by a texture at the time of this call, so if
an implementor need to change the framebuffer for some rendering stage
then the implementor must reset the framebuffer to the one obtained
via glGetIntegerv(GL_FRAMEBUFFER_BINDING, ...) afterwards.
But I'm not sure if this is related.
This is my onDrawEye code:
/**
* Draws a frame for an eye.
*
* #param eye The eye to render. Includes all required transformations.
*/
#Override
public void onDrawEye(Eye eye) {
GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT | GLES20.GL_DEPTH_BUFFER_BIT);
Matrix.multiplyMM(mView, 0, eye.getEyeView(), 0, mCamera, 0);
Matrix.multiplyMM(mViewProjectionMatrix, 0, mProjectionMatrix, 0, mView, 0);
mSphere.draw(mViewProjectionMatrix);
checkGLError("onDrawEye");
}
Any ideas how to solve this? Thanks so much
(By the way, if I draw a cube instead of a sphere everything works well)
Alright, almost 2 months later I finally solved my problem. If someone wants to know how, it was not a problem of gvr but how I was initializing my scene. Basically i moved every work in the Sphere constructor to the draw method but the shaders initiallization.

Does everything have to be a polygon in openGL (java)?

I am extremely new to JOGL, and I have two main questions about JOGL, the first is about sprites and animations and the next is about textures.
(I am not doing 3d, this is all in the contexts of 2d)
1.) I have been able to create quads, polygons, and so forth in JOGL, but I am very curious, is that the only way to get a type of image that you can manipulate out there? For instance if you want a sprite of a man to appear in JOGL, and when you move the sprite it will move in the direction you make it but also display an animation. Is there a way to do this efficiently in JOGL, or do I have to scalp a shape out of polygons, one vertex at a time, and then paint a texture over it? Or is there a simpler method of just loading the sprite and displaying it right then and there and of course changing the image depending on user input. If there is a way to do it without creating a vertex for every corner of the sprite could you display some code, or a tutorial so I can grasp the idea of what you are doing.
2.) I have been searching around for a way of displaying textures in JOGL, but I am still confused on how to do so. Let me first show you the way I found of loading and display a texture on a shape. First I create 7 variables:
Texture image;
private String textureFileName = "images/crate.png";
private String textureFileType = ".png";
private float textureTop, textureBottom, textureLeft, textureRight;
Next in my init() method I load my image by doing the following:
GL2 gl = drawable.getGL().getGL2();
gl.glShadeModel(GL_SMOOTH);
image = TextureIO.newTexture(getClass().getClassLoader().getResource(textureFileName),false, textureFileType);
// Use linear filter for texture if image is larger than the original texture
gl.glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
// Use linear filter for texture if image is smaller than the original texture
gl.glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
TextureCoords textureCoords = image.getImageTexCoords();
textureTop = textureCoords.top();
textureBottom = textureCoords.bottom();
textureLeft = textureCoords.left();
textureRight = textureCoords.right();
Then in the display method I do the following
GL2 gl = drawable.getGL().getGL2();
gl.glClear(gl.GL_COLOR_BUFFER_BIT | gl.GL_DEPTH_BUFFER_BIT);
image.enable(gl);
image.bind(gl);
gl.glBegin(gl.GL_QUADS);
gl.glTexCoord2f(textureLeft,textureTop);
gl.glVertex2d(c,a); // vertex 1
gl.glTexCoord2f(textureLeft, textureBottom);
gl.glVertex2d(c,b); // vertex 2
gl.glTexCoord2f(textureRight, textureBottom);
gl.glVertex2d(d,b); // vertex 3
gl.glTexCoord2f(textureRight, textureTop);
gl.glVertex2d(d,a); // vertex 4
gl.glEnd();
//Variables a,b,c,d are just doubles with certain values for each point
Now I just wish to know if this is an effective way to load images and display them if I am going to be having multiple textures. Seeing this way I have devised a plan on how to do that using this method but I want to know if this is the best way of doing it. I have see people talk about bmp loaders but hearing of what they do, mapping everything single integer value the image has, seems really complex. Is there no simple way to do it? But if not could someone show me how or point me into a direction of the most correct, and efficient way to load textures and display those textures.
One last thing, when I put the line:
gl.glClear(gl.GL_COLOR_BUFFER_BIT | gl.GL_DEPTH_BUFFER_BIT);
Isnt this just basically just clearing out an integers for pixels, etc. in the buffer? But what does the | do anyways? Does it shift the bits?
Also what do these two lines of code do? Im confused by the comments. These two lines appear in my init() method for loading a texture:
// Use linear filter for texture if image is larger than the original texture
gl.glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
// Use linear filter for texture if image is smaller than the original texture
gl.glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
Thank you for taking the time to read and respond to this message, Thank you.
-Dan

Unexpected results implementing simple motion blur in Libgdx

In the two attached pictures, the desktop screenshot of libgdx functions as expected. The screenshot from my Galaxy Nexus is unfortunately not as expected. I am attempting to create a simple motion blur or trail effect.
Rendering as I expected on my desktop.
Not rendering as I expected on my Galaxy nexus.
The circle textures are drawn in a for loop during rendering and the effect is achieved with a pixmap using the RGBA of 0, 0, 0, 0.1f that is drawn before the circles.
screenClearSprite creation
Pixmap screenClearPixmap = new Pixmap(256, 256, Format.RGBA8888);
screenClearPixmap.setColor(Color.rgba8888(0, 0, 0, 0.1f));
screenClearPixmap.fillRectangle(0, 0, 256, 256);
screenClearTexture = new Texture(screenClearPixmap);
screenClearSprite = new Sprite(screenClearTexture);
screenClearSprite.setSize(screenWidth, screenHeight);
screenClearPixmap.dispose();
Render
batch.begin();
font.draw(batch, "fps:" + Gdx.graphics.getFramesPerSecond(), 0, 20);
screenClearSprite.draw(batch);
for (int i = 0; i < circleBodies.size(); i++) {
tempPos = circleBodies.get(i).getPosition();
batch.draw(circleTexture, (tempPos.x * SCALE) + screenWidthHalf
- circleSizeHalf, (tempPos.y * SCALE) + screenHeightHalf
- circleSizeHalf);
}
batch.end();
So, what did I do wrong? Perhaps there is a better way to get the 'motion blur' effect of movement?
Here is a different approach, where you clear your screen each time with solid color and no alpha.
This means that you will have to modify your code some. The good thing about this, is that the way you are doing it has some flaws: It will blur everything in motion, not just the balls. And can quickly produce ugly results/artefacts unless you are careful.
Do the same as you are doing now, but instead of drawing the balls to the batch, draw them onto a texture/bitmap/whatever. Then each frame add an alpha-blended image over the balls-image, and then draw the balls in their current position on top of that. Then add that image to your screen. Very much like you are doing now, except you draw to something else and keep it. This way you don't have to rely on the viewport you are drawing onto, and can keep everything separated.
This method is similar to drawing to an accumulation buffer.
Instead of doing it the way you are doing, you can keep track of the n latest positions of each ball. And then draw all of them each frame, with different alpha. This is very easy to implement. Can result in many drawing calls if you have many balls or a large n, but if it's not too much it shouldn't limit your fps and gives nice control.
Perhaps there is a better way to get the 'motion blur' effect of
movement?
in order to make motion blur in my game i use another approch "The particle effect" it works realy fine with me and i didn't have Android/Desktop problems or with different android devices
all you have to do is to use "Particle Effect Editor" of Libgdx and make your effect then load it in your project finally draw it at the same position you draw your object (and alos draw your object)
Tips to make the right effect file with Paticle Editor :
set (use) the same image of the object that you want to blur it motion in the particle effect
try to limit the count : the max number of particle allowed
Disable the "velocity" and "Angle"
parameter
Particle effect help to do motion effect
Hope this will help someone !

Orthographic projection that reveals more world data instead of scaling during a window resize

Trying to port a java2d demo app to a dekstop libgdx implementation.
This app plots data that is in inches. The plot is like a map in that it is an overhead view of a terrain. I use OrthographicCamera in libgdx and I am able to move left/right/up/down/zoom, all of that works great. I'm struggling with window resizes.
What I want to happen is that a window resize just allows the user to view more of the map at once. What I'm seeing is that the entire scene scales to fit the new window-size.
For example: If I have an object that is 50inches x 50inches in world coordinates AND at the current camera zoom level is 50pixels x 50 pixels on the screen, when the user then resizes the window, I want the object to stay 50pixes x 50pixels and more of the world to be revealed.
How is this accomplished in straight opengl terms?
How do I configure libgdx's camera to facilitate this?
What is right term for the kind of scene I am trying to setup (my google foo has failed me here)?
In plain OpenGL you would do something like:
glOrtho( 0, windowWidth, 0, windowHeight, 0, 1 )
on each window resize or redraw. This makes sure that one OpenGL unit corresponds to one pixel and window resize's don't scale the scene.

Categories

Resources