libgdx write text on texture - android

I know I'm a bit ahead of libgdx because it's actually more a 2D-library but I'm working on a 3D app powered by libgdx and need to write text on a model.
I already come so far that I'm able to change texture of my model dynamically. Now I need to write text to a texture to apply this texture to my model... Is this already possible with libgdx? If yes, how?
Till now I only found tutorials how to write text on screen wit BitmapFont but only via SpriteBatch and I don't think there would be a possibility to write the output of spritebatch on a texture...
Thanks in advance!

You can send the output of a SpriteBatch (or any OpenGL drawing command) to a texture instead of sending it to the screen. In Libgdx you use a FrameBuffer object to accomplish this. This tutorial covers the basics and a bit more: https://github.com/mattdesl/lwjgl-basics/wiki/FrameBufferObjects

With Normal bitmap fonts you get a pixmap of ALL the Glpths, and can do bitmap copies.
pixmap.drawPixmap(fontPixmap, x_place, (TILE_HEIGHT - aGlyph.height) / 2,
aGlyph.srcX, aGlyph.srcY, aGlyph.width, aGlyph.height);
The only way (I have found) of drawing raster fonts (`.ttf`) is as follows:
Example framework:
==================
package com.badlogic.gdx.tests.bullet;
/**
Question : libgdx write text on texture
interpreted as : In libgdx, how to create dynamic texture?
Answer : Use a private render function to draw in a private frame buffer and convert the frame buffer to Pixmap, create Texture.
Author : Jon Goodwin
**/
import com.badlogic.gdx.graphics.Texture;
import com.badlogic.gdx.graphics.Pixmap;
...//(ctrl-shift-o) to auto-load imports in Eclipse
public class BaseBulletTest extends BulletTest
{
//class variables
=================
public Texture texture = null;//create this
public Array<Disposable> disposables = new Array<Disposable>();
public Pixmap pm = null;
//---------------------------
#Override
public void create ()
{
init();
}
//---------------------------
public static void init ()
{
if(texture == null) texture(Color.BLUE, Color.WHITE);
TextureAttribute ta_tex = TextureAttribute.createDiffuse(texture);
final Material material_box = new Material(ta_tex, ColorAttribute.createSpecular(1, 1, 1, 1),
FloatAttribute.createShininess(8f));
final long attributes1 = Usage.Position | Usage.Normal | Usage.TextureCoordinates;
final Model boxModel = modelBuilder.createBox(1f, 1f, 1f, material_box, attributes1);
...
}
//---------------------------
public Texture texture(Color fg_color, Color bg_color)
{
Pixmap pm = render( fg_color, bg_color );
texture = new Texture(pm);//***here's your new dynamic texture***
disposables.add(texture);//store the texture
}
//---------------------------
public Pixmap render(Color fg_color, Color bg_color)
{
int width = Gdx.graphics.getWidth();
int height = Gdx.graphics.getHeight();
SpriteBatch spriteBatch = new SpriteBatch();
m_fbo = new FrameBuffer(Format.RGB565, (int)(width * m_fboScaler), (int)(height * m_fboScaler), false);
m_fbo.begin();
Gdx.gl.glClearColor(bg_color.r, bg_color.g, bg_color.b, bg_color.a);
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
Matrix4 normalProjection = new Matrix4().setToOrtho2D(0, 0, Gdx.graphics.getWidth(), Gdx.graphics.getHeight());
spriteBatch.setProjectionMatrix(normalProjection);
spriteBatch.begin();
spriteBatch.setColor(fg_color);
//do some drawing ***here's where you draw your dynamic texture***
font.draw(spriteBatch, "5\n6\n2016", width/4, height - 20);//multi-line draw
...
spriteBatch.end();//finish write to buffer
pm = ScreenUtils.getFrameBufferPixmap(0, 0, (int) width, (int) height);//write frame buffer to Pixmap
m_fbo.end();
// pm.dispose();
// flipped.dispose();
// tx.dispose();
m_fbo.dispose();
m_fbo = null;
spriteBatch.dispose();
// return texture;
return pm;
}
//---------------------------
}//class BaseBulletTest
//---------------------------

Related

How to render 3D object within a Libgdx Actor?

Most of the Libgdx tutorials I found show how to add 2D elements in a 3D world, but I would like to know how to the the opposite, adding 3D elements in a 2D Stage.
I tried adding a background image to the Stage, then adding to the Stage an Actor that renders the model batch and the 3D instances in its draw() method.
But instead, the image isn't drawn and part of the 3D object is hidden.
SimpleGame class
public class SimpleGame extends ApplicationAdapter {
Stage stage;
#Override
public void create () {
stage = new Stage();
InputMultiplexer im = new InputMultiplexer(stage);
Gdx.input.setInputProcessor( im );
Image background = new Image(new Texture("badlogic.jpg"));
background.setSize(stage.getWidth(), stage.getHeight());
stage.addActor(background);
setup();
}
private void setup() {
SimpleActor3D group = new SimpleActor3D();
group.setSize(stage.getWidth(), stage.getHeight());
group.setPosition(0, 0);
stage.addActor(group);
}
#Override
public void render () {
stage.act();
Gdx.gl.glClearColor(1, 1, 1, 1);
Gdx.gl.glViewport(0, 0, Gdx.graphics.getWidth(), Gdx.graphics.getHeight());
Gdx.gl.glClear( GL20.GL_COLOR_BUFFER_BIT | GL20.GL_DEPTH_BUFFER_BIT );
stage.draw();
}
}
SimpleActor3D class
public class SimpleActor3D extends Actor {
public Environment environment;
public PerspectiveCamera camera;
public ModelBatch modelBatch;
public ModelInstance boxInstance;
public SimpleActor3D() {
environment = SimpleUtils.createEnvironment();
camera = SimpleUtils.createCamera();
boxInstance = SimpleUtils.createModelInstance(Color.GREEN);
modelBatch = new ModelBatch();
}
#Override
public void draw(Batch batch, float parentAlpha) {
Gdx.gl.glViewport((int)getX(), (int)getY(), (int)getWidth(), (int)getHeight());
modelBatch.begin(camera);
modelBatch.render( boxInstance, environment );
modelBatch.end();
super.draw(batch, parentAlpha);
}
}
SimpleUtils class
public class SimpleUtils {
public static Environment createEnvironment() {
Environment environment = new Environment();
environment.set( new ColorAttribute(ColorAttribute.AmbientLight, 0.4f, 0.4f, 0.4f, 1f) );
DirectionalLight dLight = new DirectionalLight();
Color lightColor = new Color(0.75f, 0.75f, 0.75f, 1);
Vector3 lightVector = new Vector3(-1.0f, -0.75f, -0.25f);
dLight.set( lightColor, lightVector );
environment.add( dLight ) ;
return environment;
}
public static PerspectiveCamera createCamera() {
PerspectiveCamera camera = new PerspectiveCamera(67, Gdx.graphics.getWidth(), Gdx.graphics.getHeight());
camera.position.set(10f, 10f, 10f);
camera.lookAt(0,0,0);
camera.near = 1f;
camera.far = 300f;
camera.update();
return camera;
}
public static ModelInstance createModelInstance(Color color) {
ModelBuilder modelBuilder = new ModelBuilder();
Material boxMaterial = new Material();
boxMaterial.set( ColorAttribute.createDiffuse(color) );
int usageCode = VertexAttributes.Usage.Position + VertexAttributes.Usage.ColorPacked + VertexAttributes.Usage.Normal;
Model boxModel = modelBuilder.createBox( 5f, 5f, 5f, boxMaterial, usageCode );
return new ModelInstance(boxModel);
}
}
What I would like :
What I have instead :
I have tried rendering the model batch directly in the ApplicationAdapter render() method and it works perfectly, so the problems must lie somewhere with the Stage but I can't find how.
I had the same problem but I needed to render 3d object only once so I came with an idea to render 3d model as a Sprite. In order to do that I rendered my model via modelBatch to frame buffer object instead of default screen buffer and then created a sprite from FBO color buffer.
Sample code below:
FrameBuffer frameBuffer = new FrameBuffer(Pixmap.Format.RGBA8888, Gdx.graphics.getBackBufferWidth(), Gdx.graphics.getBackBufferHeight(), true);
Sprite renderModel(ModelInstance modelInstance) {
frameBuffer.begin(); //Capture rendering to frame buffer.
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT | GL20.GL_DEPTH_BUFFER_BIT | (Gdx.graphics.getBufferFormat().coverageSampling ? GL20.GL_COVERAGE_BUFFER_BIT_NV : 0))
modelBatch.begin(camera);
modelBatch.render(modelInstance);
modelBatch.end();
frameBuffer.end();
return new Sprite(frameBuffer.getColorBufferTexture());
}
You can always update your sprite texture in a render loop with use of sprite.setTexture(); method. You can also create an Image from a texture -> new Image(frameBuffer.getColorBufferTexture()); and use it in Scene2d.

Libgdx OrthographicCamera zoom hidding part of Shaperenderer

I'm trying to make an isometric map on Android using libgdx. I'm basicaly drawing shapes with a ShapeRenderer and handling gestures by moving/zooming the camera. Here is my code.
public class MyGdxGame extends ApplicationAdapter{
private OrthographicCamera cam;
private ShapeRenderer mShapeRenderer;
private InputHandler mInputHandler;
#Override
public void create() {
mShapeRenderer = new ShapeRenderer();
mInputHandler = new AndroidInputHandler();
Gdx.input.setInputProcessor(mInputHandler);
Gdx.graphics.setContinuousRendering(false);
}
#Override
public void render() {
System.out.println("render()");
mInputHandler.handleInput(cam);
cam.update();
// clearing scene
Gdx.graphics.getGL20().glClearColor(1, 1, 1, 1);
Gdx.graphics.getGL20().glClear( GL20.GL_COLOR_BUFFER_BIT | GL20.GL_DEPTH_BUFFER_BIT );
//drawing updated scene
mShapeRenderer.setProjectionMatrix(cam.combined);
mShapeRenderer.begin(ShapeRenderer.ShapeType.Filled);
mShapeRenderer.setColor( 0.95f, 0.95f, 0.95f,1);
mShapeRenderer.rect(0, 0, 5.1f, 4.8f);
mShapeRenderer.rect( 6.890f,24.014f,2.201f, 6f);
mShapeRenderer.end();
}
#Override
public void resize(int width, int height) {
cam = new OrthographicCamera( 10f,10f * height / width);
cam.position.set(5, 5, 7);
cam.lookAt(0, 0, 0);
Vector3 up =cam.position.cpy();
up.nor();
up.crs((new Vector3(-1, 1, 0)).nor());
cam.up.set(up);
cam.zoom=1f;
cam.far=100000;
cam.near=0;
}
...
}
InputHandler is a custom class that handle gestures like pinch to zoom and camera translation. It only calls camera.translate(Vector3) and camera.zoom = new zoom.
My problem is that whenever i pinch to zoom, some of my shape are cut.
expected drawing
cutted shapes
I don't realy know where this comes from. I think there is something happening with my viewport. I tried modifying the base zoom and camera viewport sizes but I dont realy understand the concept of viewport width and height.
Any help would be apreciated.
Thanks

CCRenderTexture,GL11ExtensionPack,Libgdx How TO

I currently work on a effect such as "Tiny Wings" http://www.raywenderlich.com/3857/how-to-create-dynamic-textures-with-ccrendertexture ,and find CCRenderTexture is the solution. So I want to know how to make this effect on android , finally I found this link
https://github.com/ZhouWeikuan/cocos2d/blob/master/cocos2d-android/src/org/cocos2d/opengl/CCRenderTexture.java
It shows that its GL11ExtensionPack
GL11ExtensionPack egl = (GL11ExtensionPack)CCDirector.gl;
egl.glGetIntegerv(GL11ExtensionPack.GL_FRAMEBUFFER_BINDING_OES, oldFBO_, 0);
...
But in GLWrapperBase.java ,it shows
// Unsupported GL11ExtensionPack methods
public void glBindFramebufferOES (int target, int framebuffer) {
throw new UnsupportedOperationException();
}
Seems gdx have'nt implement this function . I want to know what's the same feature of libgdx or how to use GL11ExtensionPack at desktop ~
Thanks
In libGDX, you want to use a FrameBuffer object to do the equivalent of a "CCRenderTexture". The FrameBuffer basically lets you use OpenGL commands to draw into an off-screen buffer, and then you can display that buffer's contents as a texture later. See http://code.google.com/p/libgdx/wiki/OpenGLFramebufferObject. Note that the FrameBuffer object is only available if your app requires OpenGL ES 2.0.
Depending on what you want to draw, you might also look at the Pixmap class in libGDX. This supports some simple run-time drawing operations (like lines, rectangels, and pixels). Again the idea is that you draw into this texture and then render the resulting texture on-screen later. This is available in OpenGL ES 1.0, too.
Both FrameBuffer and Pixmap should work fine on Android and on the Desktop (and I believe on GWT and iOS, too..)
Be careful to understand what happens on Android when your app loses focus temporarily (OpenGL context loss causes some texture contents to disappear).
Question : CCRenderTexture,GL11ExtensionPack,Libgdx How TO
interpreted as : In libgdx, how to create dynamic texture.
Answer : Use a private render function to draw in a private frame
Example framework:
==================
package com.badlogic.gdx.tests.bullet;
/**
Question : CCRenderTexture,GL11ExtensionPack,Libgdx How TO
interpreted as : In libgdx, how to create dynamic texture?
Answer : Use a private render function to draw in a private frame buffer
convert the frame bufder to Pixmap, create Texture.
Author : Jon Goodwin
**/
import com.badlogic.gdx.graphics.Texture;
import com.badlogic.gdx.graphics.Pixmap;
...//(ctrl-shift-o) to auto-load imports in Eclipse
public class BaseBulletTest extends BulletTest
{
//class variables
=================
public Texture texture = null;//create this
public Array<Disposable> disposables = new Array<Disposable>();
public Pixmap pm = null;
//---------------------------
#Override
public void create ()
{
init();
}
//---------------------------
public static void init ()
{
if(texture == null) texture(Color.BLUE, Color.WHITE);
TextureAttribute ta_tex = TextureAttribute.createDiffuse(texture);
final Material material_box = new Material(ta_tex, ColorAttribute.createSpecular(1, 1, 1, 1),
FloatAttribute.createShininess(8f));
final long attributes1 = Usage.Position | Usage.Normal | Usage.TextureCoordinates;
final Model boxModel = modelBuilder.createBox(1f, 1f, 1f, material_box, attributes1);
...
}
//---------------------------
public Texture texture(Color fg_color, Color bg_color)
{
Pixmap pm = render( fg_color, bg_color );
texture = new Texture(pm);//***here's your new dynamic texture***
disposables.add(texture);//store the texture
}
//---------------------------
public Pixmap render(Color fg_color, Color bg_color)
{
int width = Gdx.graphics.getWidth();
int height = Gdx.graphics.getHeight();
SpriteBatch spriteBatch = new SpriteBatch();
m_fbo = new FrameBuffer(Format.RGB565, (int)(width * m_fboScaler), (int)(height * m_fboScaler), false);
m_fbo.begin();
Gdx.gl.glClearColor(bg_color.r, bg_color.g, bg_color.b, bg_color.a);
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
Matrix4 normalProjection = new Matrix4().setToOrtho2D(0, 0, Gdx.graphics.getWidth(), Gdx.graphics.getHeight());
spriteBatch.setProjectionMatrix(normalProjection);
spriteBatch.begin();
spriteBatch.setColor(fg_color);
//do some drawing ***here's where you draw your dynamic texture***
...
spriteBatch.end();//finish write to buffer
pm = ScreenUtils.getFrameBufferPixmap(0, 0, (int) width, (int) height);//write frame buffer to Pixmap
m_fbo.end();
// pm.dispose();
// flipped.dispose();
// tx.dispose();
m_fbo.dispose();
m_fbo = null;
spriteBatch.dispose();
// return texture;
return pm;
}
//---------------------------
}//class BaseBulletTest
//---------------------------

Is it possible to render an Android View to an OpenGL FBO or texture?

Is it possible to render a View (say, a WebView) to an FBO so it can be used as a texture in an OpenGL composition?
I brought together a complete demo project which renders a view to GL textures in real time in an efficient way which can be found in this repo. It shows how to render WebView to GL texture in real time as an example.
Also a brief code for this can look like the following (taken from the demo project from the repo above):
public class GLWebView extends WebView {
private ViewToGLRenderer mViewToGLRenderer;
...
// drawing magic
#Override
public void draw( Canvas canvas ) {
//returns canvas attached to gl texture to draw on
Canvas glAttachedCanvas = mViewToGLRenderer.onDrawViewBegin();
if(glAttachedCanvas != null) {
//translate canvas to reflect view scrolling
float xScale = glAttachedCanvas.getWidth() / (float)canvas.getWidth();
glAttachedCanvas.scale(xScale, xScale);
glAttachedCanvas.translate(-getScrollX(), -getScrollY());
//draw the view to provided canvas
super.draw(glAttachedCanvas);
}
// notify the canvas is updated
mViewToGLRenderer.onDrawViewEnd();
}
...
}
public class ViewToGLRenderer implements GLSurfaceView.Renderer{
private SurfaceTexture mSurfaceTexture;
private Surface mSurface;
private int mGlSurfaceTexture;
private Canvas mSurfaceCanvas;
...
#Override
public void onDrawFrame(GL10 gl){
synchronized (this){
// update texture
mSurfaceTexture.updateTexImage();
}
}
#Override
public void onSurfaceChanged(GL10 gl, int width, int height){
releaseSurface();
mGlSurfaceTexture = createTexture();
if (mGlSurfaceTexture > 0){
//attach the texture to a surface.
//It's a clue class for rendering an android view to gl level
mSurfaceTexture = new SurfaceTexture(mGlSurfaceTexture);
mSurfaceTexture.setDefaultBufferSize(mTextureWidth, mTextureHeight);
mSurface = new Surface(mSurfaceTexture);
}
}
public Canvas onDrawViewBegin(){
mSurfaceCanvas = null;
if (mSurface != null) {
try {
mSurfaceCanvas = mSurface.lockCanvas(null);
}catch (Exception e){
Log.e(TAG, "error while rendering view to gl: " + e);
}
}
return mSurfaceCanvas;
}
public void onDrawViewEnd(){
if(mSurfaceCanvas != null) {
mSurface.unlockCanvasAndPost(mSurfaceCanvas);
}
mSurfaceCanvas = null;
}
}
The demo output screenshot:
Yes is it certainly possible, I have written up a how-to here;
http://www.felixjones.co.uk/neo%20website/Android_View/
However for static elements that won't change, the bitmap option may be better.
At least someone managed to render text this way:
Rendering Text in OpenGL on Android
It describes the method I used for rendering high-quality dynamic text efficiently using OpenGL ES 1.0, with TrueType/OpenType font files.
[...]
The whole process is actually quite easy. We generate the bitmap (as a texture), calculate and store the size of each character, as well as it's location on the texture (UV coordinates). There are some other finer details, but we'll get to that.
OpenGL ES 2.0 Version: https://github.com/d3kod/Texample2

TiledSprite not working as expected

I can't seem to get TiledSprite to work as I expect. There are no manuals, and the examples in AndEngineExamples is of no help.
Consider this code:
#Override
public void onLoadResources() {
BitmapTextureAtlasTextureRegionFactory.setAssetBasePath("gfx/");
mBlockAtlas = new BitmapTextureAtlas(512, 512, TextureOptions.BILINEAR_PREMULTIPLYALPHA);
mBlockTexture = BitmapTextureAtlasTextureRegionFactory.createTiledFromAsset(mBlockAtlas, getApplicationContext(), "num_plasma.png", 0, 0, 3, 3);
getTextureManager().loadTexture(mBlockAtlas);
}
This loads a 512x512 texture that I've - manually - divided into 3x3 tiles just for testing purposes. Now, doing this:
public Scene onLoadScene() {
mScene = new Scene();
mScene.setBackground(new ColorBackground(0.5f, 0.1f, 0.6f));
TiledSprite foo, foo2;
foo = new TiledSprite(0, 0, mBlockTexture);
foo.setCurrentTileIndex(1);
foo2 = new TiledSprite(0, 200, mBlockTexture);
foo2.setCurrentTileIndex(5);
mScene.attachChild(foo);
mScene.attachChild(foo2);
return mScene;
}
This puts up two sprites on the screen (as expected), but they both shows the same tile (5)!
How are one supposed to do if you have a bunch of sprites using the same texture but showing different tiles?
I think you need to deepCopy() the Texture when you are creating the Sprites, like
foo2 = new TiledSprite(0, 200, mBlockTexture.deepCopy());

Categories

Resources