Libgdx get texture from Texture Atlas with findRegion - libgdx

I have this code
textureAtlas = TextureAtlas("atlas.atlas")
val box = textureAtlas.findRegion("box")
I want to create a texture with "box". Is it possible? box.texture return the original texture, not the regioned. Oh and I don't want to use Sprite and SpriteBatch. I need this in 3D, not 2D.
Thanks

TextureAtlas actually not separating pieces. When you get region from atlas its just saying that this is the area you gonna use (u,v,u2,v2) and this is original reference to whole texture.
This is why batch.draw(Texture) and batch.draw(TextureRegion) are not same in use.
However taking part of picture as texture is possible.
You can use pixmap to do it.
First generate pixmap from atlas texture. Then create new empty pixmap in size of "box" area you want. Then assign pixel arrays and generate texture from your new pixmap.
It may be quite expensive due to your Textureatlas size.
You can use framebuffer.
Create FBbuilder and build new frame buffer.Draw texture region to this buffer and get texture from it.
Problem here is the sizes of texture will be same as viewport/screen sizes.I guess you can create new camera to change it to sizes you want.
GLFrameBuffer.FrameBufferBuilder frameBufferBuilder = new GLFrameBuffer.FrameBufferBuilder(widthofBox, heightofBox);
frameBufferBuilder.addColorTextureAttachment(GL30.GL_RGBA8, GL30.GL_RGBA, GL30.GL_UNSIGNED_BYTE);
frameBuffer = frameBufferBuilder.build();
OrthographicCamera c = new OrthographicCamera(widthofBox, heightofBox);
c.up.set(0, 1, 0);
c.direction.set(0, 0, -1);
c.position.set(widthofBox / 2, heightofBox / 2, 0f);
c.update();
batch.setProjectionMatrix(c.combined);
frameBuffer.begin();
batch.begin();
batch.draw(boxregion...)
batch.end();
frameBuffer.end();
Texture texturefbo = frameBuffer.getColorBufferTexture();
Texturefbo will be y flipped. You can fix this with texture draw method by setting scaleY to -1 or You can scale scaleY to -1 while drawing on framebuffer or can change camera like this
up.set(0, -1, 0);
direction.set(0, 0, 1);
to flip to camera on y axis.
Last thing came to my mind is mipmapping this texture.Its also not so hard.
texturefbo.bind();
Gdx.gl.glGenerateMipmap(GL20.GL_TEXTURE_2D);
texturefbo.setFilter(Texture.TextureFilter.MipMapLinearLinear,
Texture.TextureFilter.MipMapLinearLinear);

You can do this:
Texture boxTexture = new TextureRegion(textureAtlas.findRegion("box")).getTexture();

Related

Libgdx Rendering Bitmap font to pixmap texture causes extremely slow rendering

I'm using libgdx scene2d to render 2d actors. Some of these actors originally included scene2d Label actors for rendering static text. The Labels work fine but drawing ~20 of them on the screen at once drops the frame rate by 10-15 frames, resulting in noticeably poor rendering while dragging.
I'm attempting to avoid the Labels by pre-drawing the text to textures, and rendering the textures as scene2d Image actors. I'm creating the texture using the code below:
BitmapFont font = manager.get(baseNameFont,BitmapFont.class);
GlyphLayout gl = new GlyphLayout(font,"Test Text");
int textWidth = (int)gl.width;
int textHeight = (int)gl.height;
LOGGER.info("textHeight: {}",textHeight);
//int width = Gdx.graphics.getWidth();
int width = textWidth;
//int height = 500;
int height = textHeight;
SpriteBatch spriteBatch = new SpriteBatch();
FrameBuffer m_fbo = new FrameBuffer(Pixmap.Format.RGB565, width,height, false);
m_fbo.begin();
Gdx.gl.glClearColor(1f,1f,1f,0f);
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
Matrix4 normalProjection = new Matrix4()
.setToOrtho2D(0, 0, width, height);
spriteBatch.setProjectionMatrix(normalProjection);
spriteBatch.begin();
font.draw(spriteBatch,gl,0,height);
spriteBatch.end();//finish write to buffer
Pixmap pm = ScreenUtils.getFrameBufferPixmap(0, 0, (int) width, (int) height);//write frame buffer to Pixmap
m_fbo.end();
m_fbo.dispose();
m_fbo = null;
spriteBatch.dispose();
Texture texture = new Texture(pm);
textTexture = new TextureRegion(texture);
textTexture.flip(false,true);
manager.add(texture);
I assumed, and have read, that textures are often faster. However when I replaced the Labels with the texture, it had the same, if not worse, affect on the frame rate. Oddly, I'm not experiencing this when adding textures from a file, which makes me think I'm doing something wrong in my code. Is there a different way I should be pre-rendering these pieces of text?
I have not tested this, but I think you can enable culling for the whole Stage by setting its root view to use a cullingArea matching the world width and height of the viewport. I would do this in resize after updating the Stage Viewport just in case the update affects the world width and height of the viewport.
#Override
public void resize(int width, int height) {
//...
stage.getViewport().update(width, height, true);
stage.getRoot().setCullingArea(
new Rectangle(0f, 0f, stage.getViewport().getWorldWidth(), stage.getViewport().getWorldHeight())
);
}
It will only be able to cull Actors that have their x, y, width, and height set properly. This is true I think of anything in the scene2d UI package, but for your own custom Actors you will need to do it yourself.
If a child of your root view is a Group that encompasses more than the screen and many actors, you might want to cull its children, too, such that even if the group as a whole is not culled by the root view, the group can still cull a portion of its own children. To figure out the culling rectangle for this, I think you would intersect a rectangle of the group's size with the viewport's world size rectangle offset by -x and -y of the group's position (since the culling rectangle is relative to the position of the group it's set on).

libgdx mesh screenshot original resolution

I have a mesh on which I have bound a texture in Render loop using texture.bind();
The original resolution of the texture is 1024 x 1024. My desktop screen resolution is 1366 x 768.
So I make some changes in the mesh triangles to modify the texture's look. I move some triangles here and there to get a final image. Now, I want to save that image in its original resolution, but If i do so using the image's original pixmap, it saves the original image before modification in 1024x1024. But I want to save the modified image in 1024x1024.
I also used the screenshot code:
byte[] pixels = ScreenUtils.getFrameBufferPixels(0, 0, Gdx.graphics.getBackBufferWidth(), Gdx.graphics.getBackBufferHeight(), true);
Pixmap pixmap = new Pixmap(Gdx.graphics.getBackBufferWidth(), Gdx.graphics.getBackBufferHeight(), Pixmap.Format.RGBA8888);
BufferUtils.copy(pixels, 0, pixmap.getPixels(), pixels.length);
PixmapIO.writePNG(Gdx.files.local("saved/screenshot.png"), pixmap);
pixmap.dispose();
But it saves the image in 1024x750 resolution because of the lower monitor resolution (getBackBufferHeight becomes 750 in this case).
I now want to capture/save the modified image(modified using mesh triangles). What exactly do I need to do now to get the modified 1024x1024 image? Should I use a ScrollPane to display the image in its original resolution so that when I take a screenshot, I get 1024x1024?
Do your modifications on a correctly sized frame buffer, instead of the screen's back buffer. But be wary of whether the device supports RGBA8888 for frame buffers (it's not required for OpenGL ES 2.0 so some GPUs don't support it).
int width = 1024;
int height = 1024;
FrameBuffer frameBuffer;
try {
frameBuffer = new FrameBuffer(Pixmap.Format.RGBA8888, width, height, false);
} catch (GdxRuntimeException e) {
frameBuffer = new FrameBuffer(Pixmap.Format.RGB565, width, height, false);
}
frameBuffer.begin();
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
//draw your texture and do your manipulations.
byte[] pixels = ScreenUtils.getFrameBufferPixels(0, 0, width, height, true);
Pixmap pixmap = new Pixmap(width, height, Pixmap.Format.RGBA8888);
BufferUtils.copy(pixels, 0, pixmap.getPixels(), pixels.length);
PixmapIO.writePNG(Gdx.files.local("saved/screenshot.png"), pixmap);
pixmap.dispose();
frameBuffer.end();
frameBuffer.dispose();

libgdx open gles 2.0 stencil alpha masking

I'm looking for a solution to implement alpha masking with stencil buffer in libgdx with open gles 2.0.
I have managed to implement simple alpha masking with stencil buffer and shaders, where if alpha channel of fragment is greater then some specified value it gets discarted. That works fine.
The problem is when I want to use some gradient image mask, or fethered png mask, I don't get what I wanned (I get "filled" rectangle mask with no alpha channel), instead I want smooth fade out mask.
I know that the problem is that in stencil buffer there are only 0s and 1s, but I want to write to stencil some other values, that represent actual alpha value of fragment that passed in fragment shader, and to use that value from stencil to somehow do some blending.
I hope that I've explained what I want to get, actually if it's possible.
I've recently started playing with OpenGL ES, so I still have some misunderstandings.
My questions is: How to setup and stencil buffer to store values other then 0s and 1s, and how to use that values later for alpha masking?
Tnx in advance.
This is currently my stencil setup:
Gdx.gl.glClearColor(1, 1, 1, 1);
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT | GL20.GL_STENCIL_BUFFER_BIT | GL20.GL_DEPTH_BUFFER_BIT);
// setup drawing to stencil buffer
Gdx.gl20.glEnable(GL20.GL_STENCIL_TEST);
Gdx.gl20.glStencilFunc(GL20.GL_ALWAYS, 0x1, 0xffffffff);
Gdx.gl20.glStencilOp(GL20.GL_REPLACE, GL20.GL_REPLACE, GL20.GL_REPLACE);
Gdx.gl20.glColorMask(false, false, false, false);
Gdx.gl20.glDepthMask(false);
spriteBatch.setShader(shaderStencilMask);
spriteBatch.begin();
// push to the batch
spriteBatch.draw(Assets.instance.actor1, Gdx.graphics.getWidth() / 2, Gdx.graphics.getHeight() / 2, Assets.instance.actor1.getRegionWidth(), Assets.instance.actor1.getRegionHeight());
spriteBatch.end();
// fix stencil buffer, enable color buffer
Gdx.gl20.glColorMask(true, true, true, true);
Gdx.gl20.glDepthMask(true);
Gdx.gl20.glStencilOp(GL20.GL_KEEP, GL20.GL_KEEP, GL20.GL_KEEP);
// draw where pattern has NOT been drawn
Gdx.gl20.glStencilFunc(GL20.GL_EQUAL, 0x1, 0xff);
decalBatch.add(decal);
decalBatch.flush();
Gdx.gl20.glDisable(GL20.GL_STENCIL_TEST);
decalBatch.add(decal2);
decalBatch.flush();
The only ways I can think of doing this are with a FrameBuffer.
Option 1
Draw your scene's background (the stuff that will not be masked) to a FrameBuffer. Then draw your entire scene without masks to the screen. Then draw your mask decals to the screen using the FrameBuffer's color attachment. Downside to this method is that in OpenGL ES 2.0 on Android, a FrameBuffer can have RGBA4444, not RGBA8888, so there will be visible seams along the edges of the masks where the color bit depth changes.
Option 2
Draw you mask decals as B&W opaque to your FrameBuffer. Then draw your background to the screen. When you draw anything that can be masked, draw it with multi-texturing, multiplying by the FrameBuffer's color texture. Potential downside is that absolutely anything that can be masked must be drawn multi-textured with a custom shader. But if you're just using decals, then this isn't really any more complicated than Option 1.
The following is untested...might require a bit of debugging.
In both options, I would subclass CameraGroupStrategy to be used with the DecalBatch when drawing the mask decals, and override beforeGroups to also set the second texture.
public class MaskingGroupStrategy extends CameraGroupStrategy{
private Texture fboTexture;
//call this before using the DecalBatch for drawing mask decals
public void setFBOTexture(Texture fboTexture){
this.fboTexture = fboTexture;
}
#Override
public void beforeGroups () {
super.beforeGroups();
fboTexture.bind(1);
shader.setUniformi("u_fboTexture", 1);
shader.setUniformf("u_screenDimensions", Gdx.graphics.getWidth(), Gdx.graphics.getHeight());
}
}
And in your shader, you can get the FBO texture color like this:
vec4 fboColor = texture2D(u_fboTexture, gl_FragCoord.xy/u_screenDimensions.xy);
Then for option 1:
gl_FragColor = vec4(fboColor.rgb, 1.0-texture2D(u_texture, v_texCoords).a);
or for option 2:
gl_FragColor = v_color * texture2D(u_texture, v_texCoords);
gl_FragColor.a *= fboColor.r;

LibGDX FrameBuffer

I'm trying to make a game where you build a spaceship from parts, and fly it around and such.
I would like to create the ship from a series of components (from a TextureAtlas for instance). I'd like to draw the ship from it's component textures, and then save the drawn ship as one large Texture. (So i don't have to draw 50 component textures, just one ship texture. What would be the best way to go about this?
I've been trying to do so using a FrameBuffer. I've been able to draw the components to a Texture, and draw the texture to the screen, but no matter what I try the Texture ends up with a solid background the size of the frame buffer. It's like the clear command can't clear with transparency. Here's the drawing code I have at the moment. The ship is just a Sprite which i save the FrameBuffer texture to.
public void render(){
if (ship == null){
int screenwidth = Gdx.graphics.getWidth();
int screenheight = Gdx.graphics.getHeight();
SpriteBatch fb = new SpriteBatch();
FrameBuffer fbo = new FrameBuffer(Format.RGB888, screenwidth, screenheight, false);
fbo.begin();
fb.enableBlending();
Gdx.gl.glBlendFuncSeparate(GL20.GL_SRC_ALPHA, GL20.GL_ONE_MINUS_SRC_ALPHA, GL20.GL_ONE, GL20.GL_ONE_MINUS_SRC_ALPHA);
Gdx.gl.glClearColor(1, 0, 1, 0);
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
fb.begin();
atlas.createSprite("0").draw(fb);
fb.end();
fbo.end();
ship = new Sprite(fbo.getColorBufferTexture());
ship.setPosition(0, -screenheight);
}
Gdx.gl.glClearColor(1, 0, 0, 1);
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
batch.begin();
batch.enableBlending();
batch.setBlendFunction(GL20.GL_ONE, GL20.GL_ZERO);
ship.draw(batch);
batch.end();
}
The problem here lies in this line:
FrameBuffer fbo = new FrameBuffer(Format.RGB888, screenwidth, screenheight, false);
specifically with Format.RGB888. This line is saying that your FrameBuffer should be Red (8 bits) followed by Green (8 bits) followed by Blue (8 bits). Notice however, that this format doesn't have any bits for Alpha (transparency). In order to get transparency out of your frame buffer, you probably instead want to use the Format.RGBA8888, which includes an additional 8 bits for Alpha.
Hope this helps.

LibGDX: transform Texture to TextureRegion

I am creating a TowerDefence Game in LibGDX and am now trying to replace the old Tile with a new StaticTiledMapTile.
But to create a StaticTiledMapTile I need a TextureRegion, not a Texture.
Now I'm trying to create a TextureRegion, which contains the whole Texture, but it doesn't seem to work. It always appears distorted.
I have tried the following:
TextureRegion region = new TextureRegion(new Texture("someImg.png"), 0, 0, 32, 32);
StaticTileMapTile tile = new StaticTiledMapTile(region);
getLayer().getCell(x,y).setTile(tile); //setting the new tile
In my opinion this should work (if the image, as it is, is 32px wide and 32px high).