is there a way to combine a number of textures into one texture with libgdx API?
For example, consider having these 3 textures:
Texture texture1 = new Texture("texture1.png");
Texture texture2 = new Texture("texture2.png");
Texture texture3 = new Texture("texture3.png");
The goal is to combine them into one usable texture, is there a way to do it?
I wanted to get the same result, but I did not find the previous instructions given to be of any help. Neither I was able to find any other clear solution for this issue, so here's what I managed to get working after I read a bit of api-docs and did some testing of my own.
Texture splashTexture = new Texture("texture1.png"); // Remember to dispose
splashTexture.getTextureData().prepare(); // The api-doc says this is needed
Pixmap splashpixmap = splashTexture.getTextureData().consumePixmap(); // Strange name, but gives the pixmap of the texture. Remember to dispose this also
Pixmap pixmap = new Pixmap(splashTexture.getWidth(), splashTexture.getHeight(), Format.RGBA8888); // Remember to dispose
// We want the center point coordinates of the image region as the circle origo is at the center and drawn by the radius
int x = (int) (splashTexture.getWidth() / 2f);
int y = (int) (splashTexture.getHeight() / 2f);
int radius = (int) (splashTexture.getWidth() / 2f - 5); // -5 just to leave a small margin in my picture
pixmap.setColor(Color.ORANGE);
pixmap.fillCircle(x, y, radius);
// Draws the texture on the background shape (orange circle)
pixmap.drawPixmap(splashpixmap, 0, 0);
// TADA! New combined texture
this.splashImage = new Texture(pixmap); // Not sure if needed, but may be needed to get disposed as well when it's no longer needed
// These are not needed anymore
pixmap.dispose();
splashpixmap.dispose();
splashTexture.dispose();
Then use the splashImage (which is a class variable of type Texture in my case) to render the combined image where you want it. The resulting image has the given background and the foreground is a png image which has transparent parts to be filled by the background color.
#Ville Myrskyneva's answer works, but it doesn't entirely show how to combine 2 or more textures. I made a Utility method that takes 2 textures as input and returns a combined texture. Note that the second texture will always be drawn on top of the first one.
public static Texture combineTextures(Texture texture1, Texture texture2) {
texture1.getTextureData().prepare();
Pixmap pixmap1 = texture1.getTextureData().consumePixmap();
texture2.getTextureData().prepare();
Pixmap pixmap2 = texture2.getTextureData().consumePixmap();
pixmap1.drawPixmap(pixmap2, 0, 0);
Texture textureResult = new Texture(pixmap1);
pixmap1.dispose();
pixmap2.dispose();
return textureResult;
}
You should use the TexturePacker for creating one big Texture from lots of small one. https://github.com/libgdx/libgdx/wiki/Texture-packer .
And here is GUI version (jar) whcih will help you to pack all your textures in one before putting them to your project: https://code.google.com/p/libgdx-texturepacker-gui/.
You should also remember that maximum size of one texture for most Android and IOS devices is: 2048x2048.
In case you want to use combined texture as atlas for performance benefits, you better use #Alon Zilberman answer.
But I think that your question is about another problem. If you want to get some custom texture from these three textures (e.g. merge them by drawing one at one), then your best solution is to draw to FrameBuffer. Here you can find nice example of how to do it https://stackoverflow.com/a/7632680/3802890
Related
I am trying to make a space look to my game and wanted to add stars to the background. I decided to make a float[] points and make it randomized. I then use the canvas.drawPoints(points, white);. This works very well on my emulator. On a phone, you can barely see the points. I am wondering if I can have points bigger than a pixel (I know that makes no sense) or use a method like drawRects(points, size, paint);. Using a for loop is not efficient and makes the game laggy. Is there another way or do I have to live with the lag.
Thanks!
It is related to different densities of your emulator and phone.
1 px on different screens have different physical size. You should use dp (dip or density independent pixels) and then convert it to the pixels.
So your code should look like:
ind dpRadius = 1;
Resources r = getResources();
float pxRadius = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, dpRadius, r.getDisplayMetrics());
Paint paint = new Paint();
paint.setColor(Color.BLUE);
paint.setStrokeWidth(pxRadius);
paint.setStyle(Paint.Style.STROKE);
// your drawPoints code ...
I've tried asking this question on LibGDX forums with no luck.
Basically, I've created my own packer that takes multiple spritesheets like these and packs them into something like this. As a result, I can load these packed files as arrays of TextureRegions with their X and Y offset, so that they can be drawn as if they actually had all these unnecessary transparent pixels.
Anyway, here's what I do:
Load chosen images as pixmaps;
Iterate over their "tiles" (for example, 128x128px parts of the image);
Find offsets for each tile (offsets being amount of rows/columns with only transparent pixels);
Draw non-transparent part of the tile into a new, small pixmap (continuing the example, 128-offsetLeft-offsetRight, 128-offsetTop-offsetBottom, format is the same as the loaded image);
Save each pixmap with some drawing data (offsets) in a container.
Repeat for all tiles and images.
Find the most efficient way to pack the tiles from containers into a new, bigger pixmap (again, the same format).
Save custom description file.
Save pixmap as PNG.
Pixmap-related code snippets:
Image loading:
final Pixmap image = new Pixmap(imageData.getFileHandle());
Drawing image into smaller pieces:
final Pixmap tile =
new Pixmap(imageData.getTileWidth() - offsetLeft - offsetRight, imageData.getTileHeight()
- offsetTop - offsetBottom, image.getFormat());
tile.drawPixmap(image, -columnIndex * imageData.getTileWidth() - offsetLeft,
-rowIndex * imageData.getTileHeight() - offsetTop);
Creating new Pixmap for the packed image:
Pixmap packedImage =
new Pixmap(packedImageWidth, packedImageHeight, image.getFormat());
Drawing pieces into pixmap:
packedImage.drawPixmap(frame.getPixmap(), frame.getOriginX(), frame.getOriginY());
Saving packed image:
final PixmapIO.PNG png = new PixmapIO.PNG();
png.setCompression(Deflater.NO_COMPRESSION);
png.setFlipY(false);
try {
png.write(chosenDirectory.child(packedFileName + FILE_FORMAT), packedImage);
} catch (final IOException exception) {
throw new RuntimeException(exception);
}
As a result, colors are somewhat distorted:
(Left: after packing, right: before packing, loaded and rendered as texture.)
Could any step of the packing I do distort the image or is it the saving part? Do I have to look for another solution (pure Java image processing?) or is there a way to preserve colors using LibGDX API?
Since you don't want these sprites to be blended onto the destination Pixmap, but rather replace the pixels there, I think you want to set Pixmap.setBlending(Blending.None); before you start calling drawPixmap on anything.
Sidenote: as Alexander Mironov said, LibGDX's texture packer handles whitespace stripping, and the TextureAtlas class provides you with a Sprite subclass called AtlasSprite that invisibly handles positioning the image as if the whitespace were still part of it. The various createSprite methods actually return an AtlasSprite if whitespace was stripped from the original source.
I am currently experiencing issues when drawing and scaling sprites.
I am loading my assets from a texture-atlas, which I packed no problem with the LibGDX texture packer gui tool. My texture atlas image currently looks like this.
These images are supposed to be buttons, but as you can see, the image is very small, so when the sprites are loaded, they load a sprite of say, 34x16 pixels. When I render these buttons, on a canvas of 1920x1080, they are much too small. I use sprite.scale(int scale) to scale the sprites, but when I scale them, they appear blurry. What I would like to happen, is when they are scaled, each pixel is scaled proportionally, keeping the pixelated effect on the button, rather than a blurry resized image from a really small texture. I currently render the sprites using sprite.render(SpriteBatch batch). Is this the proper way of rendering a sprite, after they are loaded using atlas.createSprite(String name)? I am new to using sprites, and loading textures from a texture-atlas, so i am wondering if this is the correct way of doing things.
Also, when I initialize my game, I load numerous different Sprite objects from a TextureAtlas. Each sprite holds a texture that will represent a game object, however it is my understanding that you render a sprite using sprite.render(SpriteBatch batch), so therefore I could only use a sprite, loaded from the TextureAtlas for one game object, because I would also have to set the scale, and position of the sprite, as it represents the game object. I am used to loading a Texture, then rendering this texture using batch.render(), at a given position, but I don't see how this is possible if I am using a sprite. Even if I use batch.render(Sprite, x, y), I am unable to scale the sprite properly, because as I mentioned before, I would like to scale the sprite while maintaining a pixelated effect, and even so, using the Sprite.scale() method, this would scale the Sprite object as a whole, making it impossible to use the Sprite's texture multiple times for numerous game objects.
Any suggestions would be greatly appreciated.
The code I am currently using to render/load the sprites is as follows:
Loading from TextureAtlas:
public static TextureAtlas atlas = new TextureAtlas(Gdx.files.internal("data/texture/pack/output/pack.pack"));
public static Sprite sprite = atlas.createSprite("buttonUp");
sprite.setScale(10);
Rendering Sprite: GdxGame.WIDTH/HEIGHT are 1920x1080. Though the Desktop window is scaled down from that size. Thus, everything is rendered as if the screen were 1920x1080.
batch = new SpriteBatch();
camera = new OrthographicCamera(GdxGame.WIDTH, GdxGame.HEIGHT);
camera.position.set(GdxGame.WIDTH/2, GdxGame.HEIGHT/2, 0);
camera.setToOrtho(false, GdxGame.WIDTH, GdxGame.HEIGHT);
public void render(float delta){
Gdx.gl.glClear(GL10.GL_COLOR_BUFFER_BIT);
batch.setProjectionMatrix(camera.combined);
batch.begin();
camera.update();
sprite.draw(batch);
batch.end();
}
After further investigation, I have discovered that I can use Sprite.set(Sprite sprite) to make Sprite x a copy of Sprite y, and therefore render each sprite multiple times. However, this does not solve the issue of scaling the sprite. I must emphasize further that when rendering a scaled sprite, the scaling is not done by pixel, meaning that it is blurry. But, when rendering a TextureRegion, like: batch.draw(TextureRegion, x, y, width, height) if the width and height are greater than that of the original texture, it will scale each pixel, rather than blur the whole thing to try and make it look better. The following is an image of the blurriness I am talking about:
Notice how this sprite is scaled to be blurry, even though the original image is small, and pixelated.
What TextureFilter settings are you using in your code or in the texturepacker? Try the "Nearest" filter. If you have set it to "Linear" or alike, it will always take 4 texture pixels (texels) and interpolate them to get the color of the pixel to be drawn.
That might help against the blur, but I am not sure if it will produce exactly that 8-bit look you are aiming for...
I'm working on a phone word game. Yesterday I decided to switch to OpenGL using libgdx to try and improve graphics performance and battery usage + to target more platforms.
The way letter tile drawing was working on a 2D canvas was each letter tile would create a bitmap for itself. I would:
Create a new mutable bitmap from the background bitmap.
Draw on the letter on the new bitmap.
Apply other tile specific effects.
Draw the new bitmap for each frame
What's the best way for me to achieve what I want using libgdx?
Should I adopt a similar approach? If so, how? I tried using pixmaps but couldn't work out how to draw the font.
Should I create a spritesheet with all the required tiles from A-Z and just use that? A bit tedious when I tweak the design of the tile background.
Should I do something totally different?
Answer
Obviously the final code shouldn't load from the files every time, as this is a massive performance hit, but here's working sample code for anyone else who is trying to achieve the same result.
// load the background into a pixmap
Pixmap tile = new Pixmap(Gdx.files.getFileHandle(
"someFile.png", FileType.Internal));
// load the font
FileHandle handle = Gdx.files.getFileHandle("someFont.fnt",
FileType.Internal);
BitmapFont font = new BitmapFont(handle);
// get the glypth info
BitmapFontData data = font.getData();
Pixmap fontPixmap = new Pixmap(Gdx.files.internal(data.imagePaths[0]));
Glyph glyph = data.getGlyph(getLetterToDraw().charAt(0));
// draw the character onto our base pixmap
tile.drawPixmap(fontPixmap, (TILE_WIDTH - glyph.width) / 2, (TILE_HEIGHT - glyph.height) / 2,
glyph.srcX, glyph.srcY, glyph.width, glyph.height);
// save this as a new texture
texture = new Texture(tile);
Quote: You can create a BitmapFontData instance and use BitmapFontData.getImagePath() to load a Pixmap containing the glyphs. You can then use BitmapFontData.getGlyph to get the location of a specific glyph in the Pixmap, which you can use with Pixmap.drawPixmap() to do what you want to do. Source: libgdx Issue 691: Draw BitmapFont to Pixmap/Texture
You get the path to the BitmapFontData and create a new Pixmap with the Filehandle to the path with this:
Pixmap(FileHandle file)
Creates a new Pixmap instance from the given file.
Source: PixmapAPI
Use Gdx.files.internal(pathfromBitmapFontData)as filehandle and you got the pixmap with all Glyps inside.
Pixmap p = new Pixmap(Gdx.files.internal(myBitmapFontData.getImagePath()))
try out if its an internal! Meight be not an internal file i dont know it
Pixmap p = new Pixmap(myFont.getData().getFontFile());
this should also work
I am using the animation class to make a simple animation, with only 2 frames.
With animation, i can get the index, or texture region at the current time.
if (!animation.isAnimationFinished(time))
time += Gdx.graphics.getDeltaTime();
else
time = 0;
But the problem is, that I can't load any texture, its width and height must be a power of 2, so i got a big 1024x1024 texture, that has the 2 images.
With sprite.setTexture() i can only put a Texture, but animation.getframe returns a texture region.
Is there a way to change the sprite texture with an animation?
Also
sprite.setTexture(animation.getKeyFrame(time).getTexture());
Does not work.
This works
sprite = new Sprite(animation.getKeyFrame(time));
But I don't think is the best idea... I think is slow can can make bugs.
You usually use TextureRegion for sprites. The method that you are looking for is TextureRegion#setRegion (Sprite extends TextureRegion).
Like this:
sprite.setRegion(animation.getKeyFrame(time));