Setting up a custom GLScene
The example plug-in download comes with several scenes you can take a look at. However, in this tutorial, you'll build your own and build a game around it.
Your scene class depends on several others. Thus, you'll need to import them for your use. Create a com.ibm.eclipse.shootout.scenes package and make a new class in this package, the GameScene class. Then begin defining it, as shown in Listing 2.
Listing 2. Class dependencies
package com.ibm.eclipse.shootout.scenes;
import com.ibm.eclipse.shootout.views.ShootoutView;
import org.eclipse.swt.examples.openglview.CompiledShape;
import org.eclipse.swt.examples.openglview.GLScene;
import org.eclipse.swt.examples.openglview.SceneGrip;
import org.eclipse.swt.SWT;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.opengl.GL;
import org.eclipse.opengl.GLU;
import java.util.Timer;
import java.util.TimerTask;
public class GameScene extends GLScene {
|
Notice that you import the ShootoutView class, used to get the number of tasks from in the Task View. Then we import three more classes:
- CompiledShape
- A compiled shape is what each shape class will extend. It has some handy methods that help abstract away OpenGL details from you.
- GLScene
-
This is the class your new
GameSceneclass extends. It, too, helps abstract some of the low-level OpenGL details away from you, which are beyond the scope of this tutorial. Feel free, however, to experiment with them.
- SceneGrip
- This is a cool class that handles all the events from the OpenGL canvas. These events include mouse and keyboard events. Later in this tutorial, you'll use the keyboard to shoot BBs and blow up a perfectly happy bug.
Next, you'll define the GameScene's class variables.
There are several shapes to create, which we declare now. You can create dummy static classes for them so the Eclipse integrated development environment (IDE) doesn't highlight all your code in evil red squiggles. Continue defining the GameScene class, as shown in Listing 3.
Listing 3. Defining class variables
public class GameScene extends GLScene {
private static final float[][] COLOR = {
{1.0f, 1.0f, 0.0f, 0.7f},
{0.0f, 1.0f, 0.0f, 0.7f},
{0.0f, 0.0f, 1.0f, 0.7f},
{1.0f, 0.0f, 1.0f, 0.7f},
};
private SceneGrip grip;
private Gun gun;
private Bug[] bugs;
private int bugCount;
private Bullet bullets[];
private Pow pow;
|
A color array is also defined. In OpenGL, a color is defined as a float array of size 4. The first index defines red, the second green, and the third blue. To remember this order, just think "RGB." For an example empty class, here's what the empty Gun class would look like:
Class Gun extends CompiledShape{ }
|
Onto the GameScene class.
We need to initialize the class. The SceneGrip class also gets initialized, which is responsible for the current view and rotation information. This will be clear when we get to see our first object in the OpenGL canvas. Define the GameScene class's constructor, as shown in Listing 4.
Listing 4. Defining class variables
public GameScene(Composite parent) {
super(parent);
this.grip = new SceneGrip(this);
this.grip.setOffsets(-3.25f, 3.25f, -30.5f);
this.grip.setRotation(45.0f, -30.0f);
this.getCanvas().addMouseListener(this.grip);
this.getCanvas().addMouseMoveListener(this.grip);
this.getCanvas().addListener(SWT.MouseWheel, this.grip);
this.getCanvas().addKeyListener(this.grip);
}
|
The constructor sets up the the SceneGrip and adds all the listeners to the OpenGL canvas with the SceneGrip as the listening class.
Next up is initializing the OpenGL context.
Initializing OpenGL parameters
OpenGL has numerous parameters we can configure. We define a few in the initGL method, as shown in Listing 5.
Listing 5. Initializing the OpenGL context
protected void initGL() {
super.initGL();
GL.glLightfv(GL.GL_LIGHT1,
GL.GL_DIFFUSE,
new float[] {1.0f, 1.0f, 1.0f, 1.0f});
GL.glLightfv(GL.GL_LIGHT1,
GL.GL_AMBIENT,
new float[] {0.5f, 0.5f, 0.5f, 1.0f});
GL.glLightfv(GL.GL_LIGHT1,
GL.GL_POSITION,
new float[] {-50.f, 50.0f, 100.0f, 1.0f});
GL.glEnable(GL.GL_LIGHT1);
GL.glEnable(GL.GL_LIGHTING);
GL.glEnable(GL.GL_COLOR_MATERIAL);
GL.glColorMaterial(GL.GL_FRONT, GL.GL_AMBIENT_AND_DIFFUSE);
...
|
Let's initialize the light and light source for GL.GL_LIGHT1. First, the color of diffuse and ambient light are set, followed by the position of the diffuse light. Next, lighting and light1 need to be enabled. Then coloring is enabled, and the last line specifies that ambient and diffuse light can affect the color of colored objects. Next, you'll initialize the custom objects you'll create later in this tutorial.
Initializing your custom objects
There are a few more features to enable and a plethora of objects to initialize. Here, you create handles to quadrics, which are complex shapes like spheres, planes, and cylinders. Finish initializing the OpenGL context, as shown in Listing 6.
Listing 6. Initializing objects
...
GL.glEnable(GL.GL_COLOR_MATERIAL);
GL.glColorMaterial(GL.GL_FRONT, GL.GL_AMBIENT_AND_DIFFUSE);
Bullet.QUADRIC = GLU.gluNewQuadric();
Bug.QUADRIC = GLU.gluNewQuadric();
Gun.QUADRIC = GLU.gluNewQuadric();
GLU.gluQuadricNormals(Bullet.QUADRIC, GLU.GLU_SMOOTH);
GLU.gluQuadricNormals(Gun.QUADRIC, GLU.GLU_SMOOTH);
GLU.gluQuadricNormals(Bug.QUADRIC, GLU.GLU_SMOOTH);
this.gun = new Gun();
bugCount = ShootoutView.viewer.getTable().getItemCount();
this.bugs = new Bug[bugCount];
for (int i = 0; i < this.bugs.length; i++){
this.bugs[i] = new Bug(COLOR[i % COLOR.length]);
}
bullets = new Bullet[25];
for(int i = 0; i < bullets.length; i++)
bullets[i] = new Bullet();
pow = new Pow();
}
|
Here, we set up the three quadric handles to your bullet, bugs, and gun classes. Next, initialize the gun, bugs, bullets and pow classes. Our gun will have 25 BBs outstanding at a time; this should be plenty. We draw the scene next.
This method essentially calls the draw methods of each of your shape classes. However, to avoid having classes pile up on top of each other, we use translation to move the origin of what we're drawing. The origin is where all of the vertices (the points where two or more line segments come together) you create are based. Define the drawScene method, as shown in Listing 7.
Listing 7. The
drawScene method
protected void drawScene() {
super.drawScene();
this.grip.adjust();
pow.draw();
GL.glTranslatef(.2f, -.2f, 9.5f);
for(int i = 0; i < bullets.length; i++)
if(bullets[i] != null)
bullets[i].draw();
GL.glTranslatef(-.2f, .2f, 2.5f);
gun.draw();
GL.glTranslatef(-Bug.RADIUS*bugCount, 0.0f, -20f);
for(int i = 0; i < bugs.length; i++){
bugs[i].draw();
GL.glTranslatef(2*Bug.RADIUS, 0.0f, 0.0f);
}
}
|
Notice that the word Pow! is drawn based on the original origin. We then translate a little and place the origin at the end of the gun's barrel. Then move the origin again and draw the gun. Another translation places the origin where the bugs will be drawn. We draw them in a row, left to right. After each bug is drawn, move the origin over 2*Bug.RADIUS so they don't overlap each other. Next, we define the dispose method.
When Eclipse or the view closes, you need to deallocate the objects. That's what the dispose method is for. Define it as shown in Listing 8.
Listing 8. Disposing the objects
public void dispose() {
GLU.gluDeleteQuadric(Gun.QUADRIC);
GLU.gluDeleteQuadric(Bullet.QUADRIC);
GLU.gluDeleteQuadric(Bug.QUADRIC);
pow.dispose();
this.gun.dispose();
for(int i = 0; i < bugs.length; i++)
bugs[i].dispose();
for(int i = 0; i < bullets.length; i++)
bullets[i].dispose();
super.dispose();
}
|
Deallocate the quadrics (a curve or surface whose equation, in Cartesian coordinates, is of the second degree), dispose of each of the objects, then dispose of the super class. We start creating shapes next.



