The title pretty much say it all, I need to get a image from a Model is this posible? I searched for this and found nothing.
Solution thanks to #retodaredevil
FrameBuffer fbo = new FrameBuffer(Pixmap.Format.RGBA4444, screenWidth, screenHeight, true);
ModelBatch batch = new ModelBatch();
fbo.begin(); // make fbo the current buffer
Gdx.gl.glViewport(0, 0,screenWidth, screenHeight);
Gdx.gl.glClear(GL_COLOR_BUFFER_BIT | GL20.GL_DEPTH_BUFFER_BIT);
batch.begin(camera);
batch.render(instance, environment);
batch.end();
try{
FileHandle fh = new FileHandle(output);
Pixmap pixmap = ScreenUtils.getFrameBufferPixmap(0,0,screenWidth,screenHeight);
PixmapIO.writePNG(fh, pixmap);
pixmap.dispose();
}catch (Exception e){
e.printStackTrace();
}
fbo.end(); // Now you can draw on the display again
batch.dispose();
fbo.dispose();
From what I understand, we'll have to use two different tutorials
https://github.com/mattdesl/lwjgl-basics/wiki/FrameBufferObjects
https://xoppa.github.io/blog/basic-3d-using-libgdx/ (You're probably already familiar with this)
FrameBuffer fbo = new FrameBuffer(Pixmap.Format.RGBA4444, width, height, hasDepth);
// I've never used a FrameBuffer before so you may have to play around with constructor parameters
ModelBatch batch = // your ModelBatch initialization here
fbo.begin(); // make fbo the current buffer
glClearColor(0f, 0f, 0f, 1f);
glClear(GL_COLOR_BUFFER_BIT);
batch.resize(fbo.getWidth(), fbo.getHeight());
batch.begin();
batch.render(modelInstance, environment);
batch.end();
fbo.end(); // Now you can draw on the display again
// If you want to, you can resize your batch and use it to draw on the display
batch.resize(Display.getWidth(), Display.getHeight());
Once you do whatever you need to do to your FrameBuffer, you can get the texture
fbo.getTexture();
EDIT: That method doesn't exist, look at OP's question for solution
EDIT 2: FrameBuffer does actually have a method called getColorBufferTexture()
For saving a texture, look at https://www.badlogicgames.com/forum/viewtopic.php?p=8358#p8358 or https://www.badlogicgames.com/forum/viewtopic.php?t=5686
I used this to get one of the links: Libgdx save SpriteBatch in a texture everything else I duckduckgoed
If something doesn't work let me know and I can try to look around more.
Related
I'm converting my game Hold & Drag from Swift (SpriteKit) to Android using LibGDX, I created my 'SpriteKit' api a little clone of the official on Xcode.
I'm looking for optimizing the render of textures especially because I got FPS drop (45-60 /60 fps)
When I don't draw textures I got 60 (the maximum).
I hope you will help me as efficiently as possible!
#Override
public void draw() {
if (texture == null)
return;
Gdx.gl.glEnable(GL20.GL_BLEND);
Gdx.gl.glBlendFunc(GL20.GL_SRC_ALPHA, GL20.GL_ONE_MINUS_SRC_ALPHA);
spriteBatch.setTransformMatrix(getTransformMatrix());
spriteBatch.begin();
Color color = spriteBatch.getColor();
color.a = getAlpha();
spriteBatch.setColor(color);
spriteBatch.draw(texture, -size.width / 2, -size.height / 2, size.width, size.height);
spriteBatch.end();
Gdx.gl.glDisable(GL20.GL_BLEND);
}
public List<SKNode> getParents() {
List<SKNode> parents = new ArrayList<>();
if (parent != null) {
parents.add(parent);
parents.addAll(parent.getParents());
}
return parents;
}
public Matrix4 getTransformMatrix() {
List<SKNode> nodes = getParents();
Collections.reverse(nodes);
nodes.add(this);
Matrix4 transformMatrix = new Matrix4();
transformMatrix.idt();
for (SKNode node : nodes) {
transformMatrix.translate(node.position.x + node.origin.x, node.position.y + node.origin.y, 0);
transformMatrix.rotate(0, 0, 1, node.zRotation);
transformMatrix.scale(node.xScale, node.yScale, 0);
transformMatrix.translate(-node.origin.x, -node.origin.y, 0);
}
return transformMatrix;
}
It is slow to do things that cause the sprite batch to "flush", which means it has to issue a number of OpenGL commands and transfer vertex data, etc. A flush occurs when you call spriteBatch.end() but also occurs if you:
Draw something with a different texture instance than the last thing drawn
Change the projection or transform matrices
Enable/disable blending
So you want to organize so you are not triggering a flush on every object you draw. What is typically done is to begin the batch, and then each sprite is drawn at its particular location with one of the spriteBatch.draw() methods that includes all the parameters you want. Like this:
batch.setProjectionMatrix(camera.combined);
batch.begin();
for (GameObject obj : myGameObjects)
obj.draw();
batch.end();
//And in your game object / sprite class
public void draw() {
if (texture == null)
return;
spriteBatch.setColor(1f, 1f, 1f, getAlpha());
spriteBatch.draw(texture, -size.width / 2, -size.height / 2, size.width, size.height);
}
Note that the above assumes you are referring to the same sprite batch instance in every object.
Now, to make it behave more like SpriteKit (I'm assuming since I haven't used it), your objects each need a transform. But you don't want to be calling setTransformMatrix or you will trigger a flush. Instead you can use the Affine2 class instead of Matrix4. It functions just as well for holding transform data for a 2D object. Then you can use spriteBatch.draw(textureRegion, width, height, affine2Transform) to draw it without triggering a flush.
To avoid triggering flushes from using different texture instances, you should use a TextureAtlas and texture regions. You can read up on that in the LibGDX documentation on their wiki.
As an aside, when using SpriteBatch, you do not need to make OpenGL calls to enable and disable blending. That is handled internally by SpriteBatch. Call spriteBatch.enableBlending() instead.
How can I use interpolation in libgdx ?
Say if I have sprite and I want to manipulate its size as it begins at 0,0
and end at its full size
I have this :
SpriteBatch batch = new SpriteBatch();
Sprite star = new Sprite(new Texture("star.png"));
public void render(float delta) {
batch.begin();
batch.draw(star, 100, 100, star.getOriginX(), star.getOriginY(),
star.getWidth(), star.getHeight(), star.getScaleX(), star.getScaleY(),
star.getRotation());
batch.end;
}
With SpriteBatch: You can use Tween engine (https://github.com/libgdx/libgdx/wiki/Universal-Tween-Engine) to do the job with the numbers.
With Scene2D: You can use actors and use addAction() to animate the transformation automatically. Actions are pretty cool and support many types of interpolations.
I have a com.badlogic.gdx.scenes.scene2d.ui.Image that is built from a Pixmap. The Pixmap is only one pixel because I'm using it to build an Image that functions as a background that can fade in and out.
Pixmap pmap = new Pixmap(1, 1, Pixmap.Format.RGBA8888);
pmap.setColor(1.0f, 1.0f, 1.0f, 1.0f);
pmap.drawPixel(0, 0);
bgImage = new Image(new Texture(pmap));
pmap.dispose();
bgImage.setSize(MyGame.VIRUAL_WIDTH, MyGame.VIRUAL_HEIGHT);
bgImage.getColor().a = 0.0f;
bgImage.addAction(Actions.sequence(Actions.fadeIn(1.0f),Actions.delay(3.0f),Actions.fadeOut(1.0f)));
stage.addActor(bgImage);
It works great but my concern is that the game might be paused while the actions are taking place. I assume the actions will continue upon resuming so I need to keep the same Image but the underlying Pixmap is not managed and therefore needs to be recreated upon resume. I'm having trouble figuring out how to reattach the Texture/Pixmap to the Image. Building the Pixmap itself is easy but getting an existing Image to use it is the problem.
My solution was as follows
Assume Pixmap pixmap = ...
TextureData texData = new PixmapTextureData(pixmap, Format.RGBA8888, false, false, true);
Texture texture = new Texture(texData);
Image image = new Image(texture);
The last flag in PixmapTextureData is "managed". It runs on mine.
You can check out the first portion of the following link to see what is managed and what is not. http://www.badlogicgames.com/wordpress/?p=1513
There is no setTexture method on an Image. Looking at the Image(Texture) constructor it wraps the texture in a drawable region:
this(new TextureRegionDrawable(new TextureRegion(texture)));
So you can do something similar and use the Image.setDrawable method to change the drawable object used. Something like this:
bgImage.setDrawable(new TextureRegionDrawable(new TextureRegion(new Texture(pmap))));
I think you can probably reuse the TextureRegion and all of its containers (so after generating a new pixmap, just wrap it in a Texture and push that into the saved TextureRegion from before the pause.
I am beginning to write a game in LibGDX, only just beginning. I have got a basic tile map loaded, a player sprite and can move the character around and the screen (camera) scrolls around - perfect.
I have two overlayed textures in the bottom right of the screen, a left and right arrow, which are used as the joypad to control the character. I position these in relation to the players.x position, which is always fixed to the centre of the screen. Cool so far .... As below:
/////////////////////////////////////////////////////////////////
private void renderJoypad(float deltaTime)
{
batch.draw(Assets.leftJoypad, blockman.position.x-14, 1, 3, 3);
batch.draw(Assets.rightJoypad, blockman.position.x-9, 1, 3, 3);
}
I am now trying to put the player's score in the top left of the screen. The score is made of a Bitmap font, as below.
font = new BitmapFont(Gdx.files.internal("fonts/minecrafter.fnt"),Gdx.files.internal("fonts/minecrafter.png"),false);
font.setScale(0.02f);
In my render() method I cam calling some other methods to update, like the positions of the
leftJoypad etc, as in renderJoypad(). I am also calling my draw font method to update the position of the score, however, when I scroll it is all jerky, and sometimes it shows less characters than there should be.
public void drawScore(float deltaTime)
{
font.draw(batch, "00000", blockman.position.x, 10);
}
I believe that I need to place the score (and any other on screen texts, HUD etc) into a stage, but I cannot understand how to get it working with my existing code.
My show method is as follows:
public void show()
{
//load assets class to get images etc
Assets Assets = new Assets();
//start logging Framerate
Gdx.app.log( GameScreen.LOG, "Creating game" );
fpsLogger = new FPSLogger();
//set the stage - bazinga
Gdx.input.setInputProcessor(stage);
//stage.setCamera(camera);
//stage.setViewport(480, 360, false);
batch = new SpriteBatch();
//load the Joypad buttons
loadJoypad();
//background image
loadBackground();
//sounds
jumpSound = Gdx.audio.newSound(Gdx.files.internal("sounds/slime_jump.mp3"));
//LOAD block man here
// load the map, set the unit scale to 1/16 (1 unit == 16 pixels)
loadMap();
//draw the score
font = new BitmapFont(Gdx.files.internal("fonts/minecrafter.fnt"),Gdx.files.internal("fonts/minecrafter.png"),false);
font.setScale(0.02f);
// create an orthographic camera, shows us 30x20 units of the world
camera = new OrthographicCamera();
camera.setToOrtho(false, 30, 20);
camera.update();
// create the Blockman we want to move around the world
blockman = new Blockman();
blockman.position.set(25, 8);
}
and my render() method is as follows:
public void render(float delta)
{
// get the delta time
float deltaTime = Gdx.graphics.getDeltaTime();
stage.act(deltaTime);
stage.draw();
// clear the screen
Gdx.gl.glClearColor(0.3f, 0.3f, 0.3f, 1);
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
renderBackground(deltaTime);
batch = renderer.getSpriteBatch();
//updateBlockman(deltaTime);
blockman.update(deltaTime);
// let the camera follow the blockMan, x-axis only
camera.position.x = blockman.position.x;
camera.update();
// set the tile map rendere view based on what the
// camera sees and render the map
renderer.setView(camera);
renderer.render();
//start the main sprite batch
batch.begin();
// render the blockMan
renderBlockman(deltaTime);
renderJoypad(deltaTime);
drawScore(deltaTime);
batch.end();
fpsLogger.log();
}
I have tried to change the way things work with relation to the Spritebatch etc and just cannot seem to get it working as I require.
Can anyone suggest how I may approach getting a stage and actors to work, or a second camera or something to help me achieve a fixed score display in the corner.
Do I need to use Scene 2D or something - aahhh! My head is exploding....
I look forward and thank you in advance.
Regards
James
I have a couple of suggestions:
Check to see if you have setUseIntegerPositions set to true
(the default) when you draw your font. If you do, and you're scaling
it, then it can cause some odd effects similar to those that you
describe. Set it to false and see if it fixes the problem.
Reset your spritebatch's matrices before drawing the text, that way you won't need to adjust it for the scrolling.
I'd even go as far as to recommend not scaling the font if you can help it, because fonts often look a little odd after being scaled.
How should I follow the directory structure and what to specify so that assetManger will use that folder for different resolution.
I have studied assetManager and ResolutionFileResolver but until now I couldn't exactly figured how to specify the folder to support different resolutions.
Update: Newer versions of Libgdx use a different strategy to resolve filenames (with directories, not files), so this answer does not apply to newer Libgdx versions after (0.9.2, I think? https://github.com/libgdx/libgdx/commit/3afcfe49c40196765033a90b4610159183dde981)
The built-in ResolutionFileResolver does not use a directory hierarchy. It uses file suffixes to match screen resolutions to assets.
Here's the code from the libGDX AssetManagerTest:
Resolution[] resolutions = { new Resolution(320, 480, ".320480"),
new Resolution(480, 800, ".480800"),
new Resolution(480, 856, ".480854") };
ResolutionFileResolver resolver = new ResolutionFileResolver(new InternalFileHandleResolver(), resolutions);
AssetManager manager = new AssetManager();
manager.setLoader(Texture.class, new TextureLoader(resolver));
...
The resolver appends one of those suffixes based on the current screen resolution. So, for example, if you look up "foo.jpg" on a 480x800 device, the file "foo.jpg.480800" will be opened.
If you want to resolve files based on directories (so "foo.jpg" would be resolved to "480x800/foo.jpg" or something like that), you can write a new resolver. Just implement FileHandleResolver. The ResolutionFileResolver.java source is probably a good place to start.
Once me too suffered from this problem but at end i got the working solution, for drawing anything using SpriteBatch or Stage in libgdx. Using orthogrphic camera we can do this.
first choose one constant resolution which is best for game. Here i have taken 1280*720(landscape).
class ScreenTest implements Screen{
final float appWidth = 1280, screenWidth = Gdx.graphics.getWidth();
final float appHeight = 720, screenHeight = Gdx.graphics.getHeight();
OrthographicCamera camera;
SpriteBatch batch;
Stage stage;
Texture img1;
Image img2;
public ScreenTest(){
camera = new OrthographicCamera();
camera.setToOrtho(false, appWidth, appHeight);
batch = new SpriteBatch();
batch.setProjectionMatrix(camera.combined);
img1 = new Texture("your_image1.png");
img2 = new Image(new Texture("your_image2.png"));
img2.setPosition(0, 0); // drawing from (0,0)
stage = new Stage(new StretchViewport(appWidth, appHeight, camera));
stage.addActor(img2);
}
#Override
public void render(float delta) {
batch.begin();
batch.draw(img, 0, 0);
batch.end();
stage.act();
stage.act(delta);
stage.draw();
// Also You can get touch input according to your Screen.
if (Gdx.input.isTouched()) {
System.out.println(" X " + Gdx.input.getX() * (appWidth / screenWidth));
System.out.println(" Y " + Gdx.input.getY() * (appHeight / screenHeight));
}
}
//
:
:
//
}
run this code in Any type of resolution it will going to adjust in that resolution without any disturbance.
If you use an OrthographicCamera you won't need to deal with different image resolutions.
Say that you have a camera with the size 400x300. Then you draw a 400x300 large image at coordinate (0,0). Then, regardless of screen resolution, the image will be scaled to fill the screen. This is really neat on Android where the screen resolution can vary a lot between different devices, and doing it like this you won't have to think about it.