Handling OpenGL ES Tasks Manually Android

We have provided a custom implementation leveraging OpenGL without using GLSurface View for users who need to develop for Android versions previous toAndroid 1.5 or who have a need for tighter control of the rendering pipeline and initialization. The following steps to initialize OpenGL ES enable you to start drawing on the screen via the OpenGL interface:

  1. Initialize SurfaceView with a surface of type SURFACE_TYPE_GPU.
  2. Start a thread for OpenGL; all OpenGL calls will be performed on this thread.
  3. Initialize EGL.
  4. Initialize GL.
  5. Start drawing!

Creating a SurfaceView

The first step to drawing fancy 3D graphics on the screen is to create your SurfaceView. This involves extending SurfaceView and implementing callbacks for Surface Holder. Callback. The following is an empty implementation that we complete shortly:

private class BasicGLSurfaceView
extends SurfaceView
implements SurfaceHolder.Callback {
SurfaceHolder mAndroidHolder;
BasicGLSurfaceView(Context context) {
super(context);
mAndroidHolder = getHolder();
mAndroidHolder.addCallback(this);
mAndroidHolder.setType(
SurfaceHolder.SURFACE_TYPE_GPU);
}
public void surfaceChanged(SurfaceHolder holder,
int format, int width, int height) {}
public void surfaceCreated(SurfaceHolder holder) {}
public void surfaceDestroyed(SurfaceHolder holder) {}
}

First, within the constructor, getHolder() is called to get and store the Surface Holder. Because the SurfaceView implements the SurfaceHolder .Callback interface, this SurfaceView is assigned for receiving callbacks for those events. Finally, you must set the surface type to SURFACE_ TYPE_GPU for OpenGL ES calls to work on it. This class is initialized and set as the content View for the activity as follows:

protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mAndroidSurface = new BasicGLSurfaceView(this);
setContentView(mAndroidSurface);
}

Although setting the SurfaceView as the entire content View works fine, it isn’t flexible if you want other functionality on the screen besides the 3D area. One way to place the SurfaceView on your screen and still have the benefits of using an XML layout file is to use one of the container widgets, such as FrameLayout, and add this View to it. For instance, consider this FrameLayout definition, which can exist anywhere within alayout:

<FrameLayout
android:id="@+id/gl_container"
android:layout_height="100px"
android:layout_width="100px" />

This puts a 100×100 pixel square container somewhere on the screen, depending on the rest of the layout. Now, the following code uses the identifier for this FrameLayout to place the child SurfaceView within the FrameLayout:

mAndroidSurface = new TextureGLSurfaceView(this);
setContentView(R.layout.constrained);
FrameLayout v = (FrameLayout) findViewById(R.id.gl_container);
v.addView(mAndroidSurface);

In this example, R.layout.constrained is our layout resource, which contains the FrameLayout with the particular identifier we used. You see why this works regardless of what is drawn in the OpenGL surface as we continue through the initialization of OpenGL ES on Android.

Starting Your OpenGL ES Thread

Within Android, you can update only the screen from the main thread of your application, sometimes referred to as the UI thread. The SurfaceView widget, however, is used so that we can offload graphics processing to a secondary thread, which can update this part of the screen. This is our OpenGL thread. Like updating the screen from the UI thread, all OpenGL calls must be within the same thread.

Recall that the SurfaceView presented also implemented the SurfaceHolder.Callback interface. You can access the underlying surface of the SurfaceView only after calling surfaceCreated() and before calling surfaceDestroyed(). Between these two calls is the only time that we have a valid surface for our OpenGL instance to draw to.

As such, we won’t bother creating the OpenGL thread until surfaceCreated() is called. The following is an example implementation of surfaceCreate(), which starts up the OpenGL thread:

public void surfaceCreated(SurfaceHolder holder) {
mGLThread = new BasicGLThread(this); mGLThread.start();
}

As promised, little more than launching the thread takes place here. The SurfaceView is passed to the thread. This is done because the OpenGL calls need to know which SurfaceView to draw upon.

The BasicGLThread class is an implementation of a Thread that contains the code we run in the OpenGL thread described. The following code block shows which functionality is placed where. The BasicGLThread is placed as a private member of the Activity class.

private class BasicGLThread extends Thread {
SurfaceView sv;
BasicGLThread(SurfaceView view) {
sv = view;
}
private boolean mDone = false;
public void run() {
initEGL();
initGL();
while (!mDone) {
// drawing code
}
}
public void requestStop() {
mDone = true;
try {
join();
} catch (InterruptedException e) {
Log.e("GL", "failed to stop gl thread", e);
}
cleanupGL();
}
public void cleanupGL() {}
public void initGL() {}
public void initEGL() {}
// main OpenGL variables
}

During creation, the SurfaceView is saved for later use. In the run() method, EGL and GL are initialized, which we describe later in this chapter. Then, the drawing code is executed either once or, as shown here, in a loop. Finally, the thread can safely be stopped from outside the thread with a call to the requestStop() method. This also cleans up the OpenGL resources. More on this is found in the section “Cleaning Up OpenGL ES” later in this chapter.

Initializing EGL

Up to this point, the application has a SurfaceView with a valid Surface and an OpenGL thread that has just been launched. The first step with most OpenGL implementations is to initialize EGL, or the native hardware. You do this in basically the same way each time, and this is a good block of code to write once and reuse.The following steps must be performed to initialize EGL on Android:

  1. Get the EGL object.
  2. Initialize the display.
  3. Get a configuration.
  4. Link the EGLSurface to an Android SurfaceView.
  5. Create the EGL context.
  6. Tell EGL which display, surface, and context to use.
  7. Get our GL object for use in rendering.

The Android SDK provides some utility classes for use with OpenGL ES. The first of these is the GLDebugHelper class. OpenGL calls don’t directly return errors. Instead, they set an error internally that can be queried. You can use the GLDebugHelper class to wrap all EGL and GL calls and have the wrapper check for errors and throw an exception. The first call for getting the EGL object uses this wrapper, as shown here:

mEGL = (EGL10) GLDebugHelper.wrap(
EGLContext.getEGL(),
GLDebugHelper.CONFIG_CHECK_GL_ERROR |
GLDebugHelper.CONFIG_CHECK_THREAD,
null);

Here, the EGL10 object is retrieved and wrapped. Turning on the CONFIG_ CHECK_ GL_ ERROR flag checks for all GL Errors. In addition, the wrapper makes sure all our GL and EGL calls are made from the correct thread because CONFIG_ CHECK_ THREAD is enabled.

Now we can proceed with initializing the display, as shown here:

mGLDisplay = mEGL.eglGetDisplay(EGL10.EGL_DEFAULT_DISPLAY);

The default display, EGL10.EGL_DEFAULT_DISPLAY, is configured by the internals of the Android implementation of OpenGL ES. Now that we have the display, we can initialize EGL and get the version of the implementation:

int[] curGLVersion = new int[2];
mEGL.eglInitialize(mGLDisplay, curGLVersion);

The current GL version varies by device.With the display initialized, we can request which configuration is closest to the one we require:

int[] mConfigSpec = {EGL10.EGL_RED_SIZE, 5,
EGL10.EGL_GREEN_SIZE, 6,
EGL10.EGL_BLUE_SIZE, 5,
EGL10.EGL_DEPTH_SIZE, 16,
EGL10.EGL_NONE };
EGLConfig[] configs = new EGLConfig[1];
int[] num_config = new int[1];
mEGL.eglChooseConfig(mGLDisplay, mConfigSpec,
configs, 1, num_config);
mGLConfig = configs[0];

The preceding configuration works on the emulator and the current hardware. If you are unsure that the configuration you’ve chosen works with your application’s target platforms, this is a good way to check the resulting list of configurations.

Now we can create the EGL surface based on this configuration:

mGLSurface = mEGL.eglCreateWindowSurface
(mGLDisplay, mGLConfig, sv.getHolder(), null);

Recall that we stored our SurfaceView for use later. Here, we use it to pass the native Android surface to EGL so they can be linked correctly. We still need to get the EGL context before we can finalize and get our instance of the GL object.

mGLContext = mEGL.eglCreateContext(
mGLDisplay, mGLConfig,EGL10.EGL_NO_CONTEXT, null);

Now that we have our display, surface, and context,we can get our GL object.

mEGL.eglMakeCurrent(mGLDisplay, mGLSurface,
mGLSurface, mGLContext);
mGL = (GL10) GLDebugHelper.wrap(
mGLContext.getGL(),
GLDebugHelper.CONFIG_CHECK_GL_ERROR |
GLDebugHelper.CONFIG_CHECK_THREAD, null);

Once again,we use GLDebugHelper to wrap the GL object so that it checks errors and confirms the thread for us. This completes the initialization of EGL on Android. Next, we can initialize GL to set up our projection and other rendering options.

Initializing GL

Now the fun begins. We have EGL fully initialized, and we have a valid GL object, so we can initialize our drawing space. For this example, we won’t be drawing anything complex. We leave most options at their default values.

Typically, one of the first calls made to initialize GL is to set the viewport. Here is an example of how to set the viewport to the same dimensions as our SurfaceView:

int width = sv.getWidth();
int height = sv.getHeight();
mGL.glViewport(0, 0, width, height);

The location of the surface on the screen is determined internally by EGL. We also use the following width and height of the SurfaceView to determine the aspect ratio for GL to render in. In the following code, we complete the configuration of a basic GL projection setup:

mGL.glMatrixMode(GL10.GL_PROJECTION);
mGL.glLoadIdentity();
float aspect = (float) width/height;
GLU.gluPerspective(mGL, 45.0f, aspect, 1.0f, 30.0f);
mGL.glClearColor(0.5f,0.5f,0.5f,1);

The Android SDK provides a few helpers similar to those found in GLUT (OpenGL Utility Toolkit). Here, we use one of them to define a perspective in terms of the vertical angle of view, aspect ratio, and near and far clipping planes.The gluPerspective() method is useful for configuring the projection matrix, which transforms th 3D scene into a flat surface. Finally, we clear the screen to gray.

Drawing on the Screen

Now that EGL and GL are initialized, objects can be drawn to the screen. For this example, to demonstrate that we’ve set up everything to actually draw, we put a simple threevertex flat surface (in layman’s terms, a triangle) on the screen. Here is some sample code to do this:

mGL.glMatrixMode(GL10.GL_MODELVIEW);
mGL.glLoadIdentity();
GLU.gluLookAt(mGL, 0, 0, 10f, 0, 0, 0, 0, 1, 0f);
mGL.glColor4f(1f, 0f, 0f, 1f);
while (!mDone) {
mGL.glClear(GL10.GL_COLOR_BUFFER_BIT |
GL10.GL_DEPTH_BUFFER_BIT);
mGL.glRotatef(1f, 0, 0, 1f);
triangle.draw(mGL);
mEGL.eglSwapBuffers(mGLDisplay, mGLSurface);
}

If it looks like something is missing, you are correct. This code doesn’t actually show the draw command for the triangle. However, it does use an Android SDK utility method to transform the model view matrix with the intuitive gluLookAt() method. Here, it sets the eye point 10 units away from the origin and looks toward the origin. The up value is, as usual, set to the positive y-axis. Within the loop, notice that the identity matrix is not assigned. This gives the glRotatef() method a compounding effect, causing the triangle to rotate in a counter-clockwise direction. In the next section,“Drawing 3D Objects,” we discuss the details of drawing with OpenGL ES in Android. When launched, a screen similar to that in Figure should display.

A red triangle rendered using OpenGL ES on the Android emulator.

A red triangle rendered using OpenGL ES on the Android emulator

You now have a working OpenGL ES environment within the Android SDK. We continue from this point to talk more about drawing within the environment.



Face Book Twitter Google Plus Instagram Youtube Linkedin Myspace Pinterest Soundcloud Wikipedia

All rights reserved © 2018 Wisdom IT Services India Pvt. Ltd DMCA.com Protection Status

Android Topics