Reputation: 98
Hello StackOverflow community. I have been working on a live wallpaper for android using OpenGL and have been successful thus far in getting OpenGL to render on the live wallpaper and have also been able to load and bind a single texture onto a quad. However when I load more than one texture the last bound texture which is a crate texture is bound onto the first quad which should have a dirt texture, and the second quad tries to bind to a texture that does not exist.
This is my quad class which draw the quads and binds whatever texture the texture object stores:
public class Quad {
/** The quad's location in space. */
private float[] vector;
private Texture texture;
/** Buffer holding the vertices. */
private FloatBuffer vertexBuffer;
/** Array holding the quad's size. */
private float[] vertices;
public Quad(GL10 gl, Context context, float[] vector, Texture texture) {
this.vector = vector;
this.texture = texture;
// Check the length of the vector to make sure it is valid.
if(vector.length != 8) {
throw new IllegalArgumentException("Please pass a vector with a length of 8. (x, y, z) (w, h) (rotX, rotY, rotZ)");
}
vertices = new float[] {
0, 0, 0.0f, // V1 - bottom left
0, vector[4], 0.0f, // V2 - top left
vector[3], 0, 0.0f, // V3 - bottom right
vector[3], vector[4], 0.0f // V4 - top right
};
ByteBuffer byteBuffer = ByteBuffer.allocateDirect(vertices.length * 4);
byteBuffer.order(ByteOrder.nativeOrder());
vertexBuffer = byteBuffer.asFloatBuffer();
vertexBuffer.put(vertices);
vertexBuffer.position(0);
}
public void draw(GL10 gl) {
// Reset the Modelview Matrix
gl.glLoadIdentity();
float[] cameraVector = Camera.getLocationVector();
// Translate the object
gl.glTranslatef(vector[0] - cameraVector[0], vector[1] - cameraVector[1], vector[2] - cameraVector[2]);
// Rotate the object
gl.glRotatef(vector[5] - cameraVector[3], 1f, 0f, 0f);
gl.glRotatef(vector[6] - cameraVector[4], 0f, 1f, 0f);
gl.glRotatef(vector[7] - cameraVector[5], 0f, 0f, 1f);
// Bind the previously generated texture
int crap = texture.getTextureID();
gl.glBindTexture(GL10.GL_TEXTURE_2D, texture.getTextureID());
// 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, texture.getBuffer());
// 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);
}
}
This is how I initialize my quads:
Texture.loadTextures(gl, context);
quad = new Quad(gl, context, new float[] { 0.0f, 0.0f, -5.0f, 1.0f, 1.0f, 0.0f, 0.0f, 0.0f, }, Texture.TEXTURE_DIRT);
quad2 = new Quad(gl, context, new float[] { -1.0f, 0.0f, -10.0f, 1.0f, 1.0f, 0.0f, 45.0f, 0.0f, }, Texture.TEXTURE_CRATE);
This is the texture class that manages all the wallpaper's textures loaded from android bitmaps:
public class Texture {
/** Buffer holding the texture coordinates. */
private FloatBuffer textureBuffer;
private final float textureCoords[] = {
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)
};
/** The texture this specific instance is pointing to. */
private int texture;
/** The id of the texture to be grabbed from android bitmap loader. */
private int textureID;
/** Stores all texture data. */
private static ArrayList<Texture> textureList;
/** List of all registered textures */
private static int lastRegisteredTexture;
/** Array of all loaded texture pointers. */
private static int[] textures;
/** Flag to indicate whether the class has been initialized properly. */
private static boolean isInitialized;
private static boolean texturesGenned;
/////////////////////////////////////////////////////////////////////////////////////////
// All recycled textures loaded on app launch
public static Texture TEXTURE_DIRT;
public static Texture TEXTURE_CRATE;
/**
* Create a new opengl texture.
* @param gl
* @param context
* @param id
*/
private Texture(GL10 gl, Context context, int id) {
if(isInitialized) {
ByteBuffer byteBuffer = ByteBuffer.allocateDirect(textureCoords.length * 4);
byteBuffer.order(ByteOrder.nativeOrder());
textureBuffer = byteBuffer.asFloatBuffer();
textureBuffer.put(textureCoords);
textureBuffer.position(0);
textureID = id;
// Add the texture into the list before loading the texture so the
// size of the texture pointer array can be determined and not have to be
// reinitialized
textureList.add(this);
} else {
throw new IllegalStateException("Not yet initialized.");
}
}
/**
* Load the texture into opengl.
* @param gl
* @param context
* @param id
*/
private static void loadGLTexture(GL10 gl, Context context) {
gl.glGenTextures(textures.length, textures, 0);
for(int i = 0; i < textureList.size(); i++) {
// Loading texture without scaling
BitmapFactory.Options opts = new BitmapFactory.Options(); opts.inScaled = false;
Bitmap bitmap = BitmapFactory.decodeResource(context.getResources(), textureList.get(i).getID(), opts);
// ...And bind it to our array
gl.glBindTexture(GL10.GL_TEXTURE_2D, textureList.get(i).getTextureID());
// 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_NEAREST);
// Use Android GLUtils to specify a two-dimensional texture image from our bitmap
GLUtils.texImage2D(GL10.GL_TEXTURE_2D, 0, bitmap, 0);
textureList.get(i).texture = lastRegisteredTexture;
lastRegisteredTexture++;
// Clean up native resources
bitmap.recycle();
}
Log.d("Test", "Test2");
}
public int getTextureID() {
return textures[texture];
}
public FloatBuffer getBuffer() {
return textureBuffer;
}
private int getID() {
return textureID;
}
public static void loadTextures(GL10 gl, Context context) {
if(!isInitialized) {
isInitialized = true;
textureList = new ArrayList<Texture>();
// Load all static textures
TEXTURE_DIRT = new Texture(gl, context, R.raw.dirt);
TEXTURE_CRATE = new Texture(gl, context, R.drawable.crate);
// Initialize the texture pointer to match the number of textures
textures = new int[textureList.size()];
loadGLTexture(gl, context);
} else {
throw new IllegalStateException("Already initialized.");
}
}
}
My suspension is that OpenGL is somehow loading one texture over the other due to a flaw in my logic and I believe the problem is happening somewhere in "loadGLTexture". Thanks ahead of time.
Upvotes: 1
Views: 1201
Reputation: 26
You called glBindTexture first.
gl.glBindTexture(GL10.GL_TEXTURE_2D, textureList.get(i).getTextureID());
But [texture] is set later.
textureList.get(i).texture = lastRegisteredTexture;
So the first texture(textures[0]) was replaced and the second not binded.
Upvotes: 1