So how can I store textures within lwjgl so that when I call a texture it does not have to go and open the file to get the texture, as this is time consuming and inefficient.
I am going to be creating an animation and need several images from a texture atlas, so how can I store the first sub pic to a specific term/variable to call later?
Related
What will be the best approach for a 2D game loading screens assets on a libgdx game?
My game has many areas, every area have a 1920*1080 jpg image, a few animations (image sequence) and audio. I can select all areas from a map by clicking on the area,
My idea is simple, every time I click the map I load the background 1920*1080 texture load the animations as TextureRegion, and the audio as music,
when I select the map and click on other area, it will dispose the everything from the previous and load the new assets.
I was thinking on loading all areas at once using assetmanager, but even if all my assets are 50 megabytes, the memory on old android devices just crash,
my goal is to make fast transitions as possible when I change areas.
Please suggest.
Try to:
Combine all reusable sprites into 1 texture atlas.
Resize your sprites to a smaller resolution and avoid creating large texture atlas(I recommend to limit your texture atlas's size to 2048x2048 if you want to support older devices).
If you want to load/unload texture atlas every time the user changes map, it's best to use loading screen.
Music assets are streamed by Libgdx and not loaded in the memory. But you can lower the music's bitrate and sample rate to reduce its size.
I've gone through the nice tutorial that creates a simple libgdx game catching raindrops in a bucket. I want to learn more about using images, so I tried replacing the raindrop with a baby.
When I try loading baby.png, I get the following error:
com.badlogic.gdx.utils.GdxRuntimeException: Texture width and height must be
powers of two: 60x83
How can I load an image of whatever size I want?
before loading the image write..
Texture.setEnforcePotImages(false);
you may do this in create function of application listner this is the easiest way if you don't want to create a texture atlas
A little reading led me to a description of TextureAtlas and TexturePacker, which combine a bunch of small images into one large one. That makes them faster to load and draw. As Vikalp says, you can also just disable the rule about image sizes if you don't care about the performance difference.
Texture.setEnforcePotImages(false);
You can learn more about game atlases in Udacity's HTML5 game class.
To create your own atlas, you can start by using the TexturePacker GUI, but I recommend eventually creating a command-line project to automatically pack your raw images.
I posted an example project that takes the example code from the bucket and raindrop tutorial, and switches to using a TextureAtlas. Now, I load the atlas and then load the images from the atlas.
atlas = new TextureAtlas(Gdx.files.internal("atlas/plank.pack"));
dropImage = atlas.findRegion("images/baby");
bucketImage = atlas.findRegion("images/bucket");
One bug I found is that the images wouldn't load in the HTML project. I found out that you can work around the bug by putting all your images in a subfolder.
I created a new project to hold the TexturePacker and any unit tests that I want to add later. The texture packer looks like this:
package com.github.donkirkby.plank;
import com.badlogic.gdx.tools.imagepacker.TexturePacker2;
public class PlankPacker {
public static void main (String[] args) throws Exception {
TexturePacker2.process(
"raw-assets", // source folder
"../plank-game-android/assets/atlas", // destination
"plank.pack"); // data file
}
}
You could also put the picture (top-left corner) into an 128x128 textures aswell:
Afaik is the using of non-power-of-two textures slower and takes more VRAM. Due the architecture of an GPU and "slow" handling of texture bindings in OpenGL, it's always recommended to put your images which are used at the same time into one big pow-two texture and grab them as regions of this texture to speed up your app.
The using and grabbing of your texture would look like:
Texture texture = Gdx.files.internal("data/yourtexture.png");
TextureRegion region = new TextureRegion(texture, 0, 0, 60, 83);
For drawing something like this:
batch.draw(region, positionX, positionY);
My program packs a series of images and outputs them into an aste.png, and an aste.atlas. My code for packing is as follows:
public void pack(){
System.out.println("Packing should not be ordinarily called! If you did not have explicit intentions of Packing, please check ImageAtlas constructor.");
Settings settings = new Settings();
settings.maxWidth = 512;
settings.maxHeight = 512;
TexturePacker2.process(settings, "E:/Files/Eclipse Projects/StarFighters/StarFighters-android/assets/sprites/" + name,
"E:/Files/Eclipse Projects/StarFighters/StarFighters-android/assets/sprites/", name.substring(0,4));
}
I will not need to pack EVERY time I run the program which is why I can get away with absolute file paths(I'll only pack when I'm running desktop and have added new images), however, I only used absolute file paths because I cannot figure out how to do it otherwise. I am using the android assets folder. (The desktop is linked to the android assets folder) As I am running it from the desktop version, it's trying to goto the desktop path, when I need it to use the assets path, which Gdx.files.internal handles for me. (This problem is not essential to the function of my program)
Once I have packed the images I do as follows:
atlas = new TextureAtlas(Gdx.files.internal("sprites/aste.atlas"));
public Texture getTex(String imgname){
return atlas.findRegion(imgname).getTexture();
}
I pass in "sma_a2" as the imgname when I try and getTex();
my assets/sprites/asteroids directory has the following images:
big_a1.png
big_a2.png
med_a1.png
med_a2.png
sma_a1.png
sma_a2.png
Which were all successfully packed into the aste.png and aste.atlas
My problem is, no matter what fname I pass in the image I receive is the entire aste.png
I also was curious as to why I would use a pack instead of just the images, as I start with images, and then pack them, only to get images again..
Don't call getTexture() on the TextureRegion returned from findRegion.
The whole point of an atlas is that all of the textures you look up in it are in the "same" texture, but at different regions within that texture. This way you can "bind" one large texture in OpenGL (which is somewhat expensive) and then render lots of different pieces out of the texture.
Most of the other APIs in Libgdx that take a Texture should also work with a TextureRegion.
**My solution:**
Using "getTexture" returns the entire image, and texture regions store basically a rectangle which represents the regoin of the packaged image that is the individual image. So, basically drawing TextureRegions isn't much different then drawing Textures, so I just drew the TextureRegion. In my case that involved adding to a superclass, so that it supported Textures, and TextureRegions in subclasses. Subclasses specified whether to use Textures or TextureRegions using a boolean, and different SpriteBatch.draw() methods were called for each.
As for why to use them P.T. posted above as follows:
The whole point of an atlas is that all of the textures you look up in
it are in the "same" texture, but at different regions within that
texture. This way you can "bind" one large texture in OpenGL (which is
somewhat expensive) and then render lots of different pieces out of
the texture.
Most of the other APIs in Libgdx that take a Texture should also work
with a TextureRegion.
So sounds to me like it is more effcient/faster.
I am using libgdx and I am loading all my textures as shown below,
Texture objTexture=new Texture(Gdx.files.internal("imagename"));
This code was inside my ApplicationListener. But, I want to load all my images at the start of my game. I don't want to load them inside of ApplicationListener. I have tried accessing texture object outside the scope of OpenGL and failed. Can anyone suggest me on this?
I think that the soonest you can load those textures (it involves uploading them into the VRAM, so I guess that the Graphics module has to be initialized and all the GL stuff done) is in the create function of the ApplicationListener.
Also, you may consider using the new AssetManager to manage your resources. Or write a simpler asset manager.
I was wondering if anyone could advise on a good pattern for loading textures in an Android Java & OpenGL ES app.
My first concern is determining how many texture names to allocate and how I can efficiently go about doing this prior to rendering my vertices.
My second concern is in loading the textures, I have to infer the texture to be loaded based on my game data. This means I'll be playing around with strings, which I understand is something I really shouldn't be doing in my GL thread.
Overall I understand what's happening when loading textures, I just want to get the best lifecycle out of it. Are there any other things I should be considering?
1) You should allocate as many texture names as you need. One for each texture you are using.
Loading a texture is a very heavy operation that stalls the rendering pipeline. So, you should never load textures inside your game loop. You should have a loading state before the application state in which you render the textures. The loading state is responsible for loading all the textures needed in the rendering. So when you need to render your geometry, you will have all the textures loaded and you don't have to worry about that anymore.
Note that after you don't need the textures anymore, you have to delete them using glDeleteTextures.
2) If you mean by infer that you need different textures for different levels or something similar, then you should process the level data in the loading state and decide which textures need to be loaded.
On the other hand, if you need to paint text (like current score), then things get more complicated in OpenGL. You will have the following options: prerender the needed text to textures (easy), implement your own bitmap font engine (harder) or use Bitmap and Canvas pair to generate textures on the fly (slow).
If you have limited set of messages to be shown during the game, then I would most probably prerender them to textures as the implementation is pretty trivial.
For the current score it is enough to have a texture which has a glyph for numbers from 0 to 9 and to use that to render arbitrary values. The implementation will be quite straightforward.
If you need longer localized texts then you need to start thinking about the generating textures on the fly. Basically you would create an bitmap into which you render text using a Canvas. Then you would upload it as a texture and render it as any other texture. After you don't need it any more, then you would delete it. This option is slow and should be avoided inside the application loop.
3) Concerning textures and to get the best out of the GPU you should keep at least the following things in your mind (these things will get a bit more advanced, and you should bother with them only after you get the application up and running and if you need to optimize the frame rate):
Minimize texture changes as it is a slow operation. Optimally you should render all the objects using the same texture in a batch. Then change the texture and render the objects
needing that and so on.
Use texture atlases to minimize the number of textures (and texture changes)
If you have lots of textures, you could need to use other bit depths than 8888 to make all your textures to fit in to the memory. Using lower bit depths may also improve performance.
This should be a comment to Lauri's answer, but i can't comment with 1 rep, and there's a thing that should be pointed out:
You should re-load textures every time your EGL context is lost (i.e. when your applications is put to background and back again). So, the correct location to (re)load them is in the method
public void onSurfaceChanged(GL10 gl, int width, int height)
of the renderer. Obviously, if you have different textures sets to be loaded based (i.e.) on the game level you're playing then when you change level you should delete the textures you're not going to use and load the new textures. Also, you have to keep track of what you have to re-load when the EGL context is lost.