Reputation: 4636
I've got dynamic textures for a word game that I create and keep on a FrameBuffer. I then use TextureRegions backed by that FrameBuffer to draw to the screen. This code works fine on Android, but I'm having problems on iOS.
You can see below a screenshot with the FrameBuffer contents drawn in the bottom left - all is well.
However, if I return to the iOS home screen, I dispose of the FrameBuffer and then recreate and redraw everything to the FrameBuffer as required. The contents of the FrameBuffer then appear to be partial flipped mirror image of the screen.
I tried disposing and recreating the FrameBuffer on every frame to see what happens. Again, this works perfectly unless I return to the iOS home screen, after which the contents of the FrameBuffer are incorrect.
I then tried reducing the size of the FrameBuffer and drawing across mutliple FrameBuffers. If I do this it again works fine unless I return to the iOS home screen. However, in this instance only the first FrameBuffer created becomes corrupted, all subsequent buffers are fine.
I then tried always creating a 1x1px FrameBuffer first that I never draw anything to and this fixes my problem.... but why!? It seems the first FrameBuffer I create after returning from the iOS home screen is not working as expected, but every FrameBuffer after that is fine. It looks like it's always trying to draw the screen over the first FrameBuffer I create.
FrameBuffer creation and drawing code below:
private static FrameBuffer getFrameBuffer(boolean newRequired) {
if (newRequired || frameBuffers.size == 0) {
FrameBuffer frameBuffer;
try {
frameBuffer = new FrameBuffer(Pixmap.Format.RGBA8888, getFrameBufferSize(), getFrameBufferSize(), false);
} catch (Exception e) {
frameBuffer = new FrameBuffer(Format.RGBA4444, getFrameBufferSize(), getFrameBufferSize(), false);
}
frameBuffer.begin();
Gdx.gl20.glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
Gdx.gl20.glClear(GL20.GL_COLOR_BUFFER_BIT);
frameBuffer.end();
frameBuffers.add(frameBuffer);
// Set up the camera correctly for the frame buffer
OrthographicCamera camera = new OrthographicCamera(frameBuffer.getWidth(), frameBuffer.getHeight());
camera.position.set(frameBuffer.getWidth() * 0.5f, frameBuffer.getHeight() * 0.5f, 0);
camera.update();
spriteBatch.setProjectionMatrix(camera.combined);
}
return frameBuffers.get(frameBuffers.size - 1);
}
private static TextureRegion getTextureUsingGpu(String letter, Bubble.BubbleType bubbleType) {
if (!enabled)
return null;
TextureRegion tx = getBlockImage(letter, bubbleType);
int width = (int) (tx.getRegionWidth() * LayoutManager.getShortEdge() / 1080 * LayoutManager.getScaling());
int height = (int) (tx.getRegionHeight() * LayoutManager.getShortEdge() / 1080 * LayoutManager.getScaling());
if (nextTextureX + width + PADDING > getFrameBufferSize()) {
nextTextureX = PADDING;
nextTextureY = nextRowY + PADDING;
if (nextTextureY + height + PADDING > getFrameBufferSize()) {
getFrameBuffer(true);
nextRowY = PADDING;
nextTextureY = PADDING;
}
}
FrameBuffer fb = getFrameBuffer(false);
fb.begin();
spriteBatch.begin();
tx.flip(false, !tx.isFlipY());
spriteBatch.disableBlending();
spriteBatch.draw(tx, nextTextureX, nextTextureY, width, height);
spriteBatch.enableBlending();
// Drawing Code Removed
spriteBatch.end();
fb.end();
TextureRegion textureRegion = new TextureRegion(fb.getColorBufferTexture(), nextTextureX, nextTextureY, width, height);
textureRegion.getTexture().setFilter(TextureFilter.Linear, TextureFilter.Linear);
cacheTexture(letter, textureRegion);
nextTextureX += width;
nextRowY = Math.max(nextRowY, nextTextureY + height);
return textureRegion;
}
Upvotes: 0
Views: 211
Reputation: 93609
If you are calling getFrameBuffer
or getTextureUsingGpu
from your resize
or resume
method, that is the problem. On iOS, resize
and resume
are not necessarily called before OpenGL is ready to resume, so it is not safe to do anything directly related to OpenGL there, like creating ShaderPrograms, loading Textures, or creating FrameBuffers. I fixed this in my game by using resume
to set a member boolean, and use that to defer the creation of the new frame buffer to the render
method.
Upvotes: 2