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
// ...
}
Related
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.
So, I received this code from another post to SO. It seems to be the most complete working code for adding textures in openGl 2.0 with shaders in android. How does he know what integer to pass into textureResourceId, and how do I set-up a resource Id to the .png files I put into my project?
Here's the link to the SO post I'm reffering to:
Android OpenGL|ES 2.0 Texturing
And here's the Square Code:
public class Square{
private static final String TAG = "Square";
public float[] rotation = {0.0f,0.0f,45.0f};
public float[] scale = {100.0f,100f,100f};
public float[] position = {0.0f,0.0f,100f};
public float[] color = { 0.0f, 0.0f, 1.0f, 1.0f };
private int textureRef = -1;
private int mMVPMatrixHandle;
protected int DRAW_MODE = GLES20.GL_TRIANGLES;
protected int mProgram;
protected int mPositionHandle;
protected Vertex vertices;
protected Vertex texture;
private int mColorHandle;
private int vsTextureCoord;
private int fsTexture;
protected float[] result_matrix = new float[16];
private final String vertexShaderCode =
"uniform mat4 uMVPMatrix;" +
"attribute vec3 vPosition;" +
"attribute vec2 TexCoordIn;" +
"varying vec2 TexCoordOut;" +
"void main() {" +
//the matrix must be included as a modifier of gl_Position
" gl_Position = uMVPMatrix * vec4(vPosition,1.0);" +
" TexCoordOut = TexCoordIn;" +
"}";
private final String fragmentShaderCode =
"precision mediump float;" +
"uniform vec4 vColor;" +
"uniform sampler2D Texture;" +
"varying lowp vec2 TexCoordOut;" +
"void main() {" +
" gl_FragColor = vColor*TexCoordOut*Texture;" +
"}";
//I am fully aware that I am not using the texture by assigning the colour, but until I can actually SEND the texture through, there would be no point.
static float squareCoords[] = { -0.5f, 0.5f, 0.0f, // top left
-0.5f, -0.5f, 0.0f, // bottom left
0.5f, -0.5f, 0.0f, // bottom right
0.5f, 0.5f, 0.0f }; // top right
private short drawOrder[] = { 0, 1, 2, 0, 2, 3 }; // order to draw vertices
public Square(int textureResourceId) {
int vertexShader = GFXUtils.loadShader(GLES20.GL_VERTEX_SHADER, vertexShaderCode);
int fragmentShader = GFXUtils.loadShader(GLES20.GL_FRAGMENT_SHADER, fragmentShaderCode);
mProgram = GLES20.glCreateProgram(); // create empty OpenGL ES Program
GLES20.glAttachShader(mProgram, vertexShader); // add the vertex shader to program
GLES20.glAttachShader(mProgram, fragmentShader); // add the fragment shader to program
GLES20.glLinkProgram(mProgram); // creates OpenGL ES program executables
textureRef = GFXUtils.textures.get(textureResourceId);
// initialize vertex byte buffer for shape coordinates
vertices = new Vertex(squareCoords, drawOrder, GFXUtils.COORDS_PER_VERTEX);
texture = new Vertex (new float[]
{
1.0f, 0.0f,
0.0f, 0.0f,
1.0f, 1.0f,
0.0f, 1.0f,
}, GFXUtils.COORDS_PER_TEXTURE);
DRAW_MODE = GLES20.GL_TRIANGLE_FAN;
}
private void getHandles()
{
//get handle to vertex shader's vPosition member
mPositionHandle = GLES20.glGetAttribLocation(mProgram, "vPosition");
if (mPositionHandle == -1) Log.e(TAG, "vPosition not found");
//get handle to fragment shader's vColor member
mColorHandle = GLES20.glGetUniformLocation(mProgram, "vColor");
if (mColorHandle == -1) Log.e(TAG, "vColor not found");
//get handle to shape's transformation matrix
mMVPMatrixHandle = GLES20.glGetUniformLocation(mProgram, "uMVPMatrix");
if (mMVPMatrixHandle == -1) Log.e(TAG, "uMVPMatrix not found");
//get handle to texture coordinate variable
vsTextureCoord = GLES20.glGetAttribLocation(mProgram, "TexCoordIn");
if (vsTextureCoord == -1) Log.e(TAG, "TexCoordIn not found");
//get handle to shape's texture reference
fsTexture = GLES20.glGetUniformLocation(mProgram, "Texture");
if (fsTexture == -1) Log.e(TAG, "Texture not found");
}
private void translateRotateScale(float[] matrix, float[] perspectiveMatrix)
{
for (int i= 0; i < perspectiveMatrix.length;i++)
matrix[i] = perspectiveMatrix[i];
Matrix.translateM(matrix, 0, position[0], position[1], position[2]);
Matrix.rotateM(matrix, 0, rotation[0], 1.0f, 0.0f, 0.0f);
Matrix.rotateM(matrix, 0, rotation[1], 0.0f, 1.0f, 0.0f);
Matrix.rotateM(matrix, 0, rotation[2], 0.0f, 0.0f, 1.0f);
Matrix.scaleM(matrix, 0, scale[0], scale[1], scale[2]);
}
public void draw(float[] mvpMatrix) {
rotation[2]+=0.5;
// Add program to OpenGL ES environment
GLES20.glUseProgram(mProgram);
GFXUtils.checkGlError("using program");
//Housekeeping
getHandles();
translateRotateScale(result_matrix, mvpMatrix);
//end housekeeping
// Set color for drawing the shape
GLES20.glUniform4fv(mColorHandle, 1, color, 0);
// Apply the projection and view transformation
GLES20.glUniformMatrix4fv(mMVPMatrixHandle, 1, false, result_matrix, 0);
GFXUtils.checkGlError("glUniformMatrix4fv");
// Prepare the shape coordinate data
GLES20.glVertexAttribPointer(mPositionHandle, GFXUtils.COORDS_PER_VERTEX,
GLES20.GL_FLOAT, false,
GFXUtils.vertexStride, vertices.floatBuffer);
GFXUtils.checkGlError("load vertex buffer");
GLES20.glVertexAttribPointer(vsTextureCoord, GFXUtils.COORDS_PER_TEXTURE,
GLES20.GL_FLOAT, false,
GFXUtils.textureStride, texture.floatBuffer);
GFXUtils.checkGlError("load texture buffer - " + vsTextureCoord);
// Enable a handle to the shape vertices
GLES20.glEnableVertexAttribArray(mPositionHandle);
GFXUtils.checkGlError("enable position handle");
GLES20.glEnableVertexAttribArray(vsTextureCoord);
GFXUtils.checkGlError("enable texture handle");
GLES20.glActiveTexture(GLES20.GL_TEXTURE0);
GFXUtils.checkGlError("activtexture");
GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, textureRef);
GFXUtils.checkGlError("bindtexture");
GLES20.glUniform1i(fsTexture, 0);
GFXUtils.checkGlError("uniformi");
//Draw the shape
GLES20.glDrawElements(DRAW_MODE, vertices.numIndeces, GLES20.GL_UNSIGNED_SHORT, vertices.indexBuffer);
GFXUtils.checkGlError("glDrawArrays with " + vertices.numVertices + " vertices");
//Disable vertex array
GLES20.glDisableVertexAttribArray(vsTextureCoord);
GLES20.glDisableVertexAttribArray(mPositionHandle);
GFXUtils.checkGlError("glDisableVertexAttribArray for position");
}
}
My Main Activity Class:
public class MainActivity extends ActionBarActivity {
GLSurfaceView myGL;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
myGL=new MySurface(this);
setContentView(myGL);
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.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();
if (id == R.id.action_settings) {
return true;
}
return super.onOptionsItemSelected(item);
}
/**
* A placeholder fragment containing a simple view.
*/
public static class PlaceholderFragment extends Fragment {
public PlaceholderFragment() {
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View rootView = inflater.inflate(R.layout.fragment_main, container,
false);
return rootView;
}
}
//---------------------------------Open GL-------------------------------------------------------
class MySurface extends GLSurfaceView
{
private MyRenderer myRend;
public MySurface(Context context)
{
super(context);
myRend=new MyRenderer();
setEGLContextClientVersion(2);
setRenderer(myRend);
setRenderMode(GLSurfaceView.RENDERMODE_WHEN_DIRTY);
}
}
Square mSquare;
float [] mViewMatrix=new float[16];
float [] mMVPMatrix=new float[16];
float [] mProjectionMatrix=new float[16];
private float[] mRotationMatrix=new float[16];
class MyRenderer implements GLSurfaceView.Renderer
{
#Override
public void onSurfaceCreated(GL10 gl, EGLConfig config) {
GLES20.glClearColor(0.0f, 0.0f, 0.0f, 1f);
mSquare=new Square(R.drawable.brick_texture);
}
#Override
public void onDrawFrame(GL10 gl) {
GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT);
Matrix.setLookAtM(mViewMatrix, 0, 0, 0, -5, 0f, 0f, 0f, 0f, 1.0f, 0.0f);
Matrix.multiplyMM(mMVPMatrix, 0, mProjectionMatrix, 0, mViewMatrix, 0);
mSquare.draw(mMVPMatrix);
}
#Override
public void onSurfaceChanged(GL10 gl, int width, int height) {
GLES20.glViewport(0, 0, width, height);
float ratio = (float) width / height;
Matrix.frustumM(mProjectionMatrix, 0, -ratio, ratio, -1, 1, 2, 50);
}
}
}
I want to rotate my cube and add 4 buttons to speed up speed down move up and move down. Could you help me? The color is yellow. 4 buttons under cube.cube should rotate about y axis.
public class MyGLRenderer implements Renderer {
Context context;
Cube cube;
public MyGLRenderer(Context context) {
this.context = context;
cube = new Cube();
}
// Call back when the surface is first created or re-created
#Override
public void onSurfaceCreated(GL10 gl, EGLConfig config) {
// clear-value for color and depth, enabling depth-test, etc.
gl.glClearColor(0.0f, 0.0f, 0.0f, 1.0f); // Set color's clear-value to black
}
// 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;
float aspect = (float) width / height;
// Set the viewport (display area) to cover the entire window
gl.glViewport(0, 0, width, height);
// Select projection matrix: projection matrix or model-view matrix
gl.glMatrixMode(GL10.GL_PROJECTION);
// Reset projection matrix
gl.glLoadIdentity();
GLU.gluPerspective(gl, 45, aspect, 0.1f, 100.f);
// Select model-view matrix
gl.glMatrixMode(GL10.GL_MODELVIEW);
// Reset
gl.glLoadIdentity();
}
// Call back to draw the current frame.
#Override
public void onDrawFrame(GL10 gl) {
// Clear color and depth buffers using clear-value set earlier
gl.glClear(GL10.GL_COLOR_BUFFER_BIT | GL10.GL_DEPTH_BUFFER_BIT);
// Reset model-view matrix
gl.glLoadIdentity();
// Translate into the screen
gl.glTranslatef(0.0f, 0.0f, -5.0f);
// Draw cube
cube.draw(gl);
}
}
this is what you are looking for: https://www.opengl.org/sdk/docs/man2/xhtml/glRotate.xml and you have to place it in front of glTranslatef
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 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.