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
//---------------------------
Related
I'm currently making an Android player plugin for Unity. The basic idea is that I will play the video by MediaPlayer on Android, which provides a setSurface API receiving a SurfaceTexture as constructor parameter and in the end binds with an OpenGL-ES texture. In most other cases like showing an image, we can just send this texture in form of pointer/id to Unity, call Texture2D.CreateExternalTexture there to generate a Texture2D object and set that to an UI GameObject to render the picture. However, when it comes to displaying video frames, it's a little bit different since video playing on Android requires a texture of type GL_TEXTURE_EXTERNAL_OES while Unity only supports the universal type GL_TEXTURE_2D.
To solve the problem, I've googled for a while and known that I should adopt a kind of technology called "Render to texture". More clear to say, I should generate 2 textures, one for the MediaPlayer and SurfaceTexture in Android to receive video frames and another for Unity that should also has the picture data inside. The first one should be in type of GL_TEXTURE_EXTERNAL_OES (let's call it OES texture for short) and the second one in type of GL_TEXTURE_2D (let's call it 2D texture). Both of these generated textures are empty in the beginning. When bound with MediaPlayer, the OES texture will be updated during video playing, then we can use a FrameBuffer to draw the content of OES texture upon the 2D texture.
I've written a pure-Android version of this process and it works pretty well when I finally draw the 2D texture upon the screen. However, when I publish it as an Unity Android plugin and runs the same code on Unity, there won't be any pictures showing. Instead, it only displays a preset color from glClearColor, which means two things:
The transferring process of OES texture -> FrameBuffer -> 2D texture is complete and Unity do receive the final 2D texture. Because the glClearColor is called only when we draw the content of OES texture to FrameBuffer.
There are some mistakes during drawing happened after glClearColor, because we don't see the video frames pictures. In fact, I also call glReadPixels after drawing and before unbinding with the FrameBuffer, which is going to read data from the FrameBuffer we bound with. And it returns the single color's value that is same with the color we set in glClearColor.
In order to simplify the code I should provide here, I'm going to draw a triangle to a 2D texture through FrameBuffer. If we can figure out which part is wrong, we then can easily solve the similar problem to draw video frames.
The function will be called on Unity:
public int displayTriangle() {
Texture2D texture = new Texture2D(UnityPlayer.currentActivity);
texture.init();
Triangle triangle = new Triangle(UnityPlayer.currentActivity);
triangle.init();
TextureTransfer textureTransfer = new TextureTransfer();
textureTransfer.tryToCreateFBO();
mTextureWidth = 960;
mTextureHeight = 960;
textureTransfer.tryToInitTempTexture2D(texture.getTextureID(), mTextureWidth, mTextureHeight);
textureTransfer.fboStart();
triangle.draw();
textureTransfer.fboEnd();
// Unity needs a native texture id to create its own Texture2D object
return texture.getTextureID();
}
Initialization of 2D texture:
protected void initTexture() {
int[] idContainer = new int[1];
GLES30.glGenTextures(1, idContainer, 0);
textureId = idContainer[0];
Log.i(TAG, "texture2D generated: " + textureId);
// texture.getTextureID() will return this textureId
bindTexture();
GLES30.glTexParameterf(GLES30.GL_TEXTURE_2D,
GLES30.GL_TEXTURE_MIN_FILTER, GLES30.GL_NEAREST);
GLES30.glTexParameterf(GLES30.GL_TEXTURE_2D,
GLES30.GL_TEXTURE_MAG_FILTER, GLES30.GL_LINEAR);
GLES30.glTexParameteri(GLES30.GL_TEXTURE_2D,
GLES30.GL_TEXTURE_WRAP_S, GLES30.GL_CLAMP_TO_EDGE);
GLES30.glTexParameteri(GLES30.GL_TEXTURE_2D,
GLES30.GL_TEXTURE_WRAP_T, GLES30.GL_CLAMP_TO_EDGE);
unbindTexture();
}
public void bindTexture() {
GLES30.glBindTexture(GLES30.GL_TEXTURE_2D, textureId);
}
public void unbindTexture() {
GLES30.glBindTexture(GLES30.GL_TEXTURE_2D, 0);
}
draw() of Triangle:
public void draw() {
float[] vertexData = new float[] {
0.0f, 0.0f, 0.0f,
1.0f, -1.0f, 0.0f,
1.0f, 1.0f, 0.0f
};
vertexBuffer = ByteBuffer.allocateDirect(vertexData.length * 4)
.order(ByteOrder.nativeOrder())
.asFloatBuffer()
.put(vertexData);
vertexBuffer.position(0);
GLES30.glClearColor(0.0f, 0.0f, 0.9f, 1.0f);
GLES30.glClear(GLES30.GL_DEPTH_BUFFER_BIT | GLES30.GL_COLOR_BUFFER_BIT);
GLES30.glUseProgram(mProgramId);
vertexBuffer.position(0);
GLES30.glEnableVertexAttribArray(aPosHandle);
GLES30.glVertexAttribPointer(
aPosHandle, 3, GLES30.GL_FLOAT, false, 12, vertexBuffer);
GLES30.glDrawArrays(GLES30.GL_TRIANGLE_STRIP, 0, 3);
}
vertex shader of Triangle:
attribute vec4 aPosition;
void main() {
gl_Position = aPosition;
}
fragment shader of Triangle:
precision mediump float;
void main() {
gl_FragColor = vec4(0.9, 0.0, 0.0, 1.0);
}
Key code of TextureTransfer:
public void tryToInitTempTexture2D(int texture2DId, int textureWidth, int textureHeight) {
if (mTexture2DId != -1) {
return;
}
mTexture2DId = texture2DId;
GLES30.glBindTexture(GLES30.GL_TEXTURE_2D, mTexture2DId);
Log.i(TAG, "glBindTexture " + mTexture2DId + " to init for FBO");
// make 2D texture empty
GLES30.glTexImage2D(GLES30.GL_TEXTURE_2D, 0, GLES30.GL_RGBA, textureWidth, textureHeight, 0,
GLES30.GL_RGBA, GLES30.GL_UNSIGNED_BYTE, null);
Log.i(TAG, "glTexImage2D, textureWidth: " + textureWidth + ", textureHeight: " + textureHeight);
GLES30.glBindTexture(GLES30.GL_TEXTURE_2D, 0);
fboStart();
GLES30.glFramebufferTexture2D(GLES30.GL_FRAMEBUFFER, GLES30.GL_COLOR_ATTACHMENT0,
GLES30.GL_TEXTURE_2D, mTexture2DId, 0);
Log.i(TAG, "glFramebufferTexture2D");
int fboStatus = GLES30.glCheckFramebufferStatus(GLES30.GL_FRAMEBUFFER);
Log.i(TAG, "fbo status: " + fboStatus);
if (fboStatus != GLES30.GL_FRAMEBUFFER_COMPLETE) {
throw new RuntimeException("framebuffer " + mFBOId + " incomplete!");
}
fboEnd();
}
public void fboStart() {
GLES30.glBindFramebuffer(GLES30.GL_FRAMEBUFFER, mFBOId);
}
public void fboEnd() {
GLES30.glBindFramebuffer(GLES30.GL_FRAMEBUFFER, 0);
}
And finally some code on Unity-side:
int textureId = plugin.Call<int>("displayTriangle");
Debug.Log("native textureId: " + textureId);
Texture2D triangleTexture = Texture2D.CreateExternalTexture(
960, 960, TextureFormat.RGBA32, false, true, (IntPtr) textureId);
triangleTexture.UpdateExternalTexture(triangleTexture.GetNativeTexturePtr());
rawImage.texture = triangleTexture;
rawImage.color = Color.white;
Well, code above will not display the expected triangle but only a blue background. I add glGetError after nearly every OpenGL functions call while no errors are thrown.
My Unity version is 2017.2.1. For Android build, I shut down the experimental multithread rendering and other settings are all default(no texture compression, not use development build, so on). My app's minimum API level is 5.0 Lollipop and target API level is 9.0 Pie.
I really need some help, thanks in advance!
Now I found the answer: If you want to do any drawing jobs in your plugin, you should do it at native layer. So if you want to make an Android plugin, you should call OpenGL-ES APIs at JNI instead of Java side. The reason is that Unity only allows drawing graphics on its rendering thread. If you simply call OpenGL-ES APIs like I did at Java side as in question description, they will actually run on Unity main thread instead of rendering thread. Unity provides a method, GL.IssuePluginEvent, to call your own functions on rendering thread but it needs native coding since this function requires a function pointer as its callback. Here is a simple example to use it:
At JNI side:
// you can copy these headers from https://github.com/googlevr/gvr-unity-sdk/tree/master/native_libs/video_plugin/src/main/jni/Unity
#include "IUnityInterface.h"
#include "UnityGraphics.h"
static void on_render_event(int event_type) {
// do all of your jobs related to rendering, including initializing the context,
// linking shaders, creating program, finding handles, drawing and so on
}
// UnityRenderingEvent is an alias of void(*)(int) defined in UnityGraphics.h
UnityRenderingEvent get_render_event_function() {
UnityRenderingEvent ptr = on_render_event;
return ptr;
}
// notice you should return a long value to Java side
extern "C" JNIEXPORT jlong JNICALL
Java_com_abc_xyz_YourPluginClass_getNativeRenderFunctionPointer(JNIEnv *env, jobject instance) {
UnityRenderingEvent ptr = get_render_event_function();
return (long) ptr;
}
At Android Java side:
class YourPluginClass {
...
public native long getNativeRenderFunctionPointer();
...
}
At Unity side:
private void IssuePluginEvent(int pluginEventType) {
long nativeRenderFuncPtr = Call_getNativeRenderFunctionPointer(); // call through plugin class
IntPtr ptr = (IntPtr) nativeRenderFuncPtr;
GL.IssuePluginEvent(ptr, pluginEventType); // pluginEventType is related to native function parameter event_type
}
void Start() {
IssuePluginEvent(1); // let's assume 1 stands for initializing everything
// get your texture2D id from plugin, create Texture2D object from it,
// attach that to a GameObject, and start playing for the first time
}
void Update() {
// call SurfaceTexture.updateTexImage in plugin
IssuePluginEvent(2); // let's assume 2 stands for transferring TEXTURE_EXTERNAL_OES to TEXTURE_2D through FrameBuffer
// call Texture2D.UpdateExternalTexture to update GameObject's appearance
}
You still need to transfer texture and everything about it should happen at JNI layer. But don't worry, they are nearly the same as I did in question description but only in a different language than Java and there are a lot of materials about this process so you can surely make it.
Finally let me address the key to solve this problem again: do your native stuff at native layer and don't be addicted to pure Java... I'm totally surprised that there are no blog/answer/wiki to tell us just write our code in C++. Although there are some open-source implementations like Google's gvr-unity-sdk, they give a complete reference but you'll still be doubt that maybe you can finish the task without writing any C++ code. Now we know that we can't. However, to be honest, I think Unity have the ability to make this progress even easier.
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.
I've had reports from a couple of users (from 85000 downloads) of the problem shown in the image below. No doubt it has occurred a few more times than this, but it's certainly rare.
I'm unable to reproduce the problem and don't believe it's specific to device as some users would appear to be playing the game perfectly happily on the same device models that have reported the problem.
The letters are drawn onto a frame buffer first to build them up from the circular background with the character drawn on top. They are then copied off and a new texture is created.
The background is also put together from multiple components on a frame buffer and copied off to create a texture, so I'm not too sure why that appears to work perfectly well when the letters don't. The background is drawn using the same FrameBuffer and the same SpriteBatch instance.
What it does look like
What it should look like
Method that create the images
private static Texture getTextureUsingGpu(String letter, Bubble.BubbleType bubbleType) {
if (!enabled)
return null;
StrokeFontHelper font = Assets.strokeFont;
font.setSettings(Fonts.BUBBLE_TEXT_SETTINGS);
TextureRegion tx = getBlockImage(letter, bubbleType);
FrameBuffer fb = TextureLoader.getFrameBuffer();
fb.begin();
Gdx.gl20.glClearColor(0.0f, 0.0f, 0.0f, 1);
// Make sure everything is really really clear! Trying to fix graphics glitches on some phones
Gdx.gl20.glClear(GL20.GL_COLOR_BUFFER_BIT | GL20.GL_DEPTH_BUFFER_BIT | GL20.GL_STENCIL_BUFFER_BIT | GL20.GL_SUBPIXEL_BITS);
float width = tx.getRegionWidth();
float height = tx.getRegionHeight();
TextureLoader.sb.begin();
tx.flip(false, !tx.isFlipY());
TextureLoader.sb.disableBlending();
TextureLoader.sb.draw(tx, 0, 0);
TextureLoader.sb.enableBlending();
// Removed character drawing code to make it more readable
TextureLoader.sb.end();
Pixmap pm = ScreenUtils.getFrameBufferPixmap(0, 0, (int) width,
(int) height);
PixmapTextureData data = new PixmapTextureData(pm, Format.RGBA8888,
false, false, true);
Texture result = new Texture(data);
result.setFilter(TextureFilter.Linear, TextureFilter.Linear);
cacheTexture(letter, result, pm);
fb.end();
return result;
}
public static FrameBuffer getFrameBuffer() {
if (frameBuffer == null || frameBuffer.getWidth() != Gdx.graphics.getWidth() || frameBuffer.getHeight() != Gdx.graphics.getHeight()) {
if (frameBuffer != null)
frameBuffer.dispose();
// Create the highest quality frame buffer we can get away with
try {
frameBuffer = new FrameBuffer(Pixmap.Format.RGBA8888, Gdx.graphics.getWidth(), Gdx.graphics.getHeight(), false);
} catch (Exception e) {
try {
frameBuffer = new FrameBuffer(Pixmap.Format.RGB888, Gdx.graphics.getWidth(), Gdx.graphics.getHeight(), false);
} catch (Exception e2) {
frameBuffer = new FrameBuffer(Pixmap.Format.RGB565, Gdx.graphics.getWidth(), Gdx.graphics.getHeight(), false);
}
}
// Set up the camera correctly for the frame buffer
camera = new OrthographicCamera(frameBuffer.getWidth(), frameBuffer.getHeight());
camera.position.set(frameBuffer.getWidth() * 0.5f, frameBuffer.getHeight() * 0.5f, 0);
camera.update();
sb.setProjectionMatrix(camera.combined);
}
return frameBuffer;
}
Edit
I've done some fiddling with this and have a very helpful user who has been testing versions for me. Here's what I've established.
If I use a ShapeRenderer rather than a SpriteBatch then I can draw over the whole area as expected.
It is almost certainly the point at which I draw textures to the FrameBuffer using the SpriteBatch that the problem occurs. It just doesn't draw to the bottom half of the textures. What's on the FreameBuffer is copied to the pixmap correctly.
Another Edit I've got a new visual glitch reported by a user. I don't know if this might shed some more light on a problem.
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
//---------------------------
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