Loading textures at random place - android

I'm trying to load all the game data at the same time, in my game scene's constructor. But it fails, because texture loading works only in an opengl context, like if load method called from draw frame or surfacechanged. But i think it's ugly to load textures when the drawframe first called or something similar. So is it possible somehow to separate my loading part from opengl functions?

I have exactly the same problem.
My solution is using the proxy textures. It means that when you're creating textures using some data from memory or file you're creating the dummy texture that holds the copy of that memory data or the file path (you can preload the data into memory for faster loading).
After that the next time my renderer calls bind() (which is something like glBindTexture) I check whether there is data to load and if it exists I just create the new texture and load the data.
This approach fits best to me, because in my case textures could be created from any thread and any time.
But if you want to preload all textures you can just do that in onSurfaceCreated or onSurfaceChanged
The same applies to buffers.
Another approach is using the native activity (check the NDK example). In this case you can handle context manually but it requires API level 9.

But i think it's ugly to load textures when the drawframe first called or something similar.
Actually deferred texture loading is the most elegant methods. It's one of the key ingredients for games that allow for traveling the world without interrupting loading screens. Just don't try to load the whole world at once, but load things, as soon they are about to become visible. Use Pixel Buffer Objects to do things asynchronously.

Related

Android Opengl loading new bitmap object in game cycle, is it a good idea?

I am new to opengl i have just learnt to load bitmap using VBO technique. i am
(1)Whether i should create new bitmap object in each cycle of game loop
or
(2)i should create all the bitmap object once at the starting of game and use them through-out the game?
i have been using the 2nd option for canvas technique because loading lot of bitmaps is a bulky task so i don't include in the cylce. But opengl works in different way so i need suggestion on that.
Definitely do not load stuff at each game cycle, if you need to change data from a vbo, do that only exacly when you need using glBufferSubData. Also hint opengl about the nature of the data using GL_DYNAMIC_DRAW.

Reloading assets on resume

I'm working in an Android game using libGDX framework while a learn from their wiki and Learning Libgdx Game Development book. The author of the book defines an Assets class to load game assets using an AssetManager. Every time the game is resumed the assets need to be reloaded so he use a call to Assets.intance.init(new AssetManager()) what reload the assets and create new objects to store textures references.
When I do this in my game, after resume, all I have are black boxes where I had nice textures so I suppose that the problem here is that I'm using the old references. I put here part of the code from the book:
AssetManager#init
public void init(AssetManager assetManager) {
/* Dispose previous asset manager */
if (this.assetManager != null) {
this.assetManager.dispose();
}
this.assetManager = assetManager;
assetManager.setErrorListener(this);
assetManager.load(Constants.TEXTURE_ATLAS, TextureAtlas.class);
/* Start loading assets and wait until finished */
assetManager.finishLoading();
Array<String> assetNames = assetManager.getAssetNames();
Gdx.app.debug(TAG, "Assets loaded: " + assetNames.size);
for (String assetName : assetNames) {
Gdx.app.debug(TAG, "Asset: " + assetName);
}
TextureAtlas atlas = assetManager.get(Constants.TEXTURE_ATLAS);
/* Create game resource objects. Here I get what I need from the atlas */
player = new AssetPlayer(atlas);
enemy = new AssetEnemy(atlas);
}
When I create my game objets I use Assets.instance.player and Assets.instance.enemy to store a reference to textures as the author of the book does so this could be the problem. The thing is that aftere re-read the book, I don't see how he solve this problem.
I'm pretty sure that I can solve the problem changing references in my game objects but all is becoming so messy. My real question is, how should I manage game assets in my game? I've been searching a lot for game examples but most of them don't use an AssetManager but instead static variables to textures.
Should I keep references of textures in game objects? It is really necessary to reload assets on resume? How could I reload textures in my game objects when all the objects are inside a worldController that don't know when a game is being resumed?
You're doing it correctly, as far as I can tell, at this level. You really do need to reload the textures, as your OpenGL context was lost, and all "pointers" into OpenGL-internal state are stale.
As you point out, because your AssetManager.player property points to a new object, anything that cached an old pointer is stale after a restart, and that is probably the source of your problems. (Though its hard to say for certain.)
If you look at the Libgdx SuperJump demo, they also cache all their asset pointers in static fields, but notice that the render calls effectively look up the texture every call. See WorldRenderer.renderBob(). One alternative would be to do a pass over your objects after (re)-loading assets to have them "refresh" their pointers the assets they use.
Have you tried not to call Assets.intance.init(new AssetManager()) on resume method (and also not to call Assets.intance.dispose() on pause method)?
Please read this link:
https://github.com/libgdx/libgdx/wiki/Managing-your-assets
At the end (Resuming with a Loading Screen) it says:
On Android your app can be paused and resumed. Managed OpenGL resources like Textures
need to be reloaded in that case, which can take a bit of time. If you want to
display a loading screen on resume, you can do the following after you created your
AssetManager.
Texture.setAssetManager(manager);
In your ApplicationListener.resume() method you can then switch to your loading screen and call AssetManager.update() again until everything is back to normal.
If you don't set the AssetManager as shown in the last snippet, the usual managed texture mechanism will kick in, so you don't have to worry about anything.
So, I believe that the author's approach is no longer necessary.
You only need to call Assets.intance.dispose() on dispose method in your "Game" class (I mean, the class that implements ApplicationListener).

Android OpenGl Renderer finish event

In OpenGL Renderer onDrawFrame is called several time, until the page is completely rendered. I cannot find an event that my page is completeley rendered in order to take a snapshot of the OpenGL page and animate it.
I have the solution to take snapshot on at the animation trigger (specific button), but this will imply a specific delay, until Bitmap is created, such as i would like to keep in memory a mutable copy of every page.
Do you know other way to animate GLSurfaceView with rendered content?
Snippet for triggering snapshot.
glSurfaceView.queueEvent(new Runnable() {
#Override
public void run() {
glSurfaceView.getRenderer().takeGlSnapshot();
}
});
EGLContext for passing the GL11 object.
public void takeGlSnapshot() {
EGL10 egl = (EGL10) EGLContext.getEGL();
GL11 gl = (GL11) egl.eglGetCurrentContext().getGL();
takeSnapshot(gl);
}
onDrawFrame(Gl10 gl) {
//is last call for this page event ????????????
No such event exists, as I will explain below.
OpenGL is designed as a client/server architecture, with the two running asynchronously. In a modern implementation, you can generally think of the client as the API front-end that you use to issue commands and the server as the GPU/driver back-end. API calls will do a little bit of work to validate input parameters etc, but save for a few exceptions (like glReadPixels (...)) they buffer up a command for the server to execute at a later point. You never truly know when your commands are finished, unless you explicitly call glFinish (...).
Calling glFinish (...) at the end of each frame is an awful idea, as it will create a CPU/GPU synchronization point and undo the benefits of having the CPU and GPU run asynchronously. But, if you just want to take a screenshot of the current frame every once in a while, then glFinish (...) could be an acceptable practice.
Another thing to consider, if you are using double-buffered rendering is that you may be able to access the last fully rendered frame by reading the front-buffer. This is implementation specific behavior however, as some systems are designed to discard the contents of the front-buffer after the buffer swap operation, others make reading its contents an undefined operation. In any case, if you do attempt this solution, be aware that the image returned will have a 1 frame latency (however, the process of reading it will not require you to finish your current frame), which may be unacceptable.

OpenGL Memory allocation problems for drawing

I'm very new to Android and I'm writing my first app which consists of drawing STL data (a bunch of triangles).
For a small number of triangles (~ 4000), my app works great. But as soon as I try to load large data (~ 100000 triangles), I get memory allocation problems. Here is basically what I do:
I am using a GLSurfaceView for my rendering
a) I read in my data, creating a list of triangles (3 * X/Y/Z and a normal vector for each triangle)
b) I create ByteBuffers using allocateDirect() for the vertex data, the normals and the indices.
c) I add the data into the ByteBuffers
d) I call glVertexPointer, glNormalPointer and I assign the bytebuffers
e) I call glDrawElements() using the indexBuffer
As soon as I try to allocate around 10MB by calling allocateDirect(), my application crashes. I tried to calll allocate() instead, which works, but then the glVertexPointer method crashes (even for a small number of triangles)
Am I doing something wrong?
Also, do I have to call glVertexPointer, glNormalPointer every time I redraw or is it enough to call it in the surfaceChanged method?
Thanks a lot,
Mark
You should only create the VBOs once. After that if you need to load new data into them you do it in local arrays, and then load it in to the VBOs all at once using a "put" call.
The largest type that you can use for the index VBO is "short", so you can only draw 64k vertexes at a time. If you are drawing 100k vertexes, you will have to do it in two passes.
Edit: regarding your memory limitations, find out what the heap limit is for your device. The heap limit can be 16, 24, 32, or 48 MB. You can use the "android:largeHeap="true"" option to greatly increase the limits, but I'm not sure if that option is available for pre-Honeycomb versions of Android or not.
I'm not expert with 3D rendering, but 10MB of vertex data strikes me as quite a lot, especially for a mobile application, so I'm not surprised you're encountering memory allocation issues! Even if they did successfully get allocated, you'd likely find it unusable due to poor performance.
Does the entire scene really need to be in video memory all the time? You may want to explore techniques to cull vertices that are far away from the camera and only upload/draw what is necessary.

Do I have to delete textures in GLSurfaceView?

After creating textures in Android OpenGL ES, do I have to explicitly delete these textures later using glDeleteTextures()? If so, how would I set up a callback to do this?
Thanks in advance
If you are no longer using a texture, then you should call glDeleteTextures() so that the underlying hardware resources can be freed up.
But as EboMike said, you have to be careful about using a texture that was created from a previous context instance; to expand on that answer, I like to create a texture-wrangling class which wraps the texture's ID and which calls glDeleteTextures() from its finalize() method, but then also have an app-static int named "contextId" which gets incremented every time the GL context is created (i.e. in onSurfaceCreated); the texture wrangler should track the value of contextId when it's instantiated, and if the value changes on it, that means it should reload its textures (keeping in mind that the old texture IDs were already discarded along with the old context).
No, they are automatically deleted once you move away from your app. The greater pitfall actually is to disregard the texture IDs if your app becomes active again - keep that in mind when your onSurfaceChanged is called again.

Categories

Resources