3

I'm looking to have an OpenGL view (GLSurfaceView) that uses a Renderer alongside some buttons in a RelativeLayout so that each of these buttons can interact with the rendered view.

Let's say in this RelativeLayout I have one GLSurfaceView and one button underneath it that when pressed will change the GLSurfaceView to a random solid color. I understand how to draw in OpenGL, what I don't understand is how to interact with a renderer from outside the renderer so that the surface can be altered by user input not associated with a touch event on the view itself.

From my research, I'm guessing that I'll need a thread of some sort, and I may need to use the method, queueEvent(Runnable). Not sure where to go from here though.

XML(main.xml)

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout 
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/RL1"
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
>

<android.opengl.GLSurfaceView
    android:id="@+id/GLView"
    android:layout_width="200dip"
    android:layout_height="200dip"
    android:layout_centerHorizontal="true"

     />


<Button
    android:id="@+id/Button1"
    android:layout_width="150dip"
    android:layout_height="100dip"
    android:text="Click."
    android:layout_below="@id/GLView"
    android:layout_centerHorizontal="true"
     />

Activity (Basic.java)

import android.app.Activity;
import android.opengl.*;
import android.os.Bundle;


public class Basic extends Activity {
/** Called when the activity is first created. */


@Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.main);

    GLSurfaceView glView = (GLSurfaceView)findViewById(R.id.GLView);
    glView.setRenderer(new BasicRenderer(this));


}
}

Renderer(OpenGLRenderer.java)

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

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

public class BasicRenderer implements Renderer {

private Context mContext;
private float mWidth, mHeight;
public BasicRenderer(Context context){
    mContext=context;
}

@Override
public void onDrawFrame(GL10 gl) {
    gl.glClear(GL10.GL_COLOR_BUFFER_BIT | 
            GL10.GL_DEPTH_BUFFER_BIT);



}

@Override
public void onSurfaceChanged(GL10 gl, int width, int height) {
    mWidth = (float)width; 
    mHeight = (float)height;

    gl.glViewport(0, 0, width, height);

    gl.glMatrixMode(GL10.GL_PROJECTION);

    gl.glLoadIdentity();

    GLU.gluPerspective(gl, 45.0f,
                               (float) width / (float) height,
                               0.1f, 100.0f);

    gl.glMatrixMode(GL10.GL_MODELVIEW);

    gl.glLoadIdentity();

}

@Override
public void onSurfaceCreated(GL10 gl, EGLConfig config) {

    // Set the background color to white
    gl.glClearColor(1f, 1f, 1f, 0.5f); 

    gl.glShadeModel(GL10.GL_SMOOTH);

    gl.glClearDepthf(1.0f);

    gl.glEnable(GL10.GL_DEPTH_TEST);

    gl.glDepthFunc(GL10.GL_LEQUAL);

    gl.glHint(GL10.GL_PERSPECTIVE_CORRECTION_HINT, 
                      GL10.GL_NICEST);

}

}
genpfault
  • 51,148
  • 11
  • 85
  • 139
HJM
  • 236
  • 1
  • 5
  • 16

1 Answers1

4

I know this is an old question, but it got some votes, so going to answer it

The trick I use to communicate across threads to my renderer is to keep the renderer object as a variable in activity and then queue stuff in the renderer for it to do when it comes to draw the next frame (next call of onDraw):

public class Basic extends Activity {
/** Called when the activity is first created. */

BasicRenderer myRenderer;


@Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.main);

    myRenderer = new BasicRenderer(this);

    GLSurfaceView glView = (GLSurfaceView)findViewById(R.id.GLView);
    glView.setRenderer(myRenderer);


    myRenderer.queueDoSomethingNextTick(BasicRenderer.DO_THIS);

    findViewById(R.id.Button1).setOnTocuhListener(new OnTouchListener(){

        public void onTouch(MotionEvent event){
            myRenderer.queueDoSomethingNextTick(BasicRenderer.DO_THAT);
           // Compiler might complain about myRenderer not being final
        }


    });


}
}


public class BasicRenderer implements Renderer {

    private Context mContext;
    private float mWidth, mHeight;


    private int command;
    public static final DO_THIS = 1;
    public static final DO_THAT = 2;

public BasicRenderer(Context context){
    mContext=context;
}

@Override
public void onDrawFrame(GL10 gl) {

    if(command==DO_THIS){
        //doThis();
    } else if(command==DO_THAT){
        //doThat();
    }

    gl.glClear(GL10.GL_COLOR_BUFFER_BIT | 
        GL10.GL_DEPTH_BUFFER_BIT);

    gl.glDrawAwesomeness();


}

public void queueDoSomethingNextTick(int command){

    this.command = command;

}

}

In the above example, you might want to change command to an array and loop through it. I actually use this approach for telling my renderer which models to draw, or telling my renderer to start loading a large model or texture ahead of time, so that when the game gets round to needing it, it is already in memory and there is no delay in loading it before it is drawn

James Coote
  • 1,975
  • 19
  • 29