I want to capture the rendered scene in my Android openGl App in A Texture Using FrameBuffer Object.
EveryThing is Fine in the emulator, But on Real Device the frameBuffer Object wouldn't work,
meaning Nothing Goes to my Texture, Here is the FBO Class (For Creating FrameBuffer and creating texture of it):
public class FBO {
int [] fb, renderTex;
int [] TextureBank;
int top;
int texW;
int texH;
int maxTextures;
public FBO(int width,int height,int maxTextures){
texW = width;
texH = height;
fb = new int[1];
renderTex= new int[1];
top=-1;
this.maxTextures = maxTextures;
TextureBank = new int[maxTextures];
}
public void setup(GL10 gl){
// generate
((GL11ExtensionPack)gl).glGenFramebuffersOES(1, fb, 0);
gl.glEnable(GL10.GL_TEXTURE_2D);
gl.glGenTextures(1, renderTex, 0);// generate texture
gl.glBindTexture(GL10.GL_TEXTURE_2D, renderTex[0]);
gl.glTexParameterf(GL10.GL_TEXTURE_2D,
GL10.GL_TEXTURE_MIN_FILTER, GL10.GL_NEAREST);
gl.glTexParameterf(GL10.GL_TEXTURE_2D,
GL10.GL_TEXTURE_MAG_FILTER, GL10.GL_NEAREST);
gl.glTexParameterf(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_WRAP_S,
GL10.GL_CLAMP_TO_EDGE);
gl.glTexParameterf(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_WRAP_T,
GL10.GL_CLAMP_TO_EDGE);
//texBuffer = ByteBuffer.allocateDirect(buf.length*4).order(ByteOrder.nativeOrder()).asIntBuffer();
//gl.glTexEnvf(GL10.GL_TEXTURE_ENV, GL10.GL_TEXTURE_ENV_MODE,GL10.GL_MODULATE);
gl.glTexImage2D(GL10.GL_TEXTURE_2D, 0, GL10.GL_RGBA, texW, texH, 0, GL10.GL_RGBA, GL10.GL_FLOAT, null);
gl.glDisable(GL10.GL_TEXTURE_2D);
if(top>=maxTextures-1){
Log.e("OUT OF TEXTURE COUNTS", "OUT OF TEXTURE COUNTS Texture WIll Not Be added to Stack");
}
else{
TextureBank [++top]= renderTex[0];
Log.d("TOP= ", "" + top);
}
}
public boolean RenderStart(GL10 gl){
// Bind the framebuffer
((GL11ExtensionPack)gl).glBindFramebufferOES(GL11ExtensionPack.GL_FRAMEBUFFER_OES, fb[0]);
// specify texture as color attachment
((GL11ExtensionPack)gl).glFramebufferTexture2DOES(GL11ExtensionPack.GL_FRAMEBUFFER_OES, GL11ExtensionPack.GL_COLOR_ATTACHMENT0_OES, GL10.GL_TEXTURE_2D, renderTex[0], 0);
int error = gl.glGetError();
if (error != GL10.GL_NO_ERROR) {
Log.d("err", "FIRST Background Load GLError: " + error+" ");
}
int status = ((GL11ExtensionPack)gl).glCheckFramebufferStatusOES(GL11ExtensionPack.GL_FRAMEBUFFER_OES);
if (status != GL11ExtensionPack.GL_FRAMEBUFFER_COMPLETE_OES)
{
Log.d("err", "SECOND Background Load GLError: " + status+" ");;
return true;
}
gl.glClear(GL10.GL_COLOR_BUFFER_BIT);
return true;
}
public void RenderEnd(GL10 gl){
((GL11ExtensionPack)gl).glBindFramebufferOES(GL11ExtensionPack.GL_FRAMEBUFFER_OES, 0);
gl.glClear(GL10.GL_COLOR_BUFFER_BIT | GL10.GL_DEPTH_BUFFER_BIT);
gl.glEnable(GL10.GL_TEXTURE_2D);
gl.glBindTexture(GL10.GL_TEXTURE_2D, 0);
gl.glColor4f(1,1,1,1);
gl.glDisable(GL10.GL_TEXTURE_2D);
}
public int getTexture(){
return renderTex[0];
}
}
And here is my OnDrawFrame Method Which uses this FBO:
public synchronized void onDrawFrame(GL10 gl) {
mObserver.onDrawFrame();
gl.glClearColor(Color.red(mBackgroundColor) / 255f,
Color.green(mBackgroundColor) / 255f,
Color.blue(mBackgroundColor) / 255f,
Color.alpha(mBackgroundColor) / 255f);
gl.glClear(GL10.GL_COLOR_BUFFER_BIT | GL10.GL_DEPTH_BUFFER_BIT);
gl.glLoadIdentity();
if(capture){
if(AttachTexture){
int h = gl.glGetError();
/**
Setup FBO
*/
frameBuffer.setup(gl);
if(h!=0){
Log.d("ERROR", "ERROR Happend"+h+"");
}
AttachTexture = false;
}
/**
Start Rendering In FBO
*/
frameBuffer.RenderStart(gl);
if (USE_PERSPECTIVE_PROJECTION) {
double x = mCurlMesh.GetMinX()* mCurlMesh.GetMinY();
gl.glTranslatef((float)(-1.000-mCurlMesh.GetMinX()),(float)(-1.000-mCurlMesh.GetMinY()), -6f);
}
gl.glMatrixMode(GL10.GL_PROJECTION);
gl.glLoadIdentity();
GLU.gluOrtho2D(gl, (float)mCurlMesh.GetMinX(), (float)mCurlMesh.GetMaxX(),
(float)mCurlMesh.GetMinY(), (float)mCurlMesh.GetMaxY());
gl.glMatrixMode(GL10.GL_MODELVIEW);
gl.glLoadIdentity();
gl.glViewport(0, 0,texW,texH);
mCurlMesh.onDrawFrame(gl);
/**
End Rendering In FBO
*/
frameBuffer.RenderEnd(gl);
}
//Reset Every Thing to Its Normal State
gl.glMatrixMode(GL10.GL_PROJECTION);
gl.glLoadIdentity();
GLU.gluOrtho2D(gl, -1.1f,1.1f,-1.1f, 1.1f);
gl.glMatrixMode(GL10.GL_MODELVIEW);
gl.glLoadIdentity();
gl.glViewport(0, 0, mViewportWidth, mViewportHeight);
mCurlMesh.onDrawFrame(gl);
}
I Should mention that my Texture size IS 2^n:
frameBuffer = new FBO(1024, 1024, 8);
Related
Guys i need your help again :)
MainRenderer.java:
package com.example.galaga2d;
import java.nio.ByteBuffer;
import java.nio.FloatBuffer;
import java.nio.ByteOrder;
import java.util.Random;
import java.util.Vector;
import javax.microedition.khronos.egl.EGLConfig;
import javax.microedition.khronos.opengles.GL10;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.opengl.GLES20;
import android.opengl.GLSurfaceView.Renderer;
import android.opengl.GLUtils;
public class MainRenderer implements Renderer {
Random rand = new Random();
float chance = 0.0f;
private Context context;
public Ship playerShip = new Ship();
Vector<Asteroid> asteroidVector = new Vector<Asteroid>();
public MainRenderer(Context context) {
this.context = context;
}
#Override
public void onSurfaceCreated(GL10 gl, EGLConfig config) {
//! TEXTURES
playerShip.loadGLTexture(gl, this.context);
gl.glEnable(GL10.GL_TEXTURE_2D);
gl.glEnable(GL10.GL_BLEND);
gl.glBlendFunc(GL10.GL_ONE, GL10.GL_SRC_COLOR);
//gl.glShadeModel(GL10.GL_SMOOTH);
//! TEXTURES
gl.glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
}
#Override
public void onDrawFrame(GL10 gl) {
gl.glClear(GL10.GL_COLOR_BUFFER_BIT);
gl.glLoadIdentity();
chance = rand.nextFloat() * (100.0f - 1.0f) + 1.0f;
if (chance <= 4.0f) {
asteroidVector.addElement(new Asteroid());
}
if (playerShip.life != 0) {
playerShip.draw(gl);
gl.glLoadIdentity();
for (int i = 0; i < asteroidVector.size(); i++) {
if(asteroidVector.elementAt(i).textured == 0) {
asteroidVector.elementAt(i).loadGLTexture(gl, this.context);
asteroidVector.elementAt(i).textured |= 1;
//gl.glLoadIdentity();
} else {
asteroidVector.elementAt(i).textured &= ~1;
}
}
for (int i = 0; i < asteroidVector.size(); i++) {
asteroidVector.elementAt(i).collisionCheck();
asteroidVector.elementAt(i).draw(gl);
if (asteroidVector.elementAt(i).Y > 480.0f) {
asteroidVector.remove(i);
}
gl.glLoadIdentity();
}
} else {
gl.glClearColor(0.0f, 0.0f, 1.0f, 1.0f);
}
}
#Override
public void onSurfaceChanged(GL10 gl, int width, int height) {
gl.glViewport(0, 0, width, height);
gl.glMatrixMode(GL10.GL_PROJECTION);
gl.glLoadIdentity();
gl.glOrthof(0, width, height, 0, 1, -1);
gl.glViewport(0, 0, width, height);
gl.glMatrixMode(GL10.GL_MODELVIEW);
gl.glLoadIdentity();
}
// --------------------------------------------------------------------------------
class Ship {
public int life = 3; // Количество жизней игрока
public FloatBuffer ShipVertexBuffer; // Vertex буффер
public FloatBuffer ShipTextureBuffer; // Texture буффер
public float X = 100.0f; // Начальные координаты игрока по X
public float Y = 300.0f; // Начальные координаты игрока по Y
//! TEXTURES
private int[] textures = new int[1];
//! TEXTURES
public float ShipVerticles[] = { // Вертикли прямоугольника - корабль
0, 0,
0, 30,
30, 0,
30, 30
};
//! TEXTURES
public float ShipTextures[] = { // Разметка наложения текстуры, соответствует
0.0f, 0.0f, // разметке вертиклей
0.0f, 1.0f,
1.0f, 0.0f,
1.0f, 1.0f
};
//! TEXTURES
public Ship() {
//! Буффер вертексов
ByteBuffer bb = ByteBuffer.allocateDirect(36);
bb.order(ByteOrder.nativeOrder());
ShipVertexBuffer = bb.asFloatBuffer();
ShipVertexBuffer.put(ShipVerticles);
ShipVertexBuffer.position(0);
//! TEXTURES
bb = ByteBuffer.allocateDirect(ShipTextures.length * 4);
bb.order(ByteOrder.nativeOrder());
ShipTextureBuffer = bb.asFloatBuffer();
ShipTextureBuffer.put(ShipTextures);
ShipTextureBuffer.position(0);
//! TEXTURES
}
public void loadGLTexture(GL10 gl, Context context) {
// loading texture
Bitmap bitmap = BitmapFactory.decodeResource(context.getResources(),
R.drawable.ship);
// generate one texture pointer
gl.glGenTextures(1, textures, 0);
// ...and bind it to our array
gl.glBindTexture(GL10.GL_TEXTURE_2D, textures[0]);
// create nearest filtered texture
gl.glTexParameterf(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_MIN_FILTER, GL10.GL_NEAREST);
GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MIN_FILTER, GLES20.GL_NEAREST);
gl.glTexParameterf(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_MAG_FILTER, GL10.GL_LINEAR);
// Use Android GLUtils to specify a two-dimensional texture image from our bitmap
GLUtils.texImage2D(GL10.GL_TEXTURE_2D, 0, bitmap, 0);
// Clean up
bitmap.recycle();
}
public void draw(GL10 gl) {
//! TEXTURE
gl.glBindTexture(GL10.GL_TEXTURE_2D, textures[0]);
gl.glEnableClientState(GL10.GL_VERTEX_ARRAY);
gl.glEnableClientState(GL10.GL_TEXTURE_COORD_ARRAY);
//! TEXTURE
gl.glColor4f(1.0f, 1.0f, 1.0f, 1.0f);
gl.glTranslatef(playerShip.X, playerShip.Y, 0.0f);
gl.glVertexPointer(2, GL10.GL_FLOAT, 0, ShipVertexBuffer);
//! TEXTURE
gl.glTexCoordPointer(2, GL10.GL_FLOAT, 0, ShipTextureBuffer);
//! TEXTURE
gl.glDrawArrays(GL10.GL_TRIANGLE_STRIP, 0, 4);
//! TEXTURE
gl.glDisableClientState(GL10.GL_VERTEX_ARRAY);
gl.glDisableClientState(GL10.GL_TEXTURE_COORD_ARRAY);
//! TEXTURE
}
}
class Asteroid {
private float colorR = rand.nextFloat()* (1.0f - 0.3f) + 0.3f;
private float colorG = rand.nextFloat()* (1.0f - 0.3f) + 0.3f;
private float colorB = rand.nextFloat()* (1.0f - 0.3f) + 0.3f;
private float X = rand.nextFloat() * (300.0f - 1.0f) + 1.0f;
private float Y = -30.0f;
private float size = rand.nextFloat() * (30.0f - 20.0f) + 20.0f;
private float speed = rand.nextFloat() * (10.0f - 1.0f) + 1.0f;
private int collision = 0;
private int textured = 0;
private FloatBuffer AsteroidVertexBuffer;
private FloatBuffer AsteroidTextureBuffer;
//! TEXTURES
private int[] textures = new int[1];
//! TEXTURES
public float AsteroidVerticles[] = {
0, 0, // лево низ
0, size, // лево вверх
size, 0, // право низ
size, size // право вверх
};
//! TEXTURES
public float AsteroidTextures[] = {
0.0f, 0.0f,
0.0f, 1.0f,
1.0f, 0.0f,
1.0f, 1.0f
};
//! TEXTURES
public Asteroid() {
ByteBuffer bb = ByteBuffer.allocateDirect(36);
bb.order(ByteOrder.nativeOrder());
AsteroidVertexBuffer = bb.asFloatBuffer();
AsteroidVertexBuffer.put(AsteroidVerticles);
AsteroidVertexBuffer.position(0);
//! TEXTURES
bb = ByteBuffer.allocateDirect(AsteroidTextures.length * 4);
bb.order(ByteOrder.nativeOrder());
AsteroidTextureBuffer = bb.asFloatBuffer();
AsteroidTextureBuffer.put(AsteroidTextures);
AsteroidTextureBuffer.position(0);
//! TEXTURES
}
public void collisionCheck() {
float result = (float)Math.sqrt(Math.pow((playerShip.X-X), 2)+Math.pow((playerShip.Y-Y), 2));
if (result < size)
{
if(collision == 0)
{
playerShip.life = playerShip.life - 1;
collision |= 1;
}
} else {
collision &= ~1;
}
}
public void loadGLTexture(GL10 gl, Context context) {
// loading texture
Bitmap bitmap = BitmapFactory.decodeResource(context.getResources(),
R.drawable.asteroid);
// generate one texture pointer
gl.glGenTextures(1, textures, 0);
// ...and bind it to our array
gl.glBindTexture(GL10.GL_TEXTURE_2D, textures[0]);
// create nearest filtered texture
gl.glTexParameterf(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_MIN_FILTER, GL10.GL_NEAREST);
GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MIN_FILTER, GLES20.GL_NEAREST);
gl.glTexParameterf(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_MAG_FILTER, GL10.GL_LINEAR);
// Use Android GLUtils to specify a two-dimensional texture image from our bitmap
GLUtils.texImage2D(GL10.GL_TEXTURE_2D, 0, bitmap, 0);
// Clean up
bitmap.recycle();
}
public void draw(GL10 gl) {
Y += speed;
//! TEXTURE
gl.glBindTexture(GL10.GL_TEXTURE_2D, textures[0]);
gl.glEnableClientState(GL10.GL_VERTEX_ARRAY);
gl.glEnableClientState(GL10.GL_TEXTURE_COORD_ARRAY);
//! TEXTURE
gl.glColor4f(colorR, colorG, colorB, 1.0f);
gl.glTranslatef(X, Y, 0.0f);
gl.glVertexPointer(2, GL10.GL_FLOAT, 0, AsteroidVertexBuffer);
//! TEXTURE
gl.glTexCoordPointer(2, GL10.GL_FLOAT, 0, AsteroidTextureBuffer);
//! TEXTURE
gl.glDrawArrays(GL10.GL_TRIANGLE_STRIP, 0, 4);
//! TEXTURE
gl.glDisableClientState(GL10.GL_VERTEX_ARRAY);
gl.glDisableClientState(GL10.GL_TEXTURE_COORD_ARRAY);
//! TEXTURE
}
}
// --------------------------------------------------------------------------------
}
Every frame drawing object asteroid by chance:
chance = rand.nextFloat() * (100.0f - 1.0f) + 1.0f;
if (chance <= 4.0f) {
asteroidVector.addElement(new Asteroid());
}
Thats mean we need to load texture for all new objects we draw every second, but we dont need to load texture for one object many times, and i add flag to check is object textured or not:
for (int i = 0; i < asteroidVector.size(); i++) {
if(asteroidVector.elementAt(i).textured == 0) {
asteroidVector.elementAt(i).loadGLTexture(gl, this.context);
asteroidVector.elementAt(i).textured |= 1;
//gl.glLoadIdentity();
} else {
asteroidVector.elementAt(i).textured &= ~1;
}
}
After object created and textured, we need to delete it if he go over screen border, so i do this:
for (int i = 0; i < asteroidVector.size(); i++) {
asteroidVector.elementAt(i).collisionCheck();
asteroidVector.elementAt(i).draw(gl);
//! THIS
if (asteroidVector.elementAt(i).Y > 480.0f) {
asteroidVector.remove(i);
}
//! THIS
gl.glLoadIdentity();
}
But that not enough, because tuxture buffer dont clear, and after 10-20 seconds on application running i have see some lagging and low fps.
The question is - How i can clear texture buffer or memory? To fix lagging and low fps?
I suppose you could do that, but then again you shouldn't be getting yourself into a situation where you actually need to in the first place.
As it now stands, you're creating a new texture object (and never freeing it!) for every Asteroid that's ever constructed, which is absolutely not necessary - a great way to fix that is to use a shared texture object for all of your Asteroid instances.
In a static function (called once), simply decode the image resource to raw pixel data -> glGenTextures -> glBindTexture -> glTexParam... calls ->GLUtils.TexImage2D -> free the (client-side) decoded raw pixel data and store the texture id (given by glGenTextures) into a static variable within the Asteroid class. Having done this, you can just bind to this shared texture object at the rendering stage (ie. draw), and proceed as you normally would.
As said before, never calling glDeleteTextures is the second part of your problem, although now that you're (hopefully) using a shared texture object for your Asteroid instances, it becomes much less important.
(Furthermore, even the vertex/texcoord buffer can be shared between instances, provided they are identical :P)
after a long search, I didn't find any solution to my problem, so here it is:
I have the following sprite:
http://i46.tinypic.com/rmji2d.png"">
but in my game with a OpenGLSurface, using 2d texture it looks like this:
http://i47.tinypic.com/2wqb9qs.png"">
The options I'm using in my textures are these:
public void onSurfaceCreated(GL10 gl, EGLConfig confid) {
gl.glEnable(GL10.GL_TEXTURE_2D);
gl.glShadeModel(GL10.GL_SMOOTH);
gl.glClearColor(255,255, 255,0);
gl.glClearDepthf(1.0f);
gl.glEnable(GL10.GL_BLEND);
gl.glDisable(GL10.GL_DEPTH_TEST);
gl.glBlendFunc(GL10.GL_SRC_ALPHA, GL10.GL_ONE_MINUS_SRC_ALPHA);
}
public void loadTextures(GL10 gl, Context context) {
gl.glGenTextures(textureCount, textures, 0);
for (int loop = 0; loop < textureCount; loop++) {
gl.glBindTexture(GL10.GL_TEXTURE_2D, textures[loop]);
gl.glTexParameterf(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_MAG_FILTER,
GL10.GL_LINEAR);
gl.glTexParameterf(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_MIN_FILTER,
GL10.GL_LINEAR);
gl.glHint(GL10.GL_PERSPECTIVE_CORRECTION_HINT, // OpenGL docs.
GL10.GL_NICEST);
GLUtils.texImage2D(GL10.GL_TEXTURE_2D, 0, bitmap[loop], 0);
bitmap[loop].recycle();
}
}
Is it only this weird because i'm scaling the image, making it shortier?
Is there anything i can do to have better graphics?
ADDED the DRAW:
public void draw(GL10 gl) {
gl.glBindTexture(GL10.GL_TEXTURE_2D, textures[0]);
for (int loop = 0; loop < sprites.size(); loop++) {
gl.glPushMatrix();
try {
DevQuestSprite sprite = sprites.get(loop);
sprite.update(screenHeight); // update enemy
gl.glBindTexture(GL10.GL_TEXTURE_2D, textures[sprite.curSprite]);
float transx = (wRatio * sprite.x);
float transy = (screenHeight * wRatio) - (wRatio * sprite.y)
- 1 / hRatio;
gl.glTranslatef(transx, transy, 0.0f);
sprite.draw(gl);
} catch (NullPointerException e) {
}
gl.glPopMatrix();
}
}
I am trying to rotate the texture around its center but it is not giving the expected results can you please see the code and let me know what i am missing?
here is my code
public class GLRenderer implements Renderer {
Context context;
Square s;
float x = 100 ,y = 100 ;
float w,h;
public GLRenderer(Context c) {
context = c;
s = new Square(x,y);
}
#Override
public void onDrawFrame(GL10 gl) {
s.draw(gl);
}
#Override
public void onSurfaceChanged(GL10 gl, int width, int height) {
gl.glViewport(0, 0, width, height);
gl.glOrthof(0, 320, 0, 480, 0, 1);
gl.glMatrixMode(GL10.GL_PROJECTION);
gl.glLoadIdentity();
gl.glEnable(GL10.GL_TEXTURE_2D);
}
#Override
public void onSurfaceCreated(GL10 gl, EGLConfig config) {
gl.glClear(GL10.GL_COLOR_BUFFER_BIT);
s.loadGLTexture(gl, R.drawable.ic_launcher);
}
public class Square{
int textures[] = new int[1];
FloatBuffer vertexbuffer;
FloatBuffer texturebuffer;
float texture[] ={
1.0f, 1.0f,
1.0f, 0.0f,
0.0f, 1.0f,
0.0f, 0.0f
};
public Square(float x, float y){
float vertices[] = {
x,y,0,
x,y+100,0,
x+100,y,0,
x+100,y+100,0
};
ByteBuffer vbb = ByteBuffer.allocateDirect(vertices.length*4);
vbb.order(ByteOrder.nativeOrder());
vertexbuffer = vbb.asFloatBuffer();
vertexbuffer.put(vertices);
vertexbuffer.position(0);
ByteBuffer tbb = ByteBuffer.allocateDirect(texture.length*4);
tbb.order(ByteOrder.nativeOrder());
texturebuffer = tbb.asFloatBuffer();
texturebuffer.put(texture);
texturebuffer.position(0);
}
public void draw(GL10 gl) {
gl.glPushMatrix();
gl.glTranslatef(-150, -150, 0);
gl.glRotatef(30,0, 0,1 );
gl.glTranslatef(150, 150, 0);
// Point to our buffers
gl.glEnableClientState(GL10.GL_VERTEX_ARRAY);
gl.glEnableClientState(GL10.GL_TEXTURE_COORD_ARRAY);
// Set the face rotation
gl.glFrontFace(GL10.GL_CW);
// Point to our vertex buffer
gl.glVertexPointer(3, GL10.GL_FLOAT, 0, vertexbuffer);
gl.glTexCoordPointer(2, GL10.GL_FLOAT, 0, texturebuffer);
// Draw the vertices as triangle strip
gl.glDrawArrays(GL10.GL_TRIANGLE_STRIP, 0, 4);
//Disable the client state before leaving
gl.glDisableClientState(GL10.GL_VERTEX_ARRAY);
gl.glDisableClientState(GL10.GL_TEXTURE_COORD_ARRAY);
r = r+10;
gl.glPopMatrix();
}
public void loadGLTexture(GL10 gl, int drawable) {
Bitmap bitmap = BitmapFactory.decodeResource(context.getResources(),
drawable);
gl.glGenTextures(1, textures, 0);
gl.glBindTexture(GL10.GL_TEXTURE_2D, textures[0]);
gl.glTexParameterf(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_MIN_FILTER, GL10.GL_NEAREST);
gl.glTexParameterf(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_MAG_FILTER, GL10.GL_LINEAR);
GLUtils.texImage2D(GL10.GL_TEXTURE_2D, 0, bitmap, 0);
bitmap.recycle();
}
}
}
Since your plane is facing the Z axis, you actually need to rotate it on the Z axis, and not on the X.
So gl.glRotatef(30, 1, 0, 0) would be gl.glRotatef(30, 0, 0, 1)
Oh, and the translation values are actually -150 and 150, not -50 & 50. Since your plane is 100x100 and it "begins" in (100,100) so 150 would be the center of the plane.
But you should try not using that x and y variables. Then your vertices would become { 0,0,0, 0,100,0, 100,0,0, 100,100,0 }, it's in this case that you'd translate it by (-50, -50, 0) and then (50, 50, 0).
I have a very basic Activity at the moment. It creates a GLSurfaceView and sets the Renderer. The problem is all I see is red, which is from glClearColor, and no texture. Not even a white area. Also glGetError() is not reporting anything.
Here is the Renderer:
public class MyRenderer implements Renderer {
public MyRenderer(Context context)
{
mContext = context;
}
public void onDrawFrame(GL10 gl) {
gl.glClearColor(1.0f, 0.0f, 0.0f, 1.0f);
gl.glClear(GL10.GL_COLOR_BUFFER_BIT | GL10.GL_DEPTH_BUFFER_BIT);
gl.glEnableClientState(GL10.GL_VERTEX_ARRAY);
gl.glEnableClientState(GL10.GL_TEXTURE_COORD_ARRAY);
gl.glBindTexture(GL10.GL_TEXTURE_2D, texture[0]);
gl.glVertexPointer(2, GL10.GL_FLOAT, 0, vertex);
gl.glTexCoordPointer(2, GL10.GL_FLOAT, 0, texCoords);
gl.glDrawArrays(GL10.GL_TRIANGLE_STRIP, 0, 4);
gl.glDisableClientState(GL10.GL_VERTEX_ARRAY);
gl.glDisableClientState(GL10.GL_TEXTURE_COORD_ARRAY);
}
public void onSurfaceChanged(GL10 gl, int width, int height) {
gl.glViewport(0, 0, width, height);
gl.glMatrixMode(GL10.GL_PROJECTION);
gl.glLoadIdentity();
gl.glOrthof(-160.0f, 160.0f, -240.0f, 240.0f, 0.1f, 1.0f);
gl.glMatrixMode(GL10.GL_MODELVIEW);
gl.glLoadIdentity();
}
public void onSurfaceCreated(GL10 gl, EGLConfig config) {
float vertexBuffer[] = {
-160.0f, -240.0f,
-160.0f, 240.0f,
160.0f, -240.0f,
160.0f, 240.0f
};
vertex = ByteBuffer.allocateDirect(8 * 4).asFloatBuffer().put(vertexBuffer);
float texCoordsBuffer[] = {
0.0f, 0.0f,
0.0f, 480.0f/512.0f,
320.0f/512.0f, 0.0f,
320.0f/512.0f, 480.0f/512.0f
};
texCoords = ByteBuffer.allocateDirect(8 * 4).asFloatBuffer().put(texCoordsBuffer);
BitmapFactory.Options options = new BitmapFactory.Options();
options.inDensity = 240; // needed so that the image will be 512x512
Bitmap bitmap = BitmapFactory.decodeResource(mContext.getResources(), R.drawable.image, options);
int width = bitmap.getWidth();
int height = bitmap.getHeight();
Log.i(TAG, "Bitmap:{w:" + width + " h:" + height + "}");
gl.glEnable(GL10.GL_TEXTURE_2D);
texture = new int[1];
gl.glGenTextures(1, texture, 0);
gl.glBindTexture(GL10.GL_TEXTURE_2D, texture[0]);
gl.glTexParameterx(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_MIN_FILTER, GL10.GL_LINEAR);
gl.glTexParameterx(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_MAG_FILTER, GL10.GL_LINEAR);
GLUtils.texImage2D(GL10.GL_TEXTURE_2D, 0, bitmap, 0);
bitmap.recycle();
int error = gl.glGetError();
if (error != GL10.GL_NO_ERROR)
{
Log.e(TAG, "GL Texture Load Error: " + error);
}
}
private Context mContext;
private int texture[];
private FloatBuffer vertex;
private FloatBuffer texCoords;
}
There are several problems with your code:
You need to set the byte order of your buffers to native:
vertex.order(ByteOrder.nativeOrder())
After copying data into your buffers, reset the position to 0:
vertex.position(0)
(Do both for texCoord as well).
It would probably also help to put your near clipping plane at -1.0 instead of .1 (in glOrthof).
// needed because the image won't be 512x512
To have OpenGL render the texture, the texture size needs to be a power of 2, ie 64x64, 128x32 or 256x1024
I'm trying to render a 640x480 RGB565 image using OpenGL ES on Android using GLSurfaceView and Native C code.
Initially I had a 0x0501 error with glTexImage2D, which I was able to resolve by changing the image dimensions.
But now, in the "drawFrame" call, when I do glDrawTexiOES to resnder the texture, I'm getting the following error on the Logs:
drawtex.c:89: DrawTexture: No textures enabled
I'm already doing glEnable(GL_TEXTURE_2D), is there anything else I should do?
Is there a complete example showing GLSurfaceView with native code using textures?
Thanks in advance!
I have had the same problem,you can either make a custom renderer like this:
or (a do it little bit complicated by subclassing SurfaceView directly)
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import javax.microedition.khronos.egl.EGLConfig;
import javax.microedition.khronos.opengles.GL10;
import javax.microedition.khronos.opengles.GL11;
import javax.microedition.khronos.opengles.GL11Ext;
import android.app.Activity;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.opengl.GLSurfaceView;
import android.util.Log;
import com.TIEmulator.JNI.NLib;
class EmulatorRenderer implements GLSurfaceView.Renderer, NLib.EventsInterface {
public static interface RenderCb {
public boolean dismissStartupDialog();
public void updateStartupDialog(String msg);
}
private static int mViewHeight;
private static int mViewWidth;
private static BitmapFactory.Options sBitmapOptions = new BitmapFactory.Options();
private static int TEX_BUF_HEIGHT = 128;
private static int TEX_BUF_WIDTH = 256;
private final ByteBuffer byteBuffer = ByteBuffer.allocateDirect(4
* EmulatorRenderer.TEX_BUF_HEIGHT * EmulatorRenderer.TEX_BUF_WIDTH);
private boolean emulation_running = false;
private Context mContext = null;
private final int[] mCropWorkspace;
private final GLSurfaceView mGLView;
protected int mTex = -1;
protected int[] mtexBuf = new int[1];
private final int[] mTextureNameWorkspace;
public EmulatorRenderer(final Context ctx, final GLSurfaceView v) {
// Pre-allocate and store these objects so we can use them at runtime
// without allocating memory mid-frame.
mTextureNameWorkspace = new int[1];
mCropWorkspace = new int[4];
byteBuffer.order(ByteOrder.BIG_ENDIAN);
// Set our bitmaps to 16-bit, 565 format.
EmulatorRenderer.sBitmapOptions.inPreferredConfig = Bitmap.Config.RGB_565;
mGLView = v;
mContext = ctx;
try {
NLib.setListener(this);
} catch (final RuntimeException exc) {
exc.printStackTrace();
callFinishOnce();
return;
}
if (!NLib.TryLoadLib()) {
callFinishOnce();
return;
}
Log.v(this.getClass().toString(),">>>>>>>>>>>>>>>>>>>>>>> init successfull! <<<<<<<<<<<<<<<<<<<<<<");
}
private void callFinishOnce() {
if (mContext != null) {
((Activity) mContext).finish();
mContext = null;
}
}
#Override
protected void finalize() throws Throwable {
NLib.stopEmu();
super.finalize();
}
protected int loadBB(final GL10 gl) {
int textureName = -1;
if (mContext != null && gl != null) {
gl.glGenTextures(1, mTextureNameWorkspace, 0);
textureName = mTextureNameWorkspace[0];
gl.glBindTexture(GL10.GL_TEXTURE_2D, textureName);
gl.glTexParameterf(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_MIN_FILTER,
GL10.GL_NEAREST);
gl.glTexParameterf(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_MAG_FILTER,
GL10.GL_NEAREST);// GL10.GL_LINEAR);
gl.glTexParameterf(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_WRAP_S,
GL10.GL_CLAMP_TO_EDGE);
gl.glTexParameterf(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_WRAP_T,
GL10.GL_CLAMP_TO_EDGE);
gl.glTexEnvf(GL10.GL_TEXTURE_ENV, GL10.GL_TEXTURE_ENV_MODE,
GL10.GL_REPLACE);
mCropWorkspace[0] = 0; // u
// mCropWorkspace[1] = EMU_HEIGHT; // v
mCropWorkspace[1] = 0; // v
mCropWorkspace[2] = NLib.getWidth(); // w
// mCropWorkspace[3] = -EMU_HEIGHT; // h -EMU_HEIGHT;
mCropWorkspace[3] = NLib.getHeight(); // h -EMU_HEIGHT;
byteBuffer.order(ByteOrder.BIG_ENDIAN);
final int error = gl.glGetError();
if (error != GL10.GL_NO_ERROR) {
Log.e("SpriteMethodTest", "Texture Load GLError: " + error);
}
}
return textureName;
}
public void onDrawFrame(final GL10 gl) {
// Log.v(this.toString(),"onDrawFrame called");
gl.glActiveTexture(mTex);
gl.glClientActiveTexture(mTex);
byteBuffer.position(0);
// this two lines bind and create the texture!
gl.glBindTexture(GL10.GL_TEXTURE_2D, mTex);
((GL11) gl).glTexParameteriv(GL10.GL_TEXTURE_2D,
GL11Ext.GL_TEXTURE_CROP_RECT_OES, mCropWorkspace, 0);
gl.glTexImage2D(GL10.GL_TEXTURE_2D, 0, GL10.GL_RGBA,
EmulatorRenderer.TEX_BUF_WIDTH,
EmulatorRenderer.TEX_BUF_HEIGHT, 0, GL10.GL_RGBA,
GL10.GL_UNSIGNED_BYTE, byteBuffer);
((GL11Ext) gl).glDrawTexiOES(0, 0, 0, EmulatorRenderer.mViewWidth,
EmulatorRenderer.mViewHeight);
/** gl.glEnable(GL10.GL_DEPTH_TEST); gl.glDepthFunc(GL10.GL_LEQUAL);
*/
}
public void OnFatalError(final String text) {
Log.d(toString(), "FATAL ERROR CALLBACK raised: " + text
+ " ===> Activity calls finish()");
}
public void onFinish() {
onPause();
}
/*
* JNI interface
*
*/
#Override
public void OnBufferUpdate() {
mGLView.requestRender();
}
// TODO Auto-generated method stub
#Override
public void OnWarning(String msg) {
// TODO Auto-generated method stub
}
public void onPause() {
mGLView.onPause();
// Log.v("onPause", "NILib.stopEmulate()");
emulation_running = false;
//startupDialogDismiss = false;
NLib.stopEmu();
}
public void onResume() {
// Log.v(this.toString(),"EmulatorRenderer:onResume called");
NLib.startEmu(byteBuffer);
mGLView.onResume();
//callFinishOnce();
emulation_running = true;
}
public void onSurfaceChanged(final GL10 gl, final int w, final int h) {
EmulatorRenderer.mViewWidth = w;
EmulatorRenderer.mViewHeight = h;
Log.v(toString(), "onSurfaceChanged: ==> New View Size: [" + w + ","
+ h + "]");
}
public void onSurfaceCreated(final GL10 gl, final EGLConfig config) {
gl.glHint(GL10.GL_PERSPECTIVE_CORRECTION_HINT, GL10.GL_FASTEST);
gl.glClearColor(0.5f, 0.5f, 0.5f, 1);
gl.glShadeModel(GL10.GL_FLAT);
gl.glDisable(GL10.GL_DEPTH_TEST);
gl.glEnable(GL10.GL_TEXTURE_2D);
/*
* By default, OpenGL enables features that improve quality but reduce
* performance. One might want to tweak that especially on software
* renderer.
*/
gl.glDisable(GL10.GL_DITHER);
gl.glDisable(GL10.GL_LIGHTING);
gl.glDisable(GL10.GL_BLEND);
gl.glDisable(GL10.GL_DEPTH_TEST);
gl.glHint(GL10.GL_LINE_SMOOTH_HINT, GL10.GL_NICEST); // Set Line
// Antialiasing
gl.glClear(GL10.GL_COLOR_BUFFER_BIT | GL10.GL_DEPTH_BUFFER_BIT);
// create the one and only texture here...
mTex = loadBB(gl);
}
public void OnTIEmuStopped() {
System.out.println("OnTIEmuStopped callback called! ");
callFinishOnce();
}
/* Called when the size of the window changes. */
public void sizeChanged(final GL10 gl, final int w, final int h) {
// Log.v(this.toString(),"sizeChanged: ==> new Viewport: ["+w+","+h+"]");
gl.glViewport(0, 0, w, h);
/*
* Set our projection matrix. This doesn't have to be done each time we
* draw, but usually a new projection needs to be set when the viewport
* is resized.
*/
gl.glMatrixMode(GL10.GL_PROJECTION);
gl.glLoadIdentity();
// Set up the orthographic projection
// gl.glOrthof(0.0f, w, 0.0f, h, 0.0f, 1.0f);
gl.glOrthof(0.0f, w, 0.0f, 0.0f, h, 1.0f);
gl.glBlendFunc(GL10.GL_SRC_ALPHA, GL10.GL_ONE_MINUS_SRC_ALPHA);
gl.glColor4x(0x10000, 0x10000, 0x10000, 0x10000);
gl.glEnable(GL10.GL_TEXTURE_2D);
gl.glMatrixMode(GL10.GL_MODELVIEW);
}
}
yes i did...
gl.glGenTextures(1, mTextureNameWorkspace, 0);
textureName = mTextureNameWorkspace[0];
gl.glBindTexture(GL10.GL_TEXTURE_2D, textureName);
gl.glTexParameterf(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_MIN_FILTER,
GL10.GL_NEAREST);
gl.glTexParameterf(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_MAG_FILTER,
GL10.GL_NEAREST);// GL10.GL_LINEAR);
gl.glTexParameterf(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_WRAP_S,
GL10.GL_CLAMP_TO_EDGE);
gl.glTexParameterf(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_WRAP_T,
GL10.GL_CLAMP_TO_EDGE);
gl.glTexEnvf(GL10.GL_TEXTURE_ENV, GL10.GL_TEXTURE_ENV_MODE,
GL10.GL_REPLACE);
mCropWorkspace[0] = 0; // u
// mCropWorkspace[1] = EMU_HEIGHT; // v
mCropWorkspace[1] = 0; // v
mCropWorkspace[2] = NLib.getWidth(); // w
// mCropWorkspace[3] = -EMU_HEIGHT; // h -EMU_HEIGHT;
mCropWorkspace[3] = NLib.getHeight(); // h -EMU_HEIGHT;
static_test_debug_if_gl_error( gl , "loadBB time 1");
gl.glActiveTexture(mTex);
gl.glClientActiveTexture(mTex);
static_test_debug_if_gl_error( gl , "loadBB time 2");
Did you generate a texture id and bind a texture first?
glGenTexture()/glBindTexture()
The following will get the texture all set up and ready to use on GL_TEXTURE0:
When loading the texture:
// in your native onSurfaceCreated function:
glEnable(GL_TEXTURE_2D);
glGenTextures(1, &texID);
glBindTexture(GL_TEXTURE_2D, texID);
// setup texture parameters if you want:
glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); // etc.
glTexImage2D(GL_TEXTURE_2D, ... );
see here for how to fill out the TexImage2D parameters.
I've unfortunately not been able to get the glDrawTex_OES functions to work properly, but the texture does work if you render it onto a quad:
// in your native onRender function:
glBindTexture(GL_TEXTURE_2D, sGlTexture.texID);
// quad drawing:
glEnableClientState(GL_VERTEX_ARRAY);
glEnableClientState(GL_TEXTURE_COORD_ARRAY);
glVertexPointer(3, GL_FLOAT, 0, quadVerts[i]);
glTexCoordPointer(2, GL_FLOAT, 0, quadTexCoords[i]);
glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
glDisableClientState(GL_VERTEX_ARRAY);
glDisableClientState(GL_TEXTURE_COORD_ARRAY);