2 Replies - 1685 Views - Last Post: 26 September 2012 - 10:44 AM

#1 Behemyth  Icon User is offline

  • New D.I.C Head
  • member icon

Reputation: 0
  • View blog
  • Posts: 12
  • Joined: 19-July 12

Interpolation in Android OpenGL ES Environment

Posted 26 September 2012 - 09:18 AM

Trying to setup a game loop thread for a test animation, I have come across a few problems. There are errors shown during start up and the Android program runs through the splash screen, but then terminates. This is the red highlighted Logcat error.
    09-24 16:09:18.731: E/AndroidRuntime(569): FATAL EXCEPTION: GLThread 76
    09-24 16:09:18.731: E/AndroidRuntime(569): java.lang.NullPointerException
    09-24 16:09:18.731: E/AndroidRuntime(569): 	at 
    com.spacewrecksoftware.iceward.GLrenderer.onSurfaceCreated(GLrenderer.java:22)
    09-24 16:09:18.731: E/AndroidRuntime(569): 	at 
    android.opengl.GLSurfaceView$GLThread.guardedRun(GLSurfaceView.java:1446)
    09-24 16:09:18.731: E/AndroidRuntime(569): 	at 
    android.opengl.GLSurfaceView$GLThread.run(GLSurfaceView.java:1216)


This program creates a texture that moves back and forth on a landscape screen with a test implementation of interpolation rendering for smoother animation at higher frame rates.
Here is the gameloop, renderer, menu, object, and state files in that order.

GameLoop:
    import android.os.SystemClock;

    public class GameLoop extends Thread {
	public static int deltaTime;
	boolean gameRunning = true;
    public void setRunning(boolean running) {
		this.gameRunning = running;
	}
    public ObjectState previous= new ObjectState(0, 0, 10/1000, 0);
    public ObjectState current= new ObjectState(0, 0, 10/1000, 0);
    public Globject button= new Globject(previous, current);
    public void run() {
    	
    	int ticksPerSec = 30;
    	int skipTicks = 1000 / ticksPerSec;
    	int maxFrameskip = 5;
    	long nextGameTick = SystemClock.uptimeMillis();
    	int loops;
    	long interpolation;
    	long oldTimeSinceStart = 0;
    	
		while (gameRunning) {

			
			loops = 0;
			while( SystemClock.uptimeMillis() > nextGameTick & loops < maxFrameskip){
				long timeSinceStart = SystemClock.uptimeMillis();
			      deltaTime = (int) (timeSinceStart - oldTimeSinceStart);
			     oldTimeSinceStart = timeSinceStart;
				updateGame();
				 nextGameTick += skipTicks;
		            loops++;
		        }
			interpolation = SystemClock.uptimeMillis() + skipTicks - nextGameTick 
                    /  skipTicks ;
            drawGame(interpolation);
		}
	}
    int switchit = 1;
	private void updateGame() {
		if (switchit==1){	
			if (button.now.position_x<=-10){		
				 switchit=0;
				 button.past.velocity_x=0-button.past.velocity_x;
			}
			else{
		button.past=button.now.copy(button.now);
		button.now=button.past.addDt(button.past, deltaTime);
			}
		}
		else if(switchit==0){	
			if (button.now.position_x>=10){		
				 switchit=1;
				 button.past.velocity_x=0-button.past.velocity_x;
			}
			else{
				button.past=button.now.copy(button.now);
				button.now=button.past.addDt(button.past, deltaTime);
			}
		}
		
	}
	private void drawGame(float interpolation) {
		button.past=button.past.interpolate(button.past, button.now, interpolation);
		Menu.menuSurface.requestRender();
		
	}
    }



Renderer:
    import javax.microedition.khronos.egl.EGLConfig;
    import javax.microedition.khronos.opengles.GL10;

    import android.content.Context;
    import android.opengl.GLSurfaceView.Renderer;
    import android.opengl.GLU;


    public class GLrenderer implements Renderer {
	
	private Globject object1;	
	private Context context;
	long startTime;
	public GLrenderer(Context context) {
		this.context = context;
		object1 = new Globject(null, null);
	}
	public void onSurfaceCreated(GL10 gl, EGLConfig config) {		
		//Load the texture for the cube once during Surface creation
		object1.now.position_x=0;
		object1.past.position_x=0;
		object1.loadGLTexture(gl, this.context);
		gl.glEnable(GL10.GL_BLEND);
		gl.glBlendFunc(GL10.GL_SRC_ALPHA, GL10.GL_ONE_MINUS_SRC_ALPHA);
		gl.glEnable(GL10.GL_TEXTURE_2D);			//Enable Texture Mapping
		gl.glShadeModel(GL10.GL_SMOOTH); 			//Enable Smooth Shading
		gl.glClearColor(0.0f, 0.666f, 0.831f, 1f); 
		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

		gl.glHint(GL10.GL_PERSPECTIVE_CORRECTION_HINT, GL10.GL_NICEST); 
	}
	/**
	 * Here we do our drawing
	 */
	public void onDrawFrame(GL10 gl) {
		gl.glClear(GL10.GL_COLOR_BUFFER_BIT | GL10.GL_DEPTH_BUFFER_BIT);	
		gl.glLoadIdentity();		
		
		gl.glTranslatef(0.0f, 0.0f, -20f);	
		gl.glPushMatrix();
		gl.glTranslatef( object1.past.position_x, 0, 0);	
		object1.draw(gl);
		gl.glPopMatrix();
		
	}

	/**
	 * If the surface changes, reset the view
	 */
	public void onSurfaceChanged(GL10 gl, int width, int height) {
		if(height == 0) { 						//Prevent A Divide By Zero By
			height = 1; 						//Making Height Equal One
		}

		gl.glViewport(0, 0, width, height); 	//Reset The Current Viewport
		gl.glMatrixMode(GL10.GL_PROJECTION); 	//Select The Projection Matrix
		gl.glLoadIdentity(); 					//Reset The Projection Matrix

		//Calculate The Aspect Ratio Of The Window
		GLU.gluPerspective(gl, 45.0f, (float)width / (float)height, 0.1f, 100.0f);

		gl.glMatrixMode(GL10.GL_MODELVIEW); 	//Select The Modelview Matrix
		gl.glLoadIdentity(); 					//Reset The Modelview Matrix
	}
    }



Menu:
    import android.app.Activity;
    import android.opengl.GLSurfaceView;
    import android.os.Bundle;
    import android.view.MotionEvent;
    import android.view.SurfaceHolder;

    public class Menu extends Activity
    {
    static GLSurfaceView menuSurface;
    private GameLoop thread;
	@Override
	public void onCreate(Bundle savedInstanceState) 
	{
		
		super.onCreate(savedInstanceState);
		menuSurface = new GLSurfaceView(this);
			menuSurface.setRenderer(new GLrenderer(this));
			menuSurface.setRenderMode(0);
		setContentView(menuSurface);
		thread = new GameLoop();
		thread.setRunning(true);
		thread.start();
	}

	@Override
	protected void onresume() 
	{
		super.onresume();
		menuSurface.onresume();
	}

	@Override
	protected void onpause() 
	{	
		super.onpause();
		menuSurface.onpause();
	}	
	public boolean onTouchEvent(MotionEvent event) {
		        return super.onTouchEvent(event);	
	}
    public void surfaceDestroyed(SurfaceHolder holder) {
	boolean retry = true;
	while (retry) {
		try {
			thread.join();
			retry = false;
		} catch (InterruptedException e) {
			// try again shutting down the thread
		}
	}
    }
    }


Object: note-the image is a power of 2, four by one texture.
    import java.io.IOException;
    import java.io.InputStream;
    import java.nio.ByteBuffer;
    import java.nio.ByteOrder;
    import java.nio.FloatBuffer;

    import javax.microedition.khronos.opengles.GL10;

    import android.content.Context;
    import android.graphics.Bitmap;
    import android.graphics.BitmapFactory;
    import android.opengl.GLUtils;

    public class Globject {

	private FloatBuffer vertexBuffer;

	private FloatBuffer textureBuffer;

	private ByteBuffer indexBuffer;
	
	
	private int[] textures = new int[1];
    public ObjectState past;
    public ObjectState now;

    private float vertices[] = {
    					//Vertices according to faces
			    		-4.0f, 1.0f,  //Vertex 0
			    		-4.0f, -1.0f,  //v1
			    		4.0f, 1.0f,   //v2
			    		4.0f, -1.0f   //v3

											};
    
    /** The initial texture coordinates (u, v) */	
    private float texture[] = {    		
			    		//Mapping coordinates for the vertices	
    					0.0f, 0.0f,
			    		0.0f, 1.0f,	    		
			    		1f, 0.0f,
			    		1f, 1.0f
			    		

			    							};
        
    /** The initial indices definition */	
    private byte indices[] = {
    					
    		0,1,2,3				
    										};

	public Globject(ObjectState past2,ObjectState now2) {
		
		now=now2;
		past=past2;
		
		ByteBuffer byteBuf = ByteBuffer.allocateDirect(vertices.length * 4);
		byteBuf.order(ByteOrder.nativeOrder());
		vertexBuffer = byteBuf.asFloatBuffer();
		vertexBuffer.put(vertices);
		vertexBuffer.position(0);

		//
		byteBuf = ByteBuffer.allocateDirect(texture.length * 4);
		byteBuf.order(ByteOrder.nativeOrder());
		textureBuffer = byteBuf.asFloatBuffer();
		textureBuffer.put(texture);
		textureBuffer.position(0);

		//
		indexBuffer = ByteBuffer.allocateDirect(indices.length);
		indexBuffer.put(indices);
		indexBuffer.position(0);
	}
	
	public void draw(GL10 gl) {
		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);
		
		//Enable the vertex and texture state
		gl.glVertexPointer(2, GL10.GL_FLOAT, 0, vertexBuffer);
		gl.glTexCoordPointer(2, GL10.GL_FLOAT, 0, textureBuffer);
		
		//Draw the vertices as triangles, based on the Index Buffer information
		gl.glDrawElements(GL10.GL_TRIANGLE_STRIP, indices.length, GL10.GL_UNSIGNED_BYTE, indexBuffer);
		
		//Disable the client state before leaving
		gl.glDisableClientState(GL10.GL_VERTEX_ARRAY);
		gl.glDisableClientState(GL10.GL_TEXTURE_COORD_ARRAY);
	}

	public void loadGLTexture(GL10 gl, Context context) {
		//Get the texture from the Android resource directory
		InputStream is = context.getResources().openRawResource(R.drawable.custom_button1);
		Bitmap bitmap = null;
		try {
			bitmap = BitmapFactory.decodeStream(is);

		} finally {
			//Always clear and close
			try {
				is.close();
				is = null;
			} catch (IOException e) {
			}
		}

		//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_LINEAR);
		gl.glTexParameterf(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_MAG_FILTER, GL10.GL_LINEAR);

		//Different possible texture parameters, e.g. GL10.GL_CLAMP_TO_EDGE
		gl.glTexParameterf(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_WRAP_S, GL10.GL_REPEAT);
		gl.glTexParameterf(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_WRAP_T, GL10.GL_REPEAT);
		
		//Use the 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();
	}   
    }


State:
    public class ObjectState {
    public float position_x;
    public float position_y;
    public float velocity_x;
    public float velocity_y;
    public ObjectState(float position_x2, float position_y2, float velocity_x2, float velocity_y2) {
        position_x = position_x2;
        position_y = position_y2;
        velocity_x = velocity_x2;
        velocity_y = velocity_y2;
    }
	public ObjectState copy(ObjectState state0) {
    ObjectState state1= new ObjectState(state0.position_x, state0.position_y,
    		state0.velocity_x, state0.velocity_y);
    return state1;
	}  
	public ObjectState subtract(ObjectState state, ObjectState state1){
		ObjectState  state2=state.copy(state);
		state2.position_x=(state1.position_x-state.position_x);
		state2.position_y=(state1.position_y-state.position_y);
		state2.velocity_x=(state1.velocity_x-state.velocity_x);
		state2.velocity_y=(state1.velocity_y-state.velocity_y);
	return state2;
	}
	public ObjectState addDt(ObjectState state, int deltaTime){
		ObjectState  state1=state.copy(state);
		state1.position_x=(state1.velocity_x*deltaTime)+state1.position_x;
		state1.position_y=(state1.velocity_y*deltaTime)+state1.position_y;
	return state1;
	}
	public ObjectState interpolate(ObjectState state, ObjectState state2,float interpolate){
		ObjectState  state1=state.copy(state);
		state1.position_x=(state1.subtract(state2, state).position_x*interpolate)+state.position_x;
		state1.position_y=(state1.subtract(state2, state).position_y*interpolate)+state.position_y;
		state1.velocity_x=(state1.subtract(state2, state).velocity_x*interpolate)+state.velocity_x;
		state1.velocity_y=(state1.subtract(state2, state).velocity_y*interpolate)+state.velocity_y;
	return state1;
	}
    }


I haven't been able to find a problem, help would be much appreciated! Thanks!

Is This A Good Question/Topic? 0
  • +

Replies To: Interpolation in Android OpenGL ES Environment

#2 farrell2k  Icon User is offline

  • D.I.C Lover
  • member icon

Reputation: 866
  • View blog
  • Posts: 2,657
  • Joined: 29-July 11

Re: Interpolation in Android OpenGL ES Environment

Posted 26 September 2012 - 09:30 AM

So, what's the NUllPointerException? Is that GL10 object null?

Also, where are you testing, hardware or emulator? Try both.

This post has been edited by farrell2k: 26 September 2012 - 09:37 AM

Was This Post Helpful? 0
  • +
  • -

#3 Behemyth  Icon User is offline

  • New D.I.C Head
  • member icon

Reputation: 0
  • View blog
  • Posts: 12
  • Joined: 19-July 12

Re: Interpolation in Android OpenGL ES Environment

Posted 26 September 2012 - 10:44 AM

Sadly, I am unable to test hardware as I don't own an android device =P So this is on an emulator. Yes, it is most likely the GL10 object.
Was This Post Helpful? 0
  • +
  • -

Page 1 of 1