Android OpenGl 2.0 Texturing with shaders - java

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);
}
}
}

Related

opengles 2.0 error 1282 after call glDrawElements(...) method

I have some troubles with opengles 2.0. Currently I trying to display 3D teapot model without success. Method GLES20.glDrawElements generate opengl error with number 1282 and nothing is displayed on screen.
My draw method code:
public void draw(float[] tfMVPMatrix) {
GLES20.glUseProgram(miProgramID);
miVertexPositionHandle = GLES20.glGetAttribLocation(miProgramID, VertexShader.Variables.VERTEX_POSITION.getName());
miVertexTexCoordsHandle = GLES20.glGetAttribLocation(miProgramID, VertexShader.Variables.VERTEX_TEXTURE_CORDS.getName());
miVertexNormalsHandle = GLES20.glGetAttribLocation(miProgramID, VertexShader.Variables.VERTEX_NORMALS.getName());
miProjectionMatrixHandle = GLES20.glGetUniformLocation(miProgramID, VertexShader.Variables.MVP_MATRIX.getName());
miColorHandle = GLES20.glGetUniformLocation(miProgramID, FragmentShader.Variables.COLOR.getName());
GLES20.glEnableVertexAttribArray(miVertexPositionHandle);
GLES20.glVertexAttribPointer(miProgramID, 3, GLES20.GL_FLOAT, false, 3 * Float.SIZE, moVertBuff);
GLES20.glEnableVertexAttribArray(miVertexTexCoordsHandle);
GLES20.glVertexAttribPointer(miProgramID, 2, GLES20.GL_FLOAT, false, 2 * Float.SIZE, moTexCoordBuff);
GLES20.glEnableVertexAttribArray(miVertexNormalsHandle);
GLES20.glVertexAttribPointer(miProgramID, 3, GLES20.GL_FLOAT, false, 3 * Float.SIZE, moNormBuff);
GLES20.glUniform4fv(miColorHandle, 1, COLOR, 0);
GLES20.glUniformMatrix4fv(miProjectionMatrixHandle, 1, false, tfMVPMatrix, 0);
GLES20.glDrawElements(GLES20.GL_TRIANGLES, miIndicesNumber, GLES20.GL_UNSIGNED_SHORT, moIndBuff); // opengl error 1282
GLES20.glDisableVertexAttribArray(miVertexPositionHandle);
GLES20.glDisableVertexAttribArray(miVertexTexCoordsHandle);
GLES20.glDisableVertexAttribArray(miVertexNormalsHandle);
}
Vertex shader code:
attribute vec4 vPosition;
attribute vec4 vNormal;
attribute vec2 vTexture;
varying vec2 texCoord;
varying vec4 normal;
uniform mat4 uMVPMatrix;
void main() {
gl_Position = uMVPMatrix * vPosition;
normal = vNormal;
texCoord = vTexture;
}
Fragment shader code:
precision mediump float;
varying vec4 normal;
uniform vec4 vColor;
void main() {
gl_FragColor = vColor;
}
My renderer code:
public class MyRenderer implements GLSurfaceView.Renderer {
private int GLProgramID;
private Demo3DObj oDemoTeapot;
private final float[] mMVPMatrix = new float[16];
private final float[] mProjectionMatrix = new float[16];
private final float[] mViewMatrix = new float[16];
private float fRatio;
#Override
public void onSurfaceCreated(GL10 gl, EGLConfig config) {
GLProgram oProgram = new GLProgram();
GLProgramID = oProgram.build();
oDemoTeapot = new Demo3DObj(GLProgramID);
GLES20.glClearColor(1.0f, 1.0f, 1.0f, 1.0f);
}
#Override
public void onSurfaceChanged(GL10 gl, int width, int height) {
GLES20.glViewport(0, 0, width, height);
fRatio = (float)width/height;
Matrix.frustumM(mProjectionMatrix, 0, -fRatio, fRatio, -1, 1, 3, 7);
}
#Override
public void onDrawFrame(GL10 gl) {
Matrix.setLookAtM(mViewMatrix, 0, 0, 0, -3, 0f, 0f, 0f, 0f, 1.0f, 0.0f);
Matrix.multiplyMM(mMVPMatrix, 0, mProjectionMatrix, 0, mViewMatrix, 0);
GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT | GLES20.GL_DEPTH_BUFFER_BIT);
oDemoTeapot.draw(mMVPMatrix);
}
}
I'm new in opengles world and I do not have any idea what can be wrong here. Can anybody help me solve this problem? What should I change here to display my model?
UPDATE!
Here is method, which is used to create moIndBuff:
private Buffer fillBufferI(int[] oContainer) {
ByteBuffer bb = ByteBuffer.allocateDirect(2 * oContainer.length);
bb.order(ByteOrder.LITTLE_ENDIAN);
for (int s : oContainer)
bb.putInt(s);
bb.rewind();
return bb;
}

Charging multiple textures OpenGL-ES Android

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
// ...
}

Make a simple slider in OpenGL Android

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.

Trying to display openGL graphics using Android

I have been following the Android documentation showing you how to display openGL graphics using Android. I am pretty sure I have followed the code correctly but nothing is displaying. Here is my code:
OpenGLES20Activity.java
import javax.microedition.khronos.opengles.GL10;
import android.app.Activity;
import android.content.Context;
import android.opengl.EGLConfig;
import android.opengl.GLES20;
import android.opengl.GLSurfaceView;
import android.os.Bundle;
public class OpenGLES20Activity extends Activity {
private GLSurfaceView mGLView;
private MyGLRenderer renderer;
private static Triangle mTriangle;
private static Square mSquare;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// Create a GLSurfaceView instance and set it
// as the ContentView for this Activity.
mGLView = new MyGLSurfaceView(this);
setContentView(mGLView);
}
class MyGLSurfaceView extends GLSurfaceView {
public MyGLSurfaceView(Context context){
super(context);
// Create an OpenGL ES 2.0 context
setEGLContextClientVersion(2);
// Set the Renderer for drawing on the GLSurfaceView
renderer = new MyGLRenderer();
setRenderer(renderer);
}
}
public static class MyGLRenderer implements GLSurfaceView.Renderer {
public void onSurfaceCreated(GL10 unused, EGLConfig config) {
}
public void onDrawFrame(GL10 unused) {
// Redraw background color
GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT);
mTriangle.draw();
}
public void onSurfaceChanged(GL10 unused, int width, int height) {
GLES20.glViewport(0, 0, width, height);
}
#Override
public void onSurfaceCreated(GL10 gl,
javax.microedition.khronos.egl.EGLConfig config) {
// Set the background frame color
GLES20.glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
// initialize a triangle
mTriangle = new Triangle();
}
public static int loadShader(int type, String shaderCode){
// create a vertex shader type (GLES20.GL_VERTEX_SHADER)
// or a fragment shader type (GLES20.GL_FRAGMENT_SHADER)
int shader = GLES20.glCreateShader(type);
// add the source code to the shader and compile it
GLES20.glShaderSource(shader, shaderCode);
GLES20.glCompileShader(shader);
return shader;
}
}
}
Triangle.java
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.nio.FloatBuffer;
import android.opengl.GLES20;
import com.example.test3d.OpenGLES20Activity.MyGLRenderer;
public class Triangle {
private FloatBuffer vertexBuffer;
int mProgram;
private final String vertexShaderCode =
"attribute vec4 vPosition;" +
"void main() {" +
" gl_Position = vPosition;" +
"}";
private final String fragmentShaderCode =
"precision mediump float;" +
"uniform vec4 vColor;" +
"void main() {" +
" gl_FragColor = vColor;" +
"}";
// number of coordinates per vertex in this array
static final int COORDS_PER_VERTEX = 3;
static float triangleCoords[] = { // in counterclockwise order:
0.0f, 0.622008459f, 0.0f, // top
0f, 0.311004243f, 0.0f, // bottom left
0f, 0.311004243f, 0.0f // bottom right
};
// Set color with red, green, blue and alpha (opacity) values
float color[] = { 0.63671875f, 0.76953125f, 0.22265625f, 1.0f };
public Triangle() {
// initialize vertex byte buffer for shape coordinates
ByteBuffer bb = ByteBuffer.allocateDirect(
// (number of coordinate values * 4 bytes per float)
triangleCoords.length * 4);
// use the device hardware's native byte order
bb.order(ByteOrder.nativeOrder());
// create a floating point buffer from the ByteBuffer
vertexBuffer = bb.asFloatBuffer();
// add the coordinates to the FloatBuffer
vertexBuffer.put(triangleCoords);
// set the buffer to read the first coordinate
vertexBuffer.position(0);
int vertexShader = MyGLRenderer.loadShader(GLES20.GL_VERTEX_SHADER, vertexShaderCode);
int fragmentShader = MyGLRenderer.loadShader(GLES20.GL_FRAGMENT_SHADER, fragmentShaderCode);
int 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
}
public void draw() {
int vertexStride = 10;
int vertexCount = 10;
// Add program to OpenGL ES environment
GLES20.glUseProgram(mProgram);
// get handle to vertex shader's vPosition member
int mPositionHandle = GLES20.glGetAttribLocation(mProgram, "vPosition");
// Enable a handle to the triangle vertices
GLES20.glEnableVertexAttribArray(mPositionHandle);
// Prepare the triangle coordinate data
GLES20.glVertexAttribPointer(mPositionHandle, COORDS_PER_VERTEX,
GLES20.GL_FLOAT, false,
vertexStride, vertexBuffer);
// get handle to fragment shader's vColor member
int mColorHandle = GLES20.glGetUniformLocation(mProgram, "vColor");
// Set color for drawing the triangle
GLES20.glUniform4fv(mColorHandle, 1, color, 0);
// Draw the triangle
GLES20.glDrawArrays(GLES20.GL_TRIANGLES, 0, vertexCount);
// Disable vertex array
GLES20.glDisableVertexAttribArray(mPositionHandle);
}
}
I have also specified in my manifest file:
<uses-feature android:glEsVersion="0x00020000" android:required="true" />
EDIT: Just to be clear, I'm not getting any errors at all. My screen is just black and it remains black. I have used some print statements and I have confirmed that Triangle.draw() is being called. So my guess would be that the draw implementation is wrong but I followed the documentation so maybe it is something else. Any help is appreciated.
I see two main problems. First of all, your triangle coordinates:
static float triangleCoords[] = { // in counterclockwise order:
0.0f, 0.622008459f, 0.0f, // top
0f, 0.311004243f, 0.0f, // bottom left
0f, 0.311004243f, 0.0f // bottom right
};
The second and third vertex have the same coordinates. A triangle with two identical vertices is degenerate, and will not render any pixels.
Then these values look questionable:
int vertexStride = 10;
int vertexCount = 10;
You have 3 floats per vertex, so vertexStride should be 3 * sizeof(float), which is 12. And I only see 3 vertices, so vertexCount should be 3.

How do i create a list of Objects in Java

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.

Categories

Resources