I have a class file called MarkerCustom. MarkerCustom has a constructor that takes three variables of different types.
public MarkerCustom(int myInt, String, myString, BitmapData myBitmap) {
From my main Main activity i want to load a GLSurface view that will take an ArrayList of every instance of MarkerCustom that i will want to load into the GLSurface along with the data that will be passed into each instance of MarkerCustom's constructor.
Lets call the Array List myMarkers;
i need myMarkers to look like this:
myMarkers[0] = [1, "hello", bitMapData1]
myMarkers[1] = [66, "johnHandy", bitmapData2]
i am fairly new to java and its casting ect confuses me a bit having come from AS3
EDIT
So following AKhill's answer below i have edited my GLSurfaceView to accept an ArrayList as shown below. But the MarkerCustom Class needs to be created from each listed in that ArrayList in the constructor in a manner that its is accessible in the onSurfaceCreate and the onDrawFrame method of the GLSurfaceView
Please see those methods and the for loops/comments in this class below:
public class GLLayer extends GLSurfaceView implements SurfaceHolder.Callback, Camera.PreviewCallback, Renderer {
private Context context;
ArrayList <MarkerCustom> locationTags;
private PhoneOrientation phoneOri;
public GLLayer(Context context, int orientation, ArrayList<MarkerCustom> custMarkers) {
super(context);
locationTags = custMarkers;
this.context = context;
phoneOri=new PhoneOrientation(context); // sensor manager and interpreter
for(int i =0; i<locationTags.size(); i++){
//Need to create a an instance of each MarkerCustom
// something like MarkerCustom locationTags[i]; = new MarkerCustom (its params);
}
this.setEGLConfigChooser(8, 8, 8, 8, 16, 0);
this.getHolder().setFormat(PixelFormat.TRANSLUCENT);
this.setRenderer(this);
phoneOri.start(context, orientation);
}
#Override
public void onDrawFrame(GL10 gl) {
gl.glEnable(GL10.GL_TEXTURE_2D);
gl.glClear(GL10.GL_COLOR_BUFFER_BIT | GL10.GL_DEPTH_BUFFER_BIT);
gl.glLoadIdentity();
GLU.gluLookAt(gl,0, 0, 0, 0, 0, 0, 0, 0, 0);
float floatMat[]=phoneOri.getMatrix();
gl.glMatrixMode(GL10.GL_MODELVIEW);
gl.glLoadMatrixf(floatMat, 0);
for(int i=0;i<loacationTags.size();i++){
gl.glPushMatrix();
//locationTags[i].draw(gl);
gl.glLoadMatrixf(floatMat,0);
}
gl.glPushMatrix();
}
#Override
public void onSurfaceChanged(GL10 gl, int width, int height) {
if(height == 0) {
height = 1;
}
float ratio = (float) width / height;
gl.glViewport(0, 0, width, height);
gl.glMatrixMode(GL10.GL_PROJECTION);
gl.glLoadIdentity();
GLU.gluPerspective(gl, 35.0f, (float)width / (float)height, 5.0f, 200.0f);
gl.glMatrixMode(GL10.GL_MODELVIEW);
gl.glLoadIdentity();
GLU.gluLookAt(gl, 0, 1.0f, 5.0f, 0, 0, 0, 0, 1.0f, 0);
}
#Override
public void onSurfaceCreated(GL10 gl, EGLConfig arg1) {
for(int i=0;i<locationTags.size();i++){
//call each MarkerCustom's loadGLTexture Method
//locationTags[i].loadGLTexture(gl, this.context);
}
gl.glEnable(GL10.GL_TEXTURE_2D);
gl.glShadeModel(GL10.GL_SMOOTH);
gl.glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
gl.glClearDepthf(1.0f);
gl.glEnable(GL10.GL_DEPTH_TEST);
gl.glDepthFunc(GL10.GL_LEQUAL);
gl.glHint(GL10.GL_PERSPECTIVE_CORRECTION_HINT, GL10.GL_SMOOTH);
}
#Override
public void onPreviewFrame(byte[] data, Camera camera) {
}
}
And Just for reference here is my MarkerCustom class
public class MarkerCustom {
public float xPos;
public float yPos;
public float zPos;
public float yaw;
public float pitch;
public Bitmap tagImage;
private FloatBuffer vertexBuffer; // buffer holding the vertices
private float vertices[] = {
0.0f, -10.0f, -10.0f, // V1 - bottom left
0.0f, -10.0f, 10.0f, // V2 - top left
0.0f, 10.0f, -10.0f, // V3 - bottom right
0.0f, 10.0f, 10.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 MarkerCustom(float x, float y, float z, float yawAngle, float pitchAngle, Bitmap bitmap) {
xPos = x;
yPos = y;
zPos = z;
yaw = yawAngle;
pitch = pitchAngle;
tagImage = bitmap;
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
// Enable blending using premultiplied alpha.
gl.glEnable(GL10.GL_BLEND);
gl.glBlendFunc(GL10.GL_ONE, GL10.GL_ONE_MINUS_SRC_ALPHA);
// 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, tagImage, 0);
// Clean up
tagImage.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);
}
}
Try this.
List<MarkerCustom> myList=new ArrayList<MarkerCustom>();
MarkerCustom entry1=new MarkerCustom(myInt, myString, myBitmap);
MarkerCustom entry2=new MarkerCustom(myInt, myString, myBitmap);
myList.add(entry1);
myList.add(entry2);
Shorthand:
List<MarkerCustom> markerList = Arrays.asList(
new MarkerCustom(1, "hello", bitMapData1),
new MarkerCustom(66, "johnHandy", bitMapData2))
};
In this case I think it's easier to create a class Marker (for instance) that has three attributes.
For example:
class Marker {
int var1;
String var2;
BitmapData var3; }
This way, you are able to store an ArrayList of Markers (ArrayList), and you can access all the information you need.
Related
I am making an application for Android with OpenGL-Es following Nehe's tutorial. I have a cube with a texture and my problem is that I want to change it by pressing a button (I have 2 textures in the folder "raw"). I think this is due to my variable imagenes in which I save the route of my images (R.raw.imagen and R.raw.imagen2 on MainActivity.java) only charge the image once at the start of the application, so even if I change the variable later in my function onClick() the texture remains the same.
What I tried to do is making a switch in the class TextureCube.java looking my variable imagenes in the function where I load the texture so it should charge the first image at the start of the application and then if I press the button change it to the other image because of the code onClick().
The image never change because I printed the variable imagenes. I don't know what I am doing wrong.
MainActivity:
b.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
if (get_imagenes() == R.raw.imagen) {
imagenes = R.raw.imagen2;
b.setText("image2");
} else if (get_imagenes() == R.raw.imagen2) {
imagenes = R.raw.imagen;
b.setText("image1");
}
}
});
TextureCube:
// Construct an input stream to texture image
switch (main.imagenes) {
case R.raw.imagen:
is = context.getResources().openRawResource(R.raw.imagen);
break;
case R.raw.imagen2:
is = context.getResources().openRawResource(R.raw.imagen2);
break;
}
I left the rest of the code of the application here.Here is my code of the MainActivity:
public class MainActivity extends AppCompatActivity {
private GLSurfaceView glView;
private TextureCube cube;
int imagenes = R.raw.imagen;
Button b;
Bitmap bitmap;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//GLSurfaceView
glView = new MyGLSurfaceView(this);
cube = new TextureCube();
setContentView(glView);
createButtons();
}
public void createButtons() {
//ButtonB
LinearLayout ll = new LinearLayout(this);
b = new Button(this);
b.setText("Change Texture");
ll.addView(b);
ll.setGravity(Gravity.BOTTOM | Gravity.CENTER);
this.addContentView(ll, new LayoutParams(LayoutParams.FILL_PARENT, LayoutParams.FILL_PARENT));
b.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
if (get_imagenes() == R.raw.imagen) {
imagenes = R.raw.imagen2;
b.setText("image2");
} else if (get_imagenes() == R.raw.imagen2) {
imagenes = R.raw.imagen;
b.setText("image1");
}
}
});
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
super.onCreateOptionsMenu(menu);
getMenuInflater().inflate(R.menu.menu_main, menu);
return true;
}
#Override
public boolean onOptionsItemSelected(MenuItem item) {
// Handle action bar item clicks here. The action bar will
// automatically handle clicks on the Home/Up button, so long
// as you specify a parent activity in AndroidManifest.xml.
int id = item.getItemId();
//noinspection SimplifiableIfStatement
if (id == R.id.action_settings) {
return true;
}
return super.onOptionsItemSelected(item);
}
// Call back when the activity is going into the background
#Override
protected void onPause() {
super.onPause();
glView.onPause();
}
// Call back after onPause()
#Override
protected void onResume() {
super.onResume();
glView.onResume();
}
public int get_imagenes() {
return imagenes;
}
}
My code of the Renderer:
public class MyGLRenderer implements GLSurfaceView.Renderer {
private Context context;
private TextureCube cube;
private MainActivity main;
// For controlling cube's z-position, x and y angles and speeds
float angleX = 0;
float angleY = 0;
float speedX = 0;
float speedY = 0;
float z = -6.0f;
int currentTextureFilter = 0; // Texture filter
// Lighting (NEW)
boolean lightingEnabled = false; // Is lighting on? (NEW)
private float[] lightAmbient = {0.5f, 0.5f, 0.5f, 1.0f};
private float[] lightDiffuse = {1.0f, 1.0f, 1.0f, 1.0f};
private float[] lightPosition = {0.0f, 0.0f, 2.0f, 1.0f};
// Blending (NEW)
boolean blendingEnabled = false; // Is blending on? (NEW)
// Constructor
public MyGLRenderer(Context context) {
this.context = context; // Get the application context (NEW)
cube = new TextureCube();
}
// Call back when the surface is first created or re-created.
#Override
public void onSurfaceCreated(GL10 gl, EGLConfig config) {
gl.glClearColor(0.5f, 0.5f, 0.5f, 1.0f); // Set color's clear-value to black
//gl.glClearColor(0f, 0f, 0f, 1.0f);
gl.glClearDepthf(1.0f); // Set depth's clear-value to farthest
gl.glEnable(GL10.GL_DEPTH_TEST); // Enables depth-buffer for hidden surface removal
gl.glDepthFunc(GL10.GL_LEQUAL); // The type of depth testing to do
gl.glHint(GL10.GL_PERSPECTIVE_CORRECTION_HINT, GL10.GL_NICEST); // nice perspective view
gl.glShadeModel(GL10.GL_SMOOTH); // Enable smooth shading of color
gl.glDisable(GL10.GL_DITHER); // Disable dithering for better performance
// Setup Texture, each time the surface is created (NEW)
cube.loadTexture(gl, context); // Load image into Texture (NEW)
gl.glEnable(GL10.GL_TEXTURE_2D); // Enable texture (NEW)
// Setup lighting GL_LIGHT1 with ambient and diffuse lights (NEW)
gl.glLightfv(GL10.GL_LIGHT1, GL10.GL_AMBIENT, lightAmbient, 0);
gl.glLightfv(GL10.GL_LIGHT1, GL10.GL_DIFFUSE, lightDiffuse, 0);
gl.glLightfv(GL10.GL_LIGHT1, GL10.GL_POSITION, lightPosition, 0);
gl.glEnable(GL10.GL_LIGHT1); // Enable Light 1 (NEW)
gl.glEnable(GL10.GL_LIGHT0); // Enable the default Light 0 (NEW)
// Setup Blending (NEW)
gl.glColor4f(1.0f, 1.0f, 1.0f, 0.5f); // Full brightness, 50% alpha (NEW)
gl.glBlendFunc(GL10.GL_SRC_ALPHA, GL10.GL_ONE); // Select blending function (NEW)
}
// Call back after onSurfaceCreated() or whenever the window's size changes.
#Override
public void onSurfaceChanged(GL10 gl, int width, int height) {
if (height == 0) height = 1; // To prevent divide by zero
float aspect = (float)width / height;
// Set the viewport (display area) to cover the entire window
gl.glViewport(0, 0, width, height);
// Setup perspective projection, with aspect ratio matches viewport
gl.glMatrixMode(GL10.GL_PROJECTION); // Select projection matrix
gl.glLoadIdentity(); // Reset projection matrix
// Use perspective projection
GLU.gluPerspective(gl, 45, aspect, 0.1f, 100.f);
gl.glMatrixMode(GL10.GL_MODELVIEW); // Select model-view matrix
gl.glLoadIdentity(); // Reset
}
#Override
public void onDrawFrame(GL10 gl) {
// Clear color and depth buffers
gl.glClear(GL10.GL_COLOR_BUFFER_BIT | GL10.GL_DEPTH_BUFFER_BIT);
if (lightingEnabled) { //Enable lighting
gl.glEnable(GL10.GL_LIGHTING);
} else {
gl.glDisable(GL10.GL_LIGHTING);
}
if (blendingEnabled) { //Enable blending
gl.glEnable(GL10.GL_BLEND); // Turn blending on (NEW)
gl.glDisable(GL10.GL_DEPTH_TEST); // Turn depth testing off (NEW)
} else {
gl.glDisable(GL10.GL_BLEND); // Turn blending off (NEW)
gl.glEnable(GL10.GL_DEPTH_TEST); // Turn depth testing on (NEW)
}
// ----- Render the Cube ----- //
gl.glLoadIdentity(); // Reset the model-view matrix
gl.glTranslatef(0.0f, 0.0f, z); // Translate into the screen (NEW)
gl.glRotatef(angleX, 1.0f, 0.0f, 0.0f); // Rotate (NEW)
gl.glRotatef(angleY, 0.0f, 1.0f, 0.0f); // Rotate (NEW)
cube.draw(gl);
// Update the rotational angle after each refresh (NEW)
angleX += speedX; // (NEW)
angleY += speedY; // (NEW)
}
}
GLSurfaceView:
public class MyGLSurfaceView extends GLSurfaceView {
MyGLRenderer renderer;
MainActivity main;
private final float TOUCH_SCALE_FACTOR = 180.0f / 320.0f;
private float previousX;
private float previousY;
//Allocate and set the renderer
public MyGLSurfaceView(Context context) {
super(context);
renderer = new MyGLRenderer(context);
this.setRenderer(renderer);
this.requestFocus();
this.setFocusableInTouchMode(true);
}
// Handler for key event
#Override
public boolean onKeyUp(int keyCode, KeyEvent evt) {
switch(keyCode) {
case KeyEvent.KEYCODE_DPAD_LEFT: // Decrease Y-rotational speed
renderer.speedY += 0.1f;
break;
case KeyEvent.KEYCODE_DPAD_RIGHT: // Increase Y-rotational speed
renderer.speedY -= 0.1f;
break;
case KeyEvent.KEYCODE_DPAD_UP: // Decrease X-rotational speed
renderer.speedX += 0.1f;
break;
case KeyEvent.KEYCODE_DPAD_DOWN: // Increase X-rotational speed
renderer.speedX -= 0.1f;
break;
case KeyEvent.KEYCODE_A: // Zoom out (decrease z)
renderer.z -= 0.2f;
break;
case KeyEvent.KEYCODE_Z: // Zoom in (increase z)
renderer.z += 0.2f;
break;
case KeyEvent.KEYCODE_B: // Toggle Blending on/off (NEW)
renderer.blendingEnabled = !renderer.blendingEnabled;
break;
case KeyEvent.KEYCODE_L: // Toggle lighting on/off (NEW)
renderer.lightingEnabled = !renderer.lightingEnabled;
break;
}
return true;
}
// Handler for touch event
#Override
public boolean onTouchEvent(final MotionEvent event) {
float currentX = event.getX();
float currentY = event.getY();
float deltaX, deltaY;
switch (event.getAction()) {
case MotionEvent.ACTION_MOVE:
// Modify rotational angles according to movement
deltaX = currentX - previousX;
deltaY = currentY - previousY;
renderer.angleX += deltaY * TOUCH_SCALE_FACTOR;
renderer.angleY += deltaX * TOUCH_SCALE_FACTOR;
break;
}
// Save current x, y
previousX = currentX;
previousY = currentY;
return true; // Event handled
}
}
And here TextureCube:
public class TextureCube {
private FloatBuffer vertexBuffer; //Buffer for vertex-array
private FloatBuffer texBuffer; //Buffer for texture-coords-array (NEW)
private MainActivity main = new MainActivity();
private float[] vertices = { //Vertices for a face
-1.0f, -1.0f, 0.0f, //left-bottom-front
1.0f, -1.0f, 0.0f, //right-bottom-front
-1.0f, 1.0f, 0.0f, //left-top-front
1.0f, 1.0f, 0.0f //right-top-front
};
float[] texCoords = { // Texture coords
0.0f, 1.0f, //left-bottom
1.0f, 1.0f, //right-bottom
0.0f, 0.0f, //left-top
1.0f, 0.0f //right-top (
};
int[] textureIDs = new int[1]; //new
public TextureCube() {
// Setup vertex-array buffer
ByteBuffer vbb = ByteBuffer.allocateDirect(vertices.length * 4);
vbb.order(ByteOrder.nativeOrder()); // Use native byte order
vertexBuffer = vbb.asFloatBuffer(); // Convert from byte to float
vertexBuffer.put(vertices); // Copy data into buffer
vertexBuffer.position(0); // Rewind
// Setup texture-array buffer
ByteBuffer tbb = ByteBuffer.allocateDirect(texCoords.length * 4);
tbb.order(ByteOrder.nativeOrder());
texBuffer = tbb.asFloatBuffer();
texBuffer.put(texCoords);
texBuffer.position(0);
}
// Draw the cube
public void draw(GL10 gl) {
gl.glFrontFace(GL10.GL_CCW); // Front face in counter-clockwise orientation
gl.glEnable(GL10.GL_CULL_FACE); // Enable cull face
gl.glCullFace(GL10.GL_BACK); // Cull the back face (don't display)
//Enable vertex and texture client
gl.glEnableClientState(GL10.GL_VERTEX_ARRAY);
gl.glVertexPointer(3, GL10.GL_FLOAT, 0, vertexBuffer);
gl.glEnableClientState(GL10.GL_TEXTURE_COORD_ARRAY); // Enable texture-coords-array (NEW)
gl.glTexCoordPointer(2, GL10.GL_FLOAT, 0, texBuffer); // Define texture-coords buffer (NEW)
//Draw all the faces
//Front
gl.glPushMatrix();
gl.glTranslatef(0.0f, 0.0f, 1.0f);
gl.glDrawArrays(GL10.GL_TRIANGLE_STRIP, 0, 4);
gl.glPopMatrix();
//Left
gl.glPushMatrix();
gl.glRotatef(270.0f, 0.0f, 1.0f, 0.0f);
gl.glTranslatef(0.0f, 0.0f, 1.0f);
gl.glDrawArrays(GL10.GL_TRIANGLE_STRIP, 0, 4);
gl.glPopMatrix();
//Back
gl.glPushMatrix();
gl.glRotatef(180.0f, 0.0f, 1.0f, 0.0f);
gl.glTranslatef(0.0f, 0.0f, 1.0f);
gl.glDrawArrays(GL10.GL_TRIANGLE_STRIP, 0, 4);
gl.glPopMatrix();
//Right
gl.glPushMatrix();
gl.glRotatef(90.0f, 0.0f, 1.0f, 0.0f);
gl.glTranslatef(0.0f, 0.0f, 1.0f);
gl.glDrawArrays(GL10.GL_TRIANGLE_STRIP, 0, 4);
gl.glPopMatrix();
//Top
gl.glPushMatrix();
gl.glRotatef(270.0f, 1.0f, 0.0f, 0.0f);
gl.glTranslatef(0.0f, 0.0f, 1.0f);
gl.glDrawArrays(GL10.GL_TRIANGLE_STRIP, 0, 4);
gl.glPopMatrix();
//Bottom
gl.glPushMatrix();
gl.glRotatef(90.0f, 1.0f, 0.0f, 0.0f);
gl.glTranslatef(0.0f, 0.0f, 1.0f);
gl.glDrawArrays(GL10.GL_TRIANGLE_STRIP, 0, 4);
gl.glPopMatrix();
gl.glDisableClientState(GL10.GL_TEXTURE_COORD_ARRAY); // Disable texture-coords-array (NEW)
gl.glDisableClientState(GL10.GL_VERTEX_ARRAY);
gl.glDisable(GL10.GL_CULL_FACE);
}
// Load an image into GL texture
public void loadTexture(GL10 gl, Context context) {
gl.glGenTextures(1, textureIDs, 0); // Generate texture-ID array new
gl.glBindTexture(GL10.GL_TEXTURE_2D, textureIDs[0]); // Bind to texture ID
// Set up texture filters
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);
InputStream is = new InputStream() {
#Override
public int read() throws IOException {
return 0;
}
};
// Construct an input stream to texture image
switch (main.imagenes) {
case R.raw.imagen:
is = context.getResources().openRawResource(R.raw.imagen);
break;
case R.raw.imagen2:
is = context.getResources().openRawResource(R.raw.imagen2);
break;
}
Log.d("prueba","imagenes"+main.imagenes);
Bitmap bitmap;
try {
// Read and decode input as bitmap
bitmap = BitmapFactory.decodeStream(is);
} finally {
try {
is.close();
} catch (IOException e) {
}
}
// Build Texture from loaded bitmap for the currently-bind texture ID
GLUtils.texImage2D(GL10.GL_TEXTURE_2D, 0, bitmap, 0);
bitmap.recycle();
}
}
At program init, you need to load the 2 bitmaps and upload those as 2 new textures to the GPU (glGenTextures / glBindTexture / GLUtils.texImage2D), this should give you two different textureIDs: textureIDs[0] and textureIDs[1].
Then when you draw the cube in public void draw(GL10 gl)you need to add a call to glBindTexture using either textureIDs[0] or textureIDs[1] depending on your button state.
You current code is only loading one of the 2 textures to GPU, the second one is only loaded to RAM when clicking the button. And also you forgot to call glBindTexture in the draw function for the cube.
-- EDIT --
Trying to explain better with some come :
First you need to load the two images to OpenGL textures when program is initialized, instead of loading the second one only when pressing the button.
This will make things easier to handle and will avoid creating any memory leak. So I create a new loadTextures function wich does that:
// you need 2 texture IDs now ...
int NB_GL_TEXTURES = 2;
int[] textureIDs = new int[NB_GL_TEXTURES];
// tool function to load a texture to OpenGL
public void loadTexture(GL10 gl, Context context, InputStream is, int GL_id_slot) {
// decode is to a Bitmap
Bitmap bitmap;
try {
bitmap = BitmapFactory.decodeStream(is);
} finally {
try {
is.close();
} catch (IOException e) {
}
}
// tell OpenGL what is the current GL texture
gl.glBindTexture(GL10.GL_TEXTURE_2D, textureIDs[GL_id_slot]);
// Set up texture filters for current GL 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);
// load the bitmap into current GL texture
GLUtils.texImage2D(GL10.GL_TEXTURE_2D, 0, bitmap, 0);
// destroy the bitmap
bitmap.recycle();
}
// Loads the two images into two OpenGL textures
public void loadTextures(GL10 gl, Context context) {
// generate 2 GL textures IDs => textureIDs[0], textureIDs[1]
gl.glGenTextures(NB_GL_TEXTURES, textureIDs, 0);
// load imagen into GL tex of id textureIDs[0]
InputStream is_bitmap_0 = context.getResources().openRawResource(R.raw.imagen);
loadTexture(gl, context, is_bitmap_0, 0);
// load imagen2 into GL tex of id textureIDs[1]
InputStream is_bitmap_1 = context.getResources().openRawResource(R.raw.imagen2);
loadTexture(gl, context, is_bitmap_1, 1);
}
public void onSurfaceCreated(GL10 gl, EGLConfig config) {
// ...
// Setup the 2 GL Textures, each time the surface is created
gl.glEnable(GL10.GL_TEXTURE_2D);
cube.loadTextures(gl, context);
// ...
}
Next step is to change the cube render code to call glBindTexture at each frame, passing it the correct GL texture ID:
// Draw the cube
public void draw(GL10 gl) {
// ...
//Enable vertex and texture client
gl.glEnableClientState(GL10.GL_VERTEX_ARRAY);
gl.glVertexPointer(3, GL10.GL_FLOAT, 0, vertexBuffer);
gl.glEnableClientState(GL10.GL_TEXTURE_COORD_ARRAY); // Enable texture-coords-array (NEW)
gl.glTexCoordPointer(2, GL10.GL_FLOAT, 0, texBuffer); // Define texture-coords buffer (NEW)
// choose which texture to use on the cube
int GL_id_slot = 0;
if (main.imagenes == R.raw.imagen)
GL_id_slot = 0;
else if (main.imagenes == R.raw.imagen2)
GL_id_slot = 1;
gl.glBindTexture(GL10.GL_TEXTURE_2D, textureIDs[GL_id_slot]);
//Draw all the faces
// ...
}
I have written a program to display an image using texture.
I have added a button that I want to use to go to the next image.
But I don't know which function I should call to go to next image.
Can anyone help me please to know which function I should call in button(b) clicklistener?
MainActivity.java:
public class MainActivity extends Activity {
Context context ;
Square square = new Square();
public Button b;
/** Called when the activity is first created. */
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
this.requestWindowFeature(Window.FEATURE_NO_TITLE);
getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,
WindowManager.LayoutParams.FLAG_FULLSCREEN);
final GLSurfaceView view = new GLSurfaceView(this);
final OpenGLRenderer openGLRenderer = new OpenGLRenderer(this);
view.setRenderer(openGLRenderer);
setContentView(view);
context = this;
b = new Button(this);
b.setText("Next Image");
b.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View arg0) {
// TODO Auto-generated method stub
}
});
this.addContentView(b, new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT));
}
}
OpenGlRenderee:
public class OpenGLRenderer implements Renderer {
private Square square; // the square
private Context context;
/** Constructor to set the handed over context */
public OpenGLRenderer(Context context) {
this.context = context;
this.square = new Square();
}
public void onSurfaceCreated(GL10 gl, EGLConfig config) {
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.5f); //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);
}
public void onDrawFrame(GL10 gl) {
// Clears the screen and depth buffer.
gl.glClear(GL10.GL_COLOR_BUFFER_BIT | GL10.GL_DEPTH_BUFFER_BIT);
// Replace the current matrix with the identity matrix
gl.glLoadIdentity();
// Translates 4 units into the screen.
gl.glTranslatef(0, 0, -4);
// Draw our square.
square.draw(gl);
}
public void onSurfaceChanged(GL10 gl, int width, int height) {
// Sets the current view port to the new size.
gl.glViewport(0, 0, width, height);
// Select the projection matrix
gl.glMatrixMode(GL10.GL_PROJECTION);
// Reset the projection matrix
gl.glLoadIdentity();
final float aspectRatio = width > height ?
(float) width / (float) height :
(float) height / (float) width;
if (width > height) {
// Landscape
gl.glOrthof( -aspectRatio, aspectRatio, -1f, 1f, 0f, 0f);
//gl.glOrthof(0f, -aspectRatio,0, aspectRatio, -1f, 1f);
} else {
// Portrait or square
//gl.glOrthof( 0f, -aspectRatio,0, aspectRatio, -1f, 1f);
gl.glOrthof( -1f, 1f, -aspectRatio, aspectRatio, 0f, 0f);
}
//gl.glOrthof(0f, (float) width / (float) height, 0f, (float) height / (float) width, -1f, 1f);
// Calculate the aspect ratio of the window
GLU.gluPerspective(gl, 45.0f, (float) width / (float) height, 0.1f,
100.0f);
// Select the modelview matrix
gl.glMatrixMode(GL10.GL_MODELVIEW);
// Reset the modelview matrix
gl.glLoadIdentity();
}
}
Square.java:
public class Square {
public static int numberOfImage = 0;
// Our vertices.
private float RectangleVertices[] = {
// 0f, 0f, // 0, Top Left
// 0f, 14f, // 1, Bottom Left
// 9f, 14f, // 2, Bottom Right
// 9f, 0f, // 3, Top Right
-0.5f, 0.5f,0.0f, // 0, Top Left
-0.5f, -0.5f,0.0f, //1, Button Left
0.5f, -0.5f,0.0f,//2,Button Right
0.5f, 0.5f, 0.0f//3, Top Right
};
int[] arr = {
R.drawable.a,
R.drawable.b,
R.drawable.c,
R.drawable.d,
R.drawable.e,
R.drawable.f,
R.drawable.g,
R.drawable.h,
R.drawable.i,
R.drawable.j,
R.drawable.k,
R.drawable.l,
};
float[] colors = {
1.0f, 1.0f, 1.0f, 1.0f,
0.7f, 0.7f, 0.7f, 1.0f,
1.0f, 1.0f, 1.0f, 1.0f,
0.7f, 0.7f, 0.7f, 1.0f,
};
private float LineVertices[] = {
-0.5f, 0f,0.0f,
0.5f, 0f,0.0f,
0.0f,-0.25f,1.0f,
0.0f,0.25f,1.0f,
};
// The order we like to connect them.
private short[] RectangleIndices = { 0, 1,2,0,2,3 };
private short[] LineIndices = {0,1};
// Our vertex buffer.
private FloatBuffer vertexBuffer;
// Our index buffer.
private ShortBuffer indexBuffer;
// Our vertex buffer.
private FloatBuffer vertexBuffer2;
// Our index buffer.
private ShortBuffer indexBuffer2;
FloatBuffer colorBuffer;// = makeFloatBuffer(colors);
//***************************************
//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);
}
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) {
//
//loading texture
// pull in the resource
Bitmap bitmap = null;
Resources resources = context.getResources();
Drawable image = resources.getDrawable( arr[numberOfImage]);
float density = resources.getDisplayMetrics().density;
int originalWidth = (int)(image.getIntrinsicWidth() / density);
int originalHeight = (int)(image.getIntrinsicHeight() / density);
bitmap = decodeSampledBitmapFromResource(context.getResources(),
arr[numberOfImage],originalWidth, originalHeight );
// 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();
if(numberOfImage == arr.length - 1)
numberOfImage = 0;
else
numberOfImage ++;
}
public static Bitmap decodeSampledBitmapFromResource(Resources res, int resId,int reqWidth, int reqHeight) {
final BitmapFactory.Options options = new BitmapFactory.Options();
options.inJustDecodeBounds = true;
BitmapFactory.decodeResource(res, resId, options);
options.inSampleSize = calculateInSampleSize(options, reqWidth,
reqHeight);
// Decode bitmap with inSampleSize set
options.inJustDecodeBounds = false;
Bitmap bmp = BitmapFactory.decodeResource(res, resId, options);
return BitmapFactory.decodeResource(res, resId, options);
}
public static int calculateInSampleSize(BitmapFactory.Options options,
int reqWidth, int reqHeight) {
final int height = options.outHeight;
final int width = options.outWidth;
int inSampleSize = 1;
if (height > reqHeight || width > reqWidth) {
if (width > height) {
inSampleSize = Math.round((float) height / (float) reqHeight);
} else {
inSampleSize = Math.round((float) width / (float) reqWidth);
}
}
return inSampleSize;
}
}
To change an image to a different drawable, you only have to set your imageView to that new image
ImageView iv=(ImageView) findViewById(R.id.iv);
Drawable mDrawable = getResources().getDrawable(R.drawable.iv);
iv.setImageDrawable(mDrawable);
You mentioned a "slider", to me that sounds like you may be interested in a ViewPager. You can create a view pager adapter, and use that to load up your images and the user can swipe the images left to right, or you can have the images change by button press if you like.
public class ViewPagerAdapter extends PagerAdapter {
private Context mContext;
private int[] mArr;
private Button btnRight; // move to next
private Button btnLeft; // move to prev
/**
* #param int[] array of your drawables
*/
public ViewPagerAdapter(Context context, int[] arr)
this.mContext = context;
this.mArr = arr;
}
#Override
public int getCount() {
return mArr.length();
}
#Override
public boolean isViewFromObject(View view, Object object) {
return view = ((LinearLayout) object); // whatever your main view is ll or rl
}
#Override
public Object instantiateItem(final ViewGroup container, final int position) {
LayoutInflater inflater = (LayoutInflater) mContext.
getSystemService(Context.LAYOUT_INFLATER_SERVICE);
// to setup buttons to change position of pager
btnLeft = (Button) itemView.findViewById(R.id.btn_left);
btnLeft.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
// setup your logic for swiping changing views
// for example
// ref: http://stackoverflow.com/questions/21368693/how-to-do-circular-scrolling-on-viewpager/24244144#24244144
int meta = ((ViewPager) container.getCurrentItem() - 1;
if (meta == 0) {
((ViewPager) container).setCurrentItem(mArr.length - 1, false);
} else {
((ViewPager) container).setCurrentitem(meta);
}
}
});
btnRight = (Button) itemView.findViewById(R.id.btn_right);
btnRight.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
// setup your logic for swiping changing views
// for example
int meta = ((ViewPager) container.getCurrentItem() - 1;
if (meta == mArr.length - 1) {
((ViewPager) container).setCurrentItem(1, false);
} else {
((ViewPager) container).setCurrentitem(meta);
}
}
});
// to listen for swiping of pager
((ViewPager) container).setOnPageChangeListener(new OnPageChangeListener() {
#Override
public void onPageSelected(int pos) {
// add whatever logic you need
// for example
if (pos == 0) {
((ViewPager) container).setCurrentItem(mArr.length - 1, true);
} else if (pos == mArr.length - 1) {
((ViewPager) container).setcurrentItem(1, true);
}
// can add other useful override
#Override
public void onPagescrollStateChanged(int state) {}
#Override
public void onPageScrolled(int pos, float posOffset, int posOffsetPixeles) {}
});
}
}
}
In your main activity call and set your adapter. For example
ViewPager viewPager = (ViewPager) findviewById(R.id.pager);
PagerAdapter adapter = new ViewPagerAdapter(context, mArr);
viewPager.setAdapter(adapter);
Hopefully this is what you were asking for. Let me know if there are any questions.
The top image is the undesired result (it also seems to flicker).
The bottom image is what I would like the render to look like on ALL devices.
Hello, I seem to be having problems with rendering a textured square to my galaxy s4, but not on my my gt p3113 tablet...
Here is the code from my GLRenderer:
#Override
public void onDrawFrame(GL10 gl)
{
manObjects.draw(gl, 0, 0);
}
#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
// respect the height:width ratio of the window.
GLU.gluOrtho2D(gl, -1f, 1f, 1.6f, -1.6f);
gl.glMatrixMode(GL10.GL_MODELVIEW); // Select The Modelview Matrix
gl.glLoadIdentity(); // Reset The Modelview Matrix
}
#Override
public void onSurfaceCreated(GL10 gl, EGLConfig config)
{
// Settings
gl.glEnable(GL10.GL_TEXTURE_2D); // Enable Texture Mapping
gl.glShadeModel(GL10.GL_SMOOTH); // Enable Smooth Shading
gl.glClearColor(0.0f, 0.0f, 0.0f, 0.5f); // Black Background
gl.glClearDepthf(1.0f); // Depth Buffer Setup
// Really Nice Perspective Calculations
gl.glHint(GL10.GL_PERSPECTIVE_CORRECTION_HINT, GL10.GL_NICEST);
gl.glEnable(GL10.GL_BLEND); // Enable blending
gl.glDisable(GL10.GL_DEPTH_TEST); // Disable depth test
gl.glBlendFunc(GL10.GL_SRC_ALPHA, GL10.GL_ONE_MINUS_SRC_ALPHA);
// Load textures
manObjects.load(gl, mContext);
}
Anyone have any ideas as to why this is happening? And more specifically why it works on one device and not on the other?
Draw code:
public void draw(GL10 gl, float x, float y)
{
gl.glLoadIdentity();
gl.glBindTexture(GL10.GL_TEXTURE_2D, texPointers[0]);
tSquare[0].draw(gl);
}
public void drawBLACK(GL10 gl)
{
gl.glLoadIdentity();
gl.glBindTexture(GL10.GL_TEXTURE_2D, 0);
gl.glScalef(1f, 1.6f, 1);
gl.glColor4f(0, 0, 0, 1);
tSquare[0].draw(gl);
gl.glColor4f(1, 1, 1, 1);
}
tSquare[0].draw(gl):
public void draw(GL10 gl)
{
//Enable the vertex, texture and normal state
gl.glEnableClientState(GL10.GL_VERTEX_ARRAY);
gl.glEnableClientState(GL10.GL_TEXTURE_COORD_ARRAY);
//Point to our buffers
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);
}
here is an example of my onDrawFrame, try making your gl calls in onDrawFrame instead
first make
public int width, height;
then
#Override
public void onSurfaceChanged(GL10 gl, int width, int height) {
this.width = width;
this.height = height;
}
then onDrawFrame something like this
#Override
public void onDrawFrame(GL10 gl)
{
gl.glClear(GL10.GL_COLOR_BUFFER_BIT);
gl.glViewport(0, 0, width, height);
gl.glMatrixMode(GL10.GL_PROJECTION);
gl.glLoadIdentity();
gl.glOrthof(0.0f, width, 0.0f, height, -1.0f, 1.0f);
gl.glMatrixMode(GL10.GL_MODELVIEW);
gl.glLoadIdentity();
gl.glEnable(GL10.GL_BLEND);
gl.glBlendFunc(GL10.GL_SRC_ALPHA, GL10.GL_ONE_MINUS_SRC_ALPHA);
gl.glEnable(GL10.GL_TEXTURE_2D);
manObjects.draw(gl, 0, 0);
}
Possible solution:
I have added another draw before the call that draws the star. This added draw call draws a giant black rectangle that covers the entire screen...
I feel like I'm only masking the problem and not really fixing it...
Thoughts?
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.
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.
I'm trying to learn OpenGL ES as part of my foray into Android development.
So far, I've created the following Android application by cutting and pasting from various tutorials I found.
The application is supposed to create 2 coloured squares (1 red square and 1 blue square) and rotate them around a central point.
So during part of the rotation, the red square should be in front while during another part of the rotation, the blue square should be in front.
When I run my application in the Android simulator however, it only shows the blue square in front.
Does anyone know what I'm missing?
package hello.world;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.nio.FloatBuffer;
import java.util.ArrayList;
import java.util.List;
import javax.microedition.khronos.egl.EGLConfig;
import javax.microedition.khronos.opengles.GL10;
import android.app.Activity;
import android.content.Context;
import android.opengl.GLSurfaceView;
import android.os.Bundle;
public class HelloActivity extends Activity {
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(new HelloView(this));
}
private class HelloView extends GLSurfaceView {
private HelloRenderer renderer;
public HelloView(Context context) {
super(context);
renderer = new HelloRenderer(context);
setRenderer(renderer);
}
}
private class HelloRenderer implements GLSurfaceView.Renderer {
public float xrot; //X Rotation ( NEW )
public float yrot; //Y Rotation ( NEW )
public float zrot; //Z Rotation ( NEW )
private List<ColoredQuad> quads;
public HelloRenderer(Context context) {
quads = new ArrayList<ColoredQuad>();
quads.add(new ColoredQuad(
new Vertex3D(-1.0f, -1.0f, 1.0f),
new Vertex3D(1.0f, -1.0f, 1.0f),
new Vertex3D(-1.0f, 1.0f, 1.0f),
new Vertex3D(1.0f, 1.0f, 1.0f),
new RGBA(1.0f, 0.0f, 0.0f)));
quads.add(new ColoredQuad(
new Vertex3D(-1.0f, -1.0f, -1.0f),
new Vertex3D(1.0f, -1.0f, -1.0f),
new Vertex3D(-1.0f, 1.0f, -1.0f),
new Vertex3D(1.0f, 1.0f, -1.0f),
new RGBA(0.0f, 0.0f, 1.0f)));
}
/**
* Called whenever drawing is needed.
*/
public void onDrawFrame(GL10 gl) {
// clear screen and depth buffer
gl.glClear(GL10.GL_COLOR_BUFFER_BIT | GL10.GL_DEPTH_BUFFER_BIT);
gl.glLoadIdentity();
//Drawing
gl.glTranslatef(0.0f, 0.0f, -5.0f); //move 5 units into the screen
gl.glScalef(0.5f, 0.5f, 0.5f); //scale the objects to 50 percent of original size
//Rotate around the axis based on the rotation matrix (rotation, x, y, z)
gl.glRotatef(xrot, 1.0f, 0.0f, 0.0f); //X
gl.glRotatef(yrot, 0.0f, 1.0f, 0.0f); //Y
gl.glRotatef(zrot, 0.0f, 0.0f, 1.0f); //Z
for (ColoredQuad quad : quads) {
quad.draw(gl);
}
//Change rotation factors (nice rotation)
xrot += 3.0f;
yrot += 2.0f;
zrot += 1.0f;
}
/**
* Called when the surface has changed.
* For example, when switching from portrait to landscape view.
*/
public void onSurfaceChanged(GL10 gl, int width, int height) {
gl.glViewport(0, 0, width, height);
}
public void onSurfaceCreated(GL10 gl, EGLConfig config) {
gl.glEnable(GL10.GL_SMOOTH); // enable smooth shading
gl.glClearColor(0.0f, 0.0f, 0.0f, 0.5f); // black background
gl.glClearDepthf(GL10.GL_DEPTH_TEST); // enable depth testing
gl.glDepthFunc(GL10.GL_LEQUAL); // type of depth testing to do
//Really Nice Perspective Calculations
gl.glHint(GL10.GL_PERSPECTIVE_CORRECTION_HINT, GL10.GL_NICEST);
}
}
private class Vertex3D {
public float x;
public float y;
public float z;
public Vertex3D(float x, float y, float z) {
this.x = x;
this.y = y;
this.z = z;
}
}
public class RGBA {
public float red;
public float blue;
public float green;
public float alpha;
public RGBA(float red, float green, float blue) {
this.red = red;
this.blue = blue;
this.green = green;
this.alpha = 1.0f;
}
}
private ByteBuffer makeByteBuffer(byte[] array)
{
ByteBuffer bb = ByteBuffer.allocateDirect(array.length);
bb.put(array);
bb.position(0);
return bb;
}
private FloatBuffer makeFloatBuffer(float[] array)
{
ByteBuffer bb = ByteBuffer.allocateDirect(array.length * 4);
bb.order(ByteOrder.nativeOrder());
FloatBuffer fb = bb.asFloatBuffer();
fb.put(array);
fb.position(0);
return fb;
}
private class ColoredQuad {
private FloatBuffer vertexBuffer;
private FloatBuffer colorBuffer;
private ByteBuffer indexBuffer;
private float[] vertices = new float[12]; // 4 vertices * XYZ (12)
private float[] colors = new float[16]; // 4 vertices * RGBA (16)
private byte[] indices = {
0, 1, 2, 1, 2, 3
};
public ColoredQuad(Vertex3D bottomLeft, Vertex3D bottomRight, Vertex3D topLeft, Vertex3D topRight, RGBA color) {
vertices[0] = bottomLeft.x; vertices[1] = bottomLeft.y; vertices[2] = bottomLeft.z;
vertices[3] = bottomRight.x; vertices[4] = bottomRight.y; vertices[5] = bottomRight.z;
vertices[6] = topLeft.x; vertices[7] = topLeft.y; vertices[8] = topLeft.z;
vertices[9] = topRight.x; vertices[10]= topRight.y; vertices[11]= topRight.z;
colors[0] = color.red; colors[1] = color.green; colors[2] = color.blue; colors[3] = color.alpha;
colors[4] = color.red; colors[5] = color.green; colors[6] = color.blue; colors[7] = color.alpha;
colors[8] = color.red; colors[9] = color.green; colors[10]= color.blue; colors[11]= color.alpha;
colors[12]= color.red; colors[13]= color.green; colors[14]= color.blue; colors[15]= color.alpha;
vertexBuffer = makeFloatBuffer(vertices);
colorBuffer = makeFloatBuffer(colors);
indexBuffer = makeByteBuffer(indices);
}
public void draw(GL10 gl) {
//Point to our buffers
gl.glEnableClientState(GL10.GL_VERTEX_ARRAY);
gl.glEnableClientState(GL10.GL_COLOR_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.glColorPointer(4, GL10.GL_FLOAT, 0, colorBuffer);
//Draw the vertices as triangles, based on the Index Buffer information
gl.glDrawElements(GL10.GL_TRIANGLES, indices.length, GL10.GL_UNSIGNED_BYTE, indexBuffer);
//Disable the client state before leaving
gl.glDisableClientState(GL10.GL_VERTEX_ARRAY);
gl.glDisableClientState(GL10.GL_TEXTURE_COORD_ARRAY);
}
}
}
The reason you only see the blue one in front is because something is going wrong with the depth testing, and the blue one is simply drawn last (over everything else).
Where you say
gl.glClearDepthf(GL10.GL_DEPTH_TEST); // enable depth testing
you probably mean
gl.glEnable(GL10.GL_DEPTH_TEST);
and possibly
gl.glClearDepthf(1.0f);
but that's the default anyway.
Cheers, Aert.