I'm trying to do some pixel work in a texture old school by accessing it using an array. My approach is to generate a texture, then use that texture each successive frame write and modify my texture as necessary. However, when I run this code in the Android Emulator, all I get is a white image. My texture size is a power of two, so I was a bit surprised. If anything, I would have expected to see a completely black image. Here is my custom renderer code:
package com.gltest;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.nio.FloatBuffer;
import java.nio.IntBuffer;
import java.nio.ShortBuffer;
import javax.microedition.khronos.egl.EGLConfig;
import javax.microedition.khronos.opengles.GL10;
import android.opengl.GLU;
import android.opengl.GLSurfaceView.Renderer;
public class OpenGLRenderer implements Renderer {
private ByteBuffer buf;
private int cwidth, cheight;
private FloatBuffer vertexBuffer, texelBuffer;
private ShortBuffer indexBuffer;
int[] textures = new int[1];
float vertices[] = {
0.0f, 1.0f, 0.0f,
0.0f, 0.0f, 0.0f,
1.0f, 0.0f, 0.0f,
1.0f, 1.0f, 0.0f
};
private float texels[] = {
0.0f, 1.0f,
0.0f, 0.0f,
1.0f, 0.0f,
1.0f, 1.0f
};
private short[] indices = { 0, 1, 2, 0, 2, 3 };
#Override
public void onDrawFrame(GL10 gl) {
gl.glClear(GL10.GL_COLOR_BUFFER_BIT | GL10.GL_DEPTH_BUFFER_BIT);
updateTexture(gl);
}
#Override
public void onSurfaceChanged(GL10 gl, int width, int height) {
gl.glViewport(0, 0, width, height);
gl.glMatrixMode(GL10.GL_PROJECTION);
gl.glLoadIdentity();
GLU.gluOrtho2D(gl, 0, width, 0, height);
gl.glMatrixMode(GL10.GL_MODELVIEW);
gl.glLoadIdentity();
buf = ByteBuffer.allocateDirect(128 * 128 * 3).order(ByteOrder.nativeOrder());
cwidth = width;
cheight= height;;
for( int i=0; i<vertices.length; i+=3 ) {
vertices[i] *= cwidth;
vertices[i+1] *= cheight;
}
gl.glEnable(GL10.GL_TEXTURE_2D);
gl.glGenTextures(1, textures, 0);
gl.glBindTexture(GL10.GL_TEXTURE_2D, textures[0]);
gl.glTexParameterf(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_MAG_FILTER, GL10.GL_NEAREST);
gl.glTexParameterf(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_MIN_FILTER, GL10.GL_NEAREST);
gl.glTexImage2D(GL10.GL_TEXTURE_2D, 0, 3, 128, 128, 0, GL10.GL_RGB, GL10.GL_UNSIGNED_BYTE, buf);
ByteBuffer vbb = ByteBuffer.allocateDirect(vertices.length * 4);
vbb.order(ByteOrder.nativeOrder());
vertexBuffer = vbb.asFloatBuffer();
vertexBuffer.put(vertices);
vertexBuffer.position(0);
ByteBuffer tbb = ByteBuffer.allocateDirect(texels.length * 4);
tbb.order(ByteOrder.nativeOrder());
texelBuffer = tbb.asFloatBuffer();
texelBuffer.put(texels);
texelBuffer.position(0);
ByteBuffer ibb = ByteBuffer.allocateDirect(indices.length * 2);
ibb.order(ByteOrder.nativeOrder());
indexBuffer = ibb.asShortBuffer();
indexBuffer.put(indices);
indexBuffer.position(0);
}
#Override
public void onSurfaceCreated(GL10 gl, EGLConfig config) {
gl.glClearColor(1.0f, 0.0f, 0.0f, 0.5f);
gl.glShadeModel(GL10.GL_SMOOTH);
gl.glClearDepthf(1.0f);
gl.glEnable(GL10.GL_DEPTH_TEST);
gl.glDepthFunc(GL10.GL_LEQUAL);
gl.glHint(GL10.GL_PERSPECTIVE_CORRECTION_HINT, GL10.GL_NICEST);
}
void updateTexture(GL10 gl)
{
// Update pixels
// write random r g or b values to random locations
for(int y = 0; y < 128; ++y)
for(int x = 0; x < 128; ++x)
buf.put(x+y*128, (byte)(Math.random()*255));
buf.position(0);
gl.glEnable(GL10.GL_TEXTURE_2D);
gl.glBindTexture(gl.GL_TEXTURE_2D, textures[0]);
gl.glEnableClientState(GL10.GL_VERTEX_ARRAY);
gl.glVertexPointer(3, GL10.GL_FLOAT, 0, vertexBuffer);
gl.glTexSubImage2D(GL10.GL_TEXTURE_2D, 0, 0, 0, 128, 128, GL10.GL_RGB, GL10.GL_UNSIGNED_BYTE, buf);
gl.glEnableClientState(GL10.GL_TEXTURE_COORD_ARRAY);
gl.glTexCoordPointer(2, GL10.GL_FLOAT, 0, texelBuffer);
gl.glBindTexture(GL10.GL_TEXTURE_2D, textures[0]);
gl.glDrawElements(GL10.GL_TRIANGLES, indices.length, GL10.GL_UNSIGNED_SHORT, indexBuffer);
gl.glDisableClientState(GL10.GL_VERTEX_ARRAY);
gl.glDisableClientState(GL10.GL_TEXTURE_COORD_ARRAY);
}
}
Honestly I do not believe it is a very convenient solution performance wise.
This kind of alteration/effects should be done in a programmable pipeline model such as OPENGL ES 2.0 using vertex and fragment shaders.
The solution you are trying to achieve is not convenient for the following reasons:
The load is entirely on the CPU and you are not using the power of the GPU at all
Texture data manipulation functions are well known to be a performance killer for nowadays GPUs
I strongly suggest you to implement the effects possibly in a fragment shader to have the best performances possible.
After some poking around, I've discovered that gl.glTexSubImage2D is not supported in GLES 1.1 on Android (it's built in but it doesn't do anything: https://www.google.com/search?ix=hea&sourceid=chrome&ie=UTF-8&q=android+opengl+glTexSubImage2D)
Also, so no one else wastes their time in the future, forget about trying to use glDrawPixels to send to the framebuffer. That isn't support either, in any GLES 1.1 / 2.0 implementation (Android, iPhone) etc.
The solution is to use the NDK as outlined in this excellent article by some coder named "Richard Quirk" who has his own blog: http://quirkygba.blogspot.com/2010/10/android-native-coding-in-c.html and, as it happens, also is a Stack Overflow regular: https://stackoverflow.com/users/4596/richq
Thanks Richard!
Related
I'm building an Android app with OpenGL.I created 2 squares, each with their own textures(PNG), and overlayed them. From hints i got from a previous question, i used gl.glBlendFunc(GL10.GL_SRC_ALPHA, GL10.GL_ONE_MINUS_SRC_ALPHA);
My problem is that the transparency effect, affects the second square, therefor i can see the background through the second square's texture.Is there a way arround this?
Here is the Renderer and at the Bottom the Square.java class :
package hello.project;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.nio.FloatBuffer;
import javax.microedition.khronos.opengles.GL10;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.opengl.GLUtils;
public class Square {
private FloatBuffer vertexBuffer; // buffer holding the vertices
static int sex=R.drawable.girl;
private FloatBuffer textureBuffer; // buffer holding the texture coordinates
private float texture[] = {
// Mapping coordinates for the vertices
0.0f, 1.0f, // top left (V2)
0.0f, 0.0f, // bottom left (V1)
1.0f, 1.0f, // top right (V4)
1.0f, 0.0f // bottom right (V3)
};
private float vertices[] = {
-1.0f, -2.0f, 0.0f, // V1 - bottom left
-1.0f, 2.0f, 0.0f, // V2 - top left
0.8f, -2.0f, 0.0f, // V3 - bottom right
0.8f, 2.0f, 0.0f // V4 - top right
};
public Square() {
ByteBuffer byteBuffer = ByteBuffer.allocateDirect(vertices.length * 4);
byteBuffer.order(ByteOrder.nativeOrder());
vertexBuffer = byteBuffer.asFloatBuffer();
vertexBuffer.put(vertices);
vertexBuffer.position(0);
byteBuffer = ByteBuffer.allocateDirect(texture.length * 4);
byteBuffer.order(ByteOrder.nativeOrder());
textureBuffer = byteBuffer.asFloatBuffer();
textureBuffer.put(texture);
textureBuffer.position(0);
}
/** The draw method for the square with the GL context */
public void draw(GL10 gl) {
// bind the previously generated texture
gl.glBindTexture(GL10.GL_TEXTURE_2D, textures[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, vertices.length / 3);
//Disable the client state before leaving
gl.glDisableClientState(GL10.GL_VERTEX_ARRAY);
gl.glDisableClientState(GL10.GL_TEXTURE_COORD_ARRAY);
}
/** The texture pointer */
private int[] textures = new int[1];
public void loadGLTexture(GL10 gl, Context context,int sex ) {
// loading texture
Bitmap bitmap = BitmapFactory.decodeResource(context.getResources(),
sex);
// 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);
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 static int getSex() {
return sex;
}
public static void setSex(int sex) {
Square.sex = sex;
}
}
---------------------------------------------------------------------------
package hello.project;
import javax.microedition.khronos.egl.EGLConfig;
import javax.microedition.khronos.opengles.GL10;
import android.content.Context;
import android.opengl.GLSurfaceView.Renderer;
import android.opengl.GLU;
public class HelloOpenGLES10Renderer implements Renderer {
private Square square; // the square
private Square2 square2; // the square
private Context context;
/** Constructor to set the handed over context */
public HelloOpenGLES10Renderer(Context context) {
this.square = new Square();
this.square2 = new Square2();
this.context=context;
}
public void onDrawFrame(GL10 gl) {
// clear Screen and Depth Buffer
gl.glClear(GL10.GL_COLOR_BUFFER_BIT | GL10.GL_DEPTH_BUFFER_BIT);
// Reset the Modelview Matrix
gl.glLoadIdentity();
// Drawing
gl.glTranslatef(0.0f, 0.0f, -5.0f); // move 5 units INTO the screen
square.draw(gl);
square2.draw(gl);
}
public void onSurfaceChanged(GL10 gl, int width, int height) {
if(height == 0) { //Prevent A Divide By Zero By
height = 1; //Making Height Equal One
}
gl.glViewport(0, 0, width, height); //Reset The Current Viewport
gl.glMatrixMode(GL10.GL_PROJECTION); //Select The Projection Matrix
gl.glLoadIdentity(); //Reset The Projection Matrix
//Calculate The Aspect Ratio Of The Window
GLU.gluPerspective(gl, 45.0f, (float)width / (float)height, 0.1f, 100.0f);
gl.glMatrixMode(GL10.GL_MODELVIEW); //Select The Modelview Matrix
gl.glLoadIdentity(); //Reset The Modelview Matrix
}
public void onSurfaceCreated(GL10 gl, EGLConfig config) {
// Load the texture for the square
square.loadGLTexture(gl, this.context,Square.getSex());
square2.loadGLTexture(gl, this.context,Square2.getSex());
gl.glEnable(GL10.GL_TEXTURE_2D);
gl.glDisable(GL10.GL_DEPTH_TEST);
gl.glEnable(GL10.GL_BLEND);
gl.glBlendFunc(GL10.GL_SRC_ALPHA, GL10.GL_ONE_MINUS_SRC_ALPHA);
gl.glShadeModel(GL10.GL_SMOOTH); //Enable Smooth Shading
gl.glClearColor(0.0f, 0.0f, 0.0f, 0.0f); //Black Background
gl.glClearDepthf(1.0f); //Depth Buffer Setup
gl.glDepthFunc(GL10.GL_NEVER); //The Type Of Depth Testing To Do
//Really Nice Perspective Calculations
gl.glHint(GL10.GL_PERSPECTIVE_CORRECTION_HINT, GL10.GL_NICEST);
}
}
Don't you just have a problem with the graphics pipeline state? Remember whichever square you tell to get drawn first gets drawn using the blend function that's currently active (and this will remain active until you change the OpenGL state). Maybe you want to add some more state changes to the blend function, or change the order of drawing to get the effect you want? You might want to also try enabling/disabling the depth test between drawing calls to make a square opaque.
Hope this helps a bit, you might need to provide a bit more detail to your question.
I have an GlSurfaceView that is drawing a square that i am trying to texturize with a image.png I have played with two different png files both in the same drawable folder.. When i reference one it loads just fine but if i switch the R.image.png to the other, my sqaure just turns white.. can anyone help? below is my square class, and my glView.
Square:
package com.eliddell.AR;
import java.io.InputStream;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.nio.FloatBuffer;
import javax.microedition.khronos.opengles.GL10;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.opengl.GLUtils;
public class Square {
private FloatBuffer vertexBuffer; // buffer holding the vertices
private float vertices[] = {
-1.0f, -1.0f, 0.0f, // V1 - bottom left
-1.0f, 1.0f, 0.0f, // V2 - top left
1.0f, -1.0f, 0.0f, // V3 - bottom right
1.0f, 1.0f, 0.0f // V4 - top right
};
private FloatBuffer textureBuffer; // buffer holding the texture coordinates
private float texture[] = {
// Mapping coordinates for the vertices
0.0f, 1.0f, // top left (V2)
0.0f, 0.0f, // bottom left (V1)
1.0f, 1.0f, // top right (V4)
1.0f, 0.0f // bottom right (V3)
};
public Square() {
ByteBuffer byteBuffer = ByteBuffer.allocateDirect(vertices.length * 4);
byteBuffer.order(ByteOrder.nativeOrder());
vertexBuffer = byteBuffer.asFloatBuffer();
vertexBuffer.put(vertices);
vertexBuffer.position(0);
byteBuffer = ByteBuffer.allocateDirect(texture.length * 4);
byteBuffer.order(ByteOrder.nativeOrder());
textureBuffer = byteBuffer.asFloatBuffer();
textureBuffer.put(texture);
textureBuffer.position(0);
}
/** The texture pointer */
private int[] textures = new int[1];
public void loadGLTexture(GL10 gl, Context context) {
// loading texture
InputStream is = context.getResources().openRawResource(R.drawable.android);
Bitmap bitmap = BitmapFactory.decodeStream(is);
//Bitmap bitmap = BitmapFactory.decodeResource(context.getResources(),R.drawable.android);
// 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);
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) {
// bind the previously generated texture
gl.glBindTexture(GL10.GL_TEXTURE_2D, textures[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, vertices.length / 3);
//Disable the client state before leaving
gl.glDisableClientState(GL10.GL_VERTEX_ARRAY);
gl.glDisableClientState(GL10.GL_TEXTURE_COORD_ARRAY);
}
}
and my GLSurfaceView and Render:
package com.eliddell.AR;
import javax.microedition.khronos.egl.EGLConfig;
import javax.microedition.khronos.opengles.GL10;
import android.opengl.GLU;
import android.content.Context;
import android.graphics.PixelFormat;
import android.hardware.Camera;
import android.opengl.GLSurfaceView;
import android.opengl.GLSurfaceView.Renderer;
import android.view.SurfaceHolder;
public class GLLayer extends GLSurfaceView implements SurfaceHolder.Callback, Camera.PreviewCallback, Renderer {
private Context context;
private Square square; // the triangle to be drawn
public GLLayer(Context context) {
super(context);
this.context = context;
this.square = new Square();
// settings for translucent glView
this.setEGLConfigChooser(8, 8, 8, 8, 16, 0);
this.getHolder().setFormat(PixelFormat.TRANSLUCENT);
// set render to inline
this.setRenderer(this);
}
#Override
public void onDrawFrame(GL10 gl) {
// clear Screen and Depth Buffer
gl.glClear(GL10.GL_COLOR_BUFFER_BIT | GL10.GL_DEPTH_BUFFER_BIT);
// Reset the Modelview Matrix
gl.glLoadIdentity();
// Drawing
gl.glTranslatef(0.0f, 0.0f, -5.0f); // move 5 units INTO the screen
// is the same as moving the camera 5 units away
square.draw(gl); // Draw the triangle
}
#Override
public void onSurfaceChanged(GL10 gl, int width, int height) {
if(height == 0) { //Prevent A Divide By Zero By
height = 1; //Making Height Equal One
}
gl.glViewport(0, 0, width, height); //Reset The Current Viewport
gl.glMatrixMode(GL10.GL_PROJECTION); //Select The Projection Matrix
gl.glLoadIdentity(); //Reset The Projection Matrix
//Calculate The Aspect Ratio Of The Window
GLU.gluPerspective(gl, 45.0f, (float)width / (float)height, 0.1f, 100.0f);
gl.glMatrixMode(GL10.GL_MODELVIEW); //Select The Modelview Matrix
gl.glLoadIdentity(); //Reset The Modelview Matrix
}
#Override
public void onSurfaceCreated(GL10 gl, EGLConfig arg1) {
// Load the texture for the square
square.loadGLTexture(gl, this.context);
gl.glEnable(GL10.GL_TEXTURE_2D); //Enable Texture Mapping ( NEW )
gl.glShadeModel(GL10.GL_SMOOTH); //Enable Smooth Shading
gl.glClearColor(0.0f, 0.0f, 0.0f, 0.0f); //Black Background
gl.glClearDepthf(1.0f); //Depth Buffer Setup
gl.glEnable(GL10.GL_DEPTH_TEST); //Enables Depth Testing
gl.glDepthFunc(GL10.GL_LEQUAL); //The Type Of Depth Testing To Do
//Really Nice Perspective Calculations
gl.glHint(GL10.GL_PERSPECTIVE_CORRECTION_HINT, GL10.GL_NICEST);
}
#Override
public void onPreviewFrame(byte[] data, Camera camera) {
// TODO Auto-generated method stub
}
}
Propably your texture dosent have power of two dimensions.
Opengl can load only textures witch have pot(power of two) size like: 32X32 , 64X64 , 128X128 ..... and not 36X36 , 48X48 ....
Change your image size.
I found out on a few phones some of my textures in my glSurfaceView arent loading (just showing white) after some googling, I set setDebugFlags(DEBUG_CHECK_ERROR) to get the following error log listed below. line 40 in MenuButton.java is:
gl.glGenTextures(1, textures, 0);
where textures is my texture pointer, declared as:
private int[] textures = new int[1];
Im stumped, as ive only seen this problem with the Droid Pro and a couple other phones and im not sure how gl.glGenTextures would have an invalid value. Any thoughts would be useful.
EDIT: the code for menu button is posted below.
12-06 17:46:31.720: E/AndroidRuntime(2984): android.opengl.GLException: invalid value
12-06 17:46:31.720: E/AndroidRuntime(2984): at android.opengl.GLErrorWrapper.glGenTextures(GLErrorWrapper.java:350)
12-06 17:46:31.720: E/AndroidRuntime(2984): at com.huskybuspurchased.MenuButton.<init>(MenuButton.java:40)
12-06 17:46:31.720: E/AndroidRuntime(2984): at com.huskybuspurchased.CampusMap.onSurfaceCreated(CampusMap.java:112)
12-06 17:46:31.720: E/AndroidRuntime(2984): at android.opengl.GLSurfaceView$GLThread.guardedRun(GLSurfaceView.java:1348)
12-06 17:46:31.720: E/AndroidRuntime(2984): at android.opengl.GLSurfaceView$GLThread.run(GLSurfaceView.java:1118)
12-06 17:46:31.728: I/hb(2984): rendering thread paused.
A pic of the issue:
package com.huskybus;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.nio.FloatBuffer;
import javax.microedition.khronos.opengles.GL10;
import android.graphics.Bitmap;
import android.opengl.GLUtils;
import android.util.Log;
import android.view.MotionEvent;
public class MenuButton {
//Our texture.
private float texture[] = {
//Mapping coordinates for the vertices
0.0f, 1.0f,
1.0f, 1.0f,
0.0f, 0.0f,
1.0f, 0.0f,
};
// The order we like to connect them.
private byte indices[] = {0,1,3,2};
// Our vertex buffer.
private FloatBuffer vertexBuffer;
// Our index buffer.
private ByteBuffer indexBuffer;
//texture buffer.
private FloatBuffer textureBuffer;
//Our texture pointer.
private int[] textures = new int[1];
private int width;
private int height;
private float rotation;
public MenuButton(Bitmap graphic,int _rotation,GL10 gl, int _width, int _height) {
rotation=_rotation;
width=_width;
height=_height;
//Generate one texture pointer...
gl.glGenTextures(1, textures, 0);
//...and bind it to our array
gl.glBindTexture(GL10.GL_TEXTURE_2D, textures[0]);
gl.glTexParameterf(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_MIN_FILTER, GL10.GL_LINEAR);
gl.glTexParameterf(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_MAG_FILTER, 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);
//Use the Android GLUtils to specify a two-dimensional texture image from our bitmap
GLUtils.texImage2D(GL10.GL_TEXTURE_2D, 0, graphic, 0);
graphic.recycle();
float vertices[] = {
0, -height, 0.0f, //LB
width, -height, 0.0f, //RB
0, 0, 0.0f, //LT
width, 0, 0.0f, //RT
};
ByteBuffer byteBuf = ByteBuffer.allocateDirect(vertices.length * 4);
byteBuf.order(ByteOrder.nativeOrder());
vertexBuffer = byteBuf.asFloatBuffer();
vertexBuffer.put(vertices);
vertexBuffer.position(0);
//
byteBuf = ByteBuffer.allocateDirect(texture.length * 4);
byteBuf.order(ByteOrder.nativeOrder());
textureBuffer = byteBuf.asFloatBuffer();
textureBuffer.put(texture);
textureBuffer.position(0);
//
indexBuffer = ByteBuffer.allocateDirect(indices.length);
indexBuffer.put(indices);
indexBuffer.position(0);
}
/**
* This function draws our square on screen.
* #param gl
*/
public void draw(GL10 gl) {
//Bind our only previously generated texture in this case
gl.glBindTexture(GL10.GL_TEXTURE_2D, textures[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_CCW);
//Enable the vertex and texture state
gl.glVertexPointer(3, GL10.GL_FLOAT, 0, vertexBuffer);
gl.glTexCoordPointer(2, GL10.GL_FLOAT, 0, textureBuffer);
gl.glRotatef(rotation, 0, 0, 1);
//Draw the vertices as triangles, based on the Index Buffer information
gl.glDrawElements(GL10.GL_TRIANGLE_FAN, indices.length, GL10.GL_UNSIGNED_BYTE, indexBuffer);
gl.glRotatef(360-rotation, 0, 0, 1);
// Disable the vertices buffer.
gl.glDisableClientState(GL10.GL_VERTEX_ARRAY);
//Disable the texture buffer.
gl.glDisableClientState(GL10.GL_TEXTURE_COORD_ARRAY);
// Disable face culling.
gl.glEnable(GL10.GL_CULL_FACE);
}
public boolean amIHit(float[] matrixValues,MotionEvent event) {
if (((event.getX())>(0)&&((event.getX()))<5+width)&&((event.getY())>0)&&(event.getY()<width)) {
Log.e("sys","hit menu button.");
return true;
}
return false;
}
}
glSurfaceView chooses a surface to render, and different android devices support different surfaces and unfortunately we dont have a common sub set that is supported by all. so it makes it tricky to choose.
By default glSurfaceView tries to find a surface which is close to 16 bit depth buffer.
So u need to use an image for ur Texture purpose which has 16 bit depth buffer or possibly 24 bit. Higher bit depth images may cause problems in certain devices.!!
You don't necessarily need to call glGenTextures. You can give your textures whatever numeric value you want--glGenTextures was just meant to be a convenience for getting a texture number that wasn't used yet.
Hi I am new in Android and OpenGLES development. I am trying to develop a simple Android game using OpenGL. The background image of my game is a tiling where I want to use the texture mapping wrap as GL_REPEAT. It is working fine in my Samsung Galaxy S and with the emulator for the platform 3.0. The problem is with my Samsung 10.1 Galaxy Tab where I cant get it to repeat the texture. It is always using the texture clamp to edge. I have found a texturing tutorial and when I modify the texture mapping and wrap parameters for this tutorial the texture is repeated as expected so I know that it is not a tablet bug in the tablet. The question is what is wrong in my code that is only being a problem for the tablet?
I am doing all texture setup in my a class that implements GLSurfaceView.Renderer. Is this a problem?
package com.droidev.games.bubbilliards;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.nio.FloatBuffer;
import java.nio.ShortBuffer;
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.GLSurfaceView;
import android.opengl.GLUtils;
import android.util.Log;
public class BBGLRenderer implements GLSurfaceView.Renderer {
private BBGame game;
private int width;
private int height;
private float ratio_w_h;
private ShortBuffer indicesBuffer;
private FloatBuffer vertexBuffer;
private FloatBuffer textureBuffer;
private FloatBuffer backgroundVertexBuffer;
private FloatBuffer backgroundTextureBuffer;
private Context context;
private BBGLSurfaceView glSurfaceView;
private int ball_textures[];
private int hole_open_textures[];
private int hole_closed_textures[];
private int background_textures[];
private float length;
private boolean texture_set;
private Bitmap green_ball;
private Bitmap orange_ball;
private Bitmap purple_ball;
private Bitmap green_hole_open;
private Bitmap orange_hole_open;
private Bitmap purple_hole_open;
private Bitmap green_hole_closed;
private Bitmap orange_hole_closed;
private Bitmap purple_hole_closed;
private Bitmap background;
public BBGLRenderer(Context context_, BBGLSurfaceView sv){
super();
context = context_;
glSurfaceView = sv;
game = new BBGame(sv);
texture_set = false;
}
public void onSurfaceCreated(GL10 gl, EGLConfig config){
gl.glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
gl.glEnable(GL10.GL_BLEND);
gl.glDisable(GL10.GL_DEPTH_TEST);
gl.glBlendFunc(GL10.GL_ONE, GL10.GL_ONE_MINUS_SRC_ALPHA);
gl.glEnable(GL10.GL_TEXTURE_2D);
// reading images from resources
green_ball = BitmapFactory.decodeResource(context.getResources(), R.drawable.green_ball);
orange_ball = BitmapFactory.decodeResource(context.getResources(), R.drawable.orange_ball);
purple_ball = BitmapFactory.decodeResource(context.getResources(), R.drawable.purple_ball);
green_hole_open = BitmapFactory.decodeResource(context.getResources(), R.drawable.green_hole_open);
orange_hole_open = BitmapFactory.decodeResource(context.getResources(), R.drawable.orange_hole_open);
purple_hole_open = BitmapFactory.decodeResource(context.getResources(), R.drawable.purple_hole_open);
green_hole_closed = BitmapFactory.decodeResource(context.getResources(), R.drawable.green_hole_closed);
orange_hole_closed = BitmapFactory.decodeResource(context.getResources(), R.drawable.orange_hole_closed);
purple_hole_closed = BitmapFactory.decodeResource(context.getResources(), R.drawable.purple_hole_closed);
background = BitmapFactory.decodeResource(context.getResources(), R.drawable.tile);
// creating textures IDS
int num_colors = BBColor.values().length;
ball_textures = new int[num_colors];
hole_open_textures = new int[num_colors];
hole_closed_textures = new int[num_colors];
background_textures = new int[1];
gl.glGenTextures(num_colors, ball_textures , 0);
// balls
initializeTexture(gl, green_ball , ball_textures, (int)BBColor.GREEN.ordinal());
initializeTexture(gl, orange_ball, ball_textures, (int)BBColor.ORANGE.ordinal());
initializeTexture(gl, purple_ball, ball_textures, (int)BBColor.PURPLE.ordinal());
gl.glGenTextures(num_colors, hole_open_textures , 0);
// holes open
initializeTexture(gl, green_hole_open , hole_open_textures, (int)BBColor.GREEN.ordinal());
initializeTexture(gl, orange_hole_open, hole_open_textures, (int)BBColor.ORANGE.ordinal());
initializeTexture(gl, purple_hole_open, hole_open_textures, (int)BBColor.PURPLE.ordinal());
gl.glGenTextures(num_colors, hole_closed_textures, 0);
// holes closed
initializeTexture(gl, green_hole_closed, hole_closed_textures, (int)BBColor.GREEN.ordinal());
initializeTexture(gl, orange_hole_closed, hole_closed_textures, (int)BBColor.ORANGE.ordinal());
initializeTexture(gl, purple_hole_closed, hole_closed_textures, (int)BBColor.PURPLE.ordinal());
gl.glGenTextures(1 , background_textures , 0);
initializeTexture(gl, background, background_textures, 0);
// initializeBuffers();
}
public void initializeTextures(GL10 gl){
int num_colors = BBColor.values().length;
gl.glGenTextures(num_colors, ball_textures , 0);
gl.glGenTextures(num_colors, hole_open_textures , 0);
gl.glGenTextures(num_colors, hole_closed_textures, 0);
gl.glGenTextures(1 , background_textures , 0);
// balls
initializeTexture(gl, green_ball , ball_textures, (int)BBColor.GREEN.ordinal());
initializeTexture(gl, orange_ball, ball_textures, (int)BBColor.ORANGE.ordinal());
initializeTexture(gl, purple_ball, ball_textures, (int)BBColor.PURPLE.ordinal());
// holes open
initializeTexture(gl, green_hole_open , hole_open_textures, (int)BBColor.GREEN.ordinal());
initializeTexture(gl, orange_hole_open, hole_open_textures, (int)BBColor.ORANGE.ordinal());
initializeTexture(gl, purple_hole_open, hole_open_textures, (int)BBColor.PURPLE.ordinal());
// holes closed
initializeTexture(gl, green_hole_closed, hole_closed_textures, (int)BBColor.GREEN.ordinal());
initializeTexture(gl, orange_hole_closed, hole_closed_textures, (int)BBColor.ORANGE.ordinal());
initializeTexture(gl, purple_hole_closed, hole_closed_textures, (int)BBColor.PURPLE.ordinal());
initializeTexture(gl, background, background_textures, 0);
texture_set = true;
}
public void initializeTexture(GL10 gl, Bitmap bmp, int textures[], int color){
gl.glBindTexture(GL10.GL_TEXTURE_2D, textures[color]);
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.glTexParameterf(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_WRAP_S, GL10.GL_REPEAT);
gl.glTexParameterf(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_WRAP_T, GL10.GL_REPEAT);
GLUtils.texImage2D(GL10.GL_TEXTURE_2D, 0, bmp, 0);
// gl.glTexImage2D(GL10.GL_TEXTURE_2D, 0, GL10.GL_RGBA, bmp.getWidth(), bmp.getHeight(), 0, GL10.GL_RGBA, GL10.GL_, pixels)
}
public void initializeBuffers(int w, int h){
length = Math.min(ratio_w_h/(float)game.getWidth(), 1.0f/(float)game.getHeight());
// Vertices Position //////////////////////////////////////////////////////////
float vertices[] = {0.0f , 0.0f , 0.0f,
length, 0.0f , 0.0f,
0.0f , length, 0.0f,
length, length, 0.0f};
ByteBuffer vertexByteBuffer = ByteBuffer.allocateDirect(vertices.length * 4);
vertexByteBuffer.order(ByteOrder.nativeOrder());
vertexBuffer = vertexByteBuffer.asFloatBuffer();
vertexBuffer.put(vertices);
vertexBuffer.position(0);
// indices ////////////////////////////////////////////////////////////////////
short[] indices = new short[] { 0, 1, 2, 1, 3, 2 };
ByteBuffer indicesByteBuffer = ByteBuffer.allocateDirect(indices.length * 2);
indicesByteBuffer.order(ByteOrder.nativeOrder());
indicesBuffer = indicesByteBuffer.asShortBuffer();
indicesBuffer.put(indices);
indicesBuffer.position(0);
// Texture Coords /////////////////////////////////////////////////////////////
float coords[] = {0.0f, 1.0f,
1.0f, 1.0f,
0.0f, 0.0f,
1.0f, 0.0f};
ByteBuffer textureByteBuffer = ByteBuffer.allocateDirect(coords.length * 4);
textureByteBuffer.order(ByteOrder.nativeOrder());
textureBuffer = textureByteBuffer.asFloatBuffer();
textureBuffer.put(coords);
textureBuffer.position(0);
//////////////////////////////////////////////////////////////////////
// Vertices Position //////////////////////////////////////////////////////////
float verticesBackground[] = {0.0f , 0.0f, 0.0f,
game.getWidth()*length, 0.0f, 0.0f,
0.0f , game.getHeight()*length, 0.0f,
game.getWidth()*length, game.getHeight()*length, 0.0f};
ByteBuffer backgroundVertexByteBuffer = ByteBuffer.allocateDirect(verticesBackground.length * 4);
backgroundVertexByteBuffer.order(ByteOrder.nativeOrder());
backgroundVertexBuffer = backgroundVertexByteBuffer.asFloatBuffer();
backgroundVertexBuffer.put(verticesBackground);
backgroundVertexBuffer.position(0);
// Texture Coords /////////////////////////////////////////////////////////////
float coordsBackground[] = {0.0f, game.getHeight(),
game.getWidth(), game.getHeight(),
0.0f, 0.0f,
game.getWidth(), 0.0f};
ByteBuffer backgroundTextureByteBuffer = ByteBuffer.allocateDirect(coordsBackground.length * 4);
backgroundTextureByteBuffer.order(ByteOrder.nativeOrder());
backgroundTextureBuffer = backgroundTextureByteBuffer.asFloatBuffer();
backgroundTextureBuffer.put(coordsBackground);
backgroundTextureBuffer.position(0);
//////////////////////////////////////////////////////////////////////
game.setResolution(w, h);
game.setRatio_W_H(ratio_w_h);
game.setSquareLength(length);
}
public void onSurfaceChanged(GL10 gl, int w, int h){
width = w;
height = h;
ratio_w_h = (float)width/(float)height;
gl.glViewport(0, 0, w, h);
gl.glMatrixMode(GL10.GL_PROJECTION);
gl.glLoadIdentity();
gl.glOrthof(0.0f, ratio_w_h*1.0f, 0.0f, 1.0f, -1.0f, 1.0f);
gl.glMatrixMode(GL10.GL_MODELVIEW);
initializeBuffers(w, h);
}
public void onDrawFrame(GL10 gl){
gl.glClear(GL10.GL_COLOR_BUFFER_BIT | GL10.GL_DEPTH_BUFFER_BIT);
gl.glLoadIdentity();
gl.glEnable(GL10.GL_TEXTURE_2D);
gl.glEnableClientState(GL10.GL_TEXTURE_COORD_ARRAY);
gl.glTexCoordPointer(2, GL10.GL_FLOAT, 0, backgroundTextureBuffer);
gl.glBindTexture(GL10.GL_TEXTURE_2D, background_textures[0]);
//gl.glTexParameterf(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_WRAP_S, GL10.GL_REPEAT);
//gl.glTexParameterf(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_WRAP_T, GL10.GL_REPEAT);
// if(!texture_set){
// initializeTextures(gl);
// initializeBuffers(width, height);
// }
gl.glEnableClientState(GL10.GL_VERTEX_ARRAY);
gl.glVertexPointer(3, GL10.GL_FLOAT, 0, backgroundVertexBuffer);
// gl.glTexParameterx(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_MAG_FILTER, GL10.GL_LINEAR);
// gl.glTexParameterx(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_MIN_FILTER, GL10.GL_LINEAR);
// gl.glTexParameterx(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_WRAP_S, GL10.GL_CLAMP_TO_EDGE);
// gl.glTexParameterx(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_WRAP_T, GL10.GL_CLAMP_TO_EDGE);
// gl.glDrawArrays(GL10.GL_TRIANGLE_FAN, 0, 4);
gl.glDrawElements(GL10.GL_TRIANGLES, 6, GL10.GL_UNSIGNED_SHORT, indicesBuffer);
gl.glVertexPointer(3, GL10.GL_FLOAT, 0, vertexBuffer);
gl.glTexCoordPointer(2, GL10.GL_FLOAT, 0, textureBuffer);
for(BBHole h: game.getHoles()){
gl.glPushMatrix();
gl.glTranslatef(h.getX()*length, h.getY()*length, 0.0f);
gl.glBindTexture(GL10.GL_TEXTURE_2D, (h.isOpen())?hole_open_textures[h.getColor().ordinal()]:hole_closed_textures[h.getColor().ordinal()]);
// gl.glDrawArrays(GL10.GL_TRIANGLE_FAN, 0, 4);
gl.glDrawElements(GL10.GL_TRIANGLES, 6, GL10.GL_UNSIGNED_SHORT, indicesBuffer);
gl.glPopMatrix();
}
for(BBBubble b: game.getBubbles()){
synchronized (b) {
gl.glPushMatrix();
gl.glTranslatef(b.getX()*length+b.getTx(), b.getY()*length+b.getTy(), 0.0f);
gl.glBindTexture(GL10.GL_TEXTURE_2D, ball_textures[b.getColor().ordinal()]);
// gl.glDrawArrays(GL10.GL_TRIANGLE_FAN, 0, 4);
gl.glDrawElements(GL10.GL_TRIANGLES, 6, GL10.GL_UNSIGNED_SHORT, indicesBuffer);
gl.glPopMatrix();
b.notifyAll();
}
}
// gl.glColor4f(1.0f, 0.0f, 0.0f, 1.0f);
gl.glDisableClientState(GL10.GL_TEXTURE_COORD_ARRAY);
gl.glDisableClientState(GL10.GL_VERTEX_ARRAY);
gl.glDisable(GL10.GL_TEXTURE_2D);
// gl.glFlush();
// Log.i("GL_ERROR = ", Integer.toString( gl.glGetError()));
glSurfaceView.setDirty(false);
}
public BBGame getGame(){
return game;
}
}
So I basically have an Activity a class that extends the GLSurfaceView, a class presented above that implements the GLSurfaceView.Renderer and a class that have the game rules, etc.
Thanks in advance!
I think GL_REPEAT only works with POT (power of two) textures and your drawable-xyz probably got scaled up or down to a non-POT size.
OK I found the solution for my problem but it does not make sense for me. The project that was created in eclipse had in the res folder only the folders drawable-hdpi, drawable-mdpi and drawable-ldpi but not a drawable folder such as in the tutorial I have mentioned before.
So the solution was to create this "drawable" folder and put the image there. Then GL_REPEAT "magically" worked for the galaxy tab. I wasted 2 days because of this folder problem :(.
I am curious if it makes sense or not and if I should put all my textures inside these drawable folder always.
Im new to openGL, and im trying to map an texture to a square. I followed NeHe's tutorial on texture mapping here:
http://insanitydesign.com/wp/wp-content/uploads/lesson06.zip
Right now i see my image...but its not mapping correctly. Heres the original image:
http://ge.tt/2FzsdIx
...and heres what im seeing.
http://ge.tt/6y3cdIu
I used the vertices and texture arrays from this great iphone tutorial (link below) so im hoping they have been mapped correctly. Below is the link to my code in Square.java, thanks!
public class Square {
// Our vertices.
private float vertices[] = {
-1.0f, 1.0f, 0.0f, // 0, Top Left
-1.0f, -1.0f, 0.0f, // 1, Bottom Left
1.0f, -1.0f, 0.0f, // 2, Bottom Right
1.0f, 1.0f, 0.0f, // 3, Top Right
};
// The order we like to connect them.
private short[] indices = { 0, 1, 2, 0, 2, 3 };
// Our vertex buffer.
private FloatBuffer vertexBuffer;
// Our index buffer.
private ShortBuffer indexBuffer;
/** The buffer holding the texture coordinates */
private FloatBuffer textureBuffer;
//the texture pointer, holds the texture name which is actually a number.
private int[] textures = new int[1];
public Square() {
// a float is 4 bytes, therefore we multiply the number if
// vertices with 4.
ByteBuffer vbb = ByteBuffer.allocateDirect(vertices.length * 4);
vbb.order(ByteOrder.nativeOrder());
vertexBuffer = vbb.asFloatBuffer();
vertexBuffer.put(vertices);
vertexBuffer.position(0);
// short is 2 bytes, therefore we multiply the number if
// vertices with 2.
ByteBuffer ibb = ByteBuffer.allocateDirect(indices.length * 2);
ibb.order(ByteOrder.nativeOrder());
indexBuffer = ibb.asShortBuffer();
indexBuffer.put(indices);
indexBuffer.position(0);
//plot our texture
float textCoords[]={
//Mapping coordinates for the vertices
0.0f, 1.0f,
1.0f, 1.0f,
0.0f, 0.0f,
1.0f, 0.0f
};
ByteBuffer tbb = ByteBuffer.allocateDirect(textCoords.length * 4); tbb.order(ByteOrder.nativeOrder());
textureBuffer = tbb.asFloatBuffer(); textureBuffer.put(textCoords);
textureBuffer.position(0);
}
//load our texture(s)
static void loadTexture(GL10 gl, Context context, int resource) {
Bitmap bmp = BitmapFactory.decodeResource(context.getResources(),resource);
GLUtils.texImage2D(GL10.GL_TEXTURE_2D, 0, bmp, 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);
bmp.recycle();
}
/**
* This function draws our square on screen.
* #param gl
*/
public void draw(GL10 gl) {
//use our textures
gl.glEnable(GL10.GL_TEXTURE_2D); // workaround bug 3623
gl.glTexCoordPointer(2, GL10.GL_FLOAT, 0, textureBuffer);
// Counter-clockwise winding.
gl.glFrontFace(GL10.GL_CCW); // OpenGL docs
// Enable face culling.
gl.glEnable(GL10.GL_CULL_FACE); // OpenGL docs
// What faces to remove with the face culling.
gl.glCullFace(GL10.GL_BACK); // OpenGL docs
// Enabled the vertices buffer for writing and to be used during
// rendering.
gl.glEnableClientState(GL10.GL_VERTEX_ARRAY);// OpenGL docs.
// Specifies the location and data format of an array of vertex
// coordinates to use when rendering.
gl.glVertexPointer(3, GL10.GL_FLOAT, 0, // OpenGL docs
vertexBuffer);
gl.glDrawElements(GL10.GL_TRIANGLES, indices.length,// OpenGL docs
GL10.GL_UNSIGNED_SHORT, indexBuffer);
// Disable the vertices buffer.
gl.glDisableClientState(GL10.GL_VERTEX_ARRAY); // OpenGL docs
// Disable face culling.
gl.glDisable(GL10.GL_CULL_FACE); // OpenGL docs
}
}
iPhone tutorial:
http://www.iphonemobilephones.com/opengl-es-from-the-ground-up-part-6-textures-and-texture-mapping.html
You can draw faster using a triangle fan, in the following order in your indices, faster.
01
32
Then you don't need to use drawElements or indices, you can just feed it to drawArrays and only need 4 elements.
Your bug is that the , the tex coords are wrong
tl is 0,0
bl is 0,1
br is 1,1
tr is 1,0
You have
0.0f, 1.0f,
1.0f, 1.0f,
0.0f, 0.0f,
1.0f, 0.0f
So your UV is wrong.
Normally the rendering of a square in OpenGL looks something like this
gl.glLoadIdentity();
gl.glBindTexture(GL.GL_TEXTURE_2D,0);
gl.glBegin(GL_QUADS)
glVertex(x,y,z);
glTexcoord2f(s,t);
glVertex(-x,y,z);
glTexcoord2f(-s,t);
glVertex(-x,-y,z);
glTexcoord2f(-s,-t);
glVertex(x,-y,z);
glTexcoord2f(s,-t);
gl.glEnd();
I don't see anything like that, but I have never done GLES on Android before so I may be too old.
see https://github.com/ChrisLundquist/Asteroids/blob/master/src/ScenePanel.java#L277