Generating textures at runtime with text using libgdx - java

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

Related

Alternatives to Canvas.snapshot() on JavaFX

I'm developing a little graphic engine using Canvas in JavaFX. In some point I had to render an off screen image, and then print it on my primary canvas using its GraphicContext.
I'm using this code right now:
private Canvas offScreenCanvas;
private GraphicsContext offScreenGraphic;
private SnapshotParameters parameters;
private WritableImage offScreenImage;
[...]
offScreenCanvas = new Canvas(WIDTH, HEIGHT);
offScreenGraphic = offScreenCanvas.getGraphicsContext2D();
parameters = new SnapshotParameters();
parameters.setFill(Color.TRANSPARENT);
[...]
offScreenImage = offScreenCanvas.snapshot(parameters, offScreenImage);
graphic.setGlobalBlendMode(BlendMode.HARD_LIGHT);
graphic.drawImage(offScreenImage, 0, 0);
graphic.setGlobalBlendMode(BlendMode.SRC_OVER);
My problem is the method snaphot() takes too much time, ~14ms, in each execution. I need to update the canvas at least at 60fps, so this consumes practically all the time I have to draw.
Is there another way to get an Image or WritableImage from a canvas? Maybe another different process?
This is another method to obtain a visual equivalent result, without reduce performance.
I have used java.awt clases, instead of JavaFX clases. The creation of a java.awt.image.BufferedImage offers the possibility to get a java.awt.Graphics2D where you can draw using other methods. The main problem here is that draw big images consumes a lot of time using this libraries, but you can create a scaled image. In my case, I have created a quarter-size BufferedImage, and I have drawn all the objects using that scale factor.
At the end of the draw process, just convert the BufferedImage, to a javafx.scene.image.Image, using:
SwingFXUtils.WritableImage toFXImage(BufferedImage bimg, WritableImage wimg);
Then print it on the main canvas using:
graphic.drawImage(Image image, 0, 0, WIDTH, HEIGHT);
To fill all the canvas with the image.
Finally, the scale factor is configurable, so if you need a detailed image, just use a higher value. For me, a 25-percent-size image is enough because I am drawing gradients. Now, it takes 1-3ms to draw the image, this is much better than before.
Hope it helps someone.

Draw a single sprite to Pixmap - LibGDX

I am currently working on a game in which i need pixel perfect collision with objects. The only obstacle i had gotten to however, is with actually getting a mask of the object. I thought about rendering a sprite of an object (which is properly scaled and transformed) to FrameBuffer, which then i'd convert to a pixmap, but i had no luck doing it (tried many methods, including this)
So, my question is: Is there a way of rendering a single sprite to a pixmap in LibGDX?
Sounds like putting the horse behind the cart. A Sprite is a region of a Texture, which in turn is an image loaded from file aka Pixmap. If you just want to load the image from file then you can do: new Pixmap(Gdx.files.internal("yourfile.png"));. You can also scale and transform your coordinates without rendering to a FBO first.
That said; getting the Pixmap of a FrameBuffer is as "simple" as taking a screenshot while the FBO is bound, because it is exactly that.
fbo.begin();
Gdx.gl.glClear(...);
... //render to the FBO
Pixmap pixmap = ScreenUtils.getFrameBufferPixmap(0, 0, fbo.getWidth(), fbo.getHeight());
fbo.end();
Note that this will look like it is up-side-down.
But you are probably only interested in the pixel data, so you might as well skip the Pixmap step in that case and use the ScreenUtils.getFrameBufferPixels method.
However, that said; using the pixel data for collision detection is most likely not the best solution for whatever it is you are trying to achieve. Instead I'd advise to look into other options, for example have a look at this tool which can be used to convert your images into a collision shape.

Color distortion in PNGs created with LibGDX

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.

libgdx - combine a number of textures into one

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

Scrolling BufferedImage Java

I'm making a simple side scroller game in Java but am having trouble making the camera move with the person. My plan was to create a buffered image that could adjust the region of the image that is displaying and simply have it follow my character. However, I couldn't find any functions in the API to change the region of the buffered image that's displayed, so how could I do this? Thanks for any help provided.
//The level is created in an 800x400 pixel size, is there any way I can change
//the region myImage displays?
myImage = new BufferedImage(400, 400, BufferedImage.TYPE_INT_RGB);
Well while you will be drawing your image you have a lot of options for example this function can draw any rectangle from your original image on any rectangle of the surface you get Graphics object from.

Categories