I have the following problem: I'm trying to create a solar system in OpenGL ES on Android. I already have some spheres. Now I want to make the spheres rotate in an orbit around the biggest sphere in the center (like the planets rotate around the sun). How do I do that? The rotation of a sphere around itself works, but I don't know how to make it rotate around another sphere.
Also, I have a problem with colors. There must be a problem somewhere in my code, because all my "planets" are grey. I tried to make the sun red, but it sticks to grey and I don't know why. I used gl.glColor4f and that should work, but it doesn't.
Please help, this is VERY urgent, because I need the thing running by Monday, the 28th of January, because this is a program I'm doing for my studies and I really have no idea how to fix these problems. Please help. Thank you.
Here is my code:
import javax.microedition.khronos.egl.EGLConfig;
import javax.microedition.khronos.opengles.GL;
import javax.microedition.khronos.opengles.GL10;
import my.pack.graphics.primitives.Sphere;
import android.app.Activity;
import android.content.Context;
import android.opengl.GLSurfaceView;
import android.opengl.GLU;
import android.opengl.GLUtils;
import android.os.Bundle;
import android.util.FloatMath;
import android.util.Log;
import android.view.Menu;
import android.view.MenuItem;
import android.view.MotionEvent;
import android.widget.Toast;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.nio.FloatBuffer;
import java.nio.IntBuffer;
import java.nio.ShortBuffer;
public class GLES06 extends Activity {
private GLSurfaceView touchableGLSurfaceView;
private final int MENU_RESET = 1, MENU_PAN = 2, MENU_ZOOM = 3;
private final int GROUP_DEFAULT = 0, GROUP_PAN = 1, GROUP_ZOOM = 2;
private boolean PAN = false;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
touchableGLSurfaceView = new TouchableGLSurfaceView(this);
setContentView(touchableGLSurfaceView);
touchableGLSurfaceView.setFocusableInTouchMode(true);
touchableGLSurfaceView.requestFocus();
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
menu.add(GROUP_DEFAULT, MENU_RESET, 0, "Reset");
menu.add(GROUP_PAN, MENU_PAN, 0, "Pan");
menu.add(GROUP_ZOOM, MENU_ZOOM, 0, "Zoom");
return super.onCreateOptionsMenu(menu);
}
@Override
public boolean onPrepareOptionsMenu(Menu menu) {
if (PAN) {
menu.setGroupVisible(GROUP_PAN, false);
menu.setGroupVisible(GROUP_ZOOM, true);
} else {
menu.setGroupVisible(GROUP_PAN, true);
menu.setGroupVisible(GROUP_ZOOM, false);
}
return super.onPrepareOptionsMenu(menu);
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case MENU_RESET:
TouchableGLSurfaceView.resetViewing();
Toast.makeText(this, "trackball reset",
Toast.LENGTH_SHORT).show();
touchableGLSurfaceView.requestRender();
return true;
case MENU_PAN:
Toast.makeText(this, "panning activated",
Toast.LENGTH_SHORT).show();
PAN = true;
TouchableGLSurfaceView.guiZoom = false;
return true;
case MENU_ZOOM:
Toast.makeText(this, "zooming activated",
Toast.LENGTH_SHORT).show();
PAN = false;
TouchableGLSurfaceView.guiZoom = true;
return true;
}
return super.onOptionsItemSelected(item);
}
@Override
protected void onResume() {
super.onResume();
touchableGLSurfaceView.onResume();
}
@Override
protected void onPause() {
super.onPause();
touchableGLSurfaceView.onPause();
}
}
// touchable GLSurfaceView with
// an implementation of a virtual trackball rotation control
class TouchableGLSurfaceView extends GLSurfaceView {
private OurRenderer ourRenderer;
static public boolean guiZoom = true;
// possible touch states
final static int NONE = 0;
final static int ROTATE = 1;
final static int ZOOM = 2;
final static int PAN = 3;
int touchState = NONE;
final static float MIN_DIST = 50;
static int oldDistance = 0;
static int centerX = 0, centerY = 0;
static int oldCenterX = 0, oldCenterY = 0;
static float EYE_DISTANCE, EYE_DISTANCE_INC;
static float PAN_X, PAN_Y, PAN_INC;
static float CURRENT_QUATERNION[], LAST_QUATERNION[];
static float TRANSFORM_MATRIX[];
static int OLD_MOUSE_X, OLD_MOUSE_Y, MOUSE_BUTTON_PRESSED;
static int WINDOW_W = 600;
static int WINDOW_H = 800;
static float zNear = 1.0f, zFar = 1000.0f;
static {
CURRENT_QUATERNION = new float[4];
LAST_QUATERNION = new float[4];
TRANSFORM_MATRIX = new float[16];
}
public TouchableGLSurfaceView(Context context) {
super(context);
ourRenderer = new OurRenderer();
setRenderer(ourRenderer);
ourRenderer.autoRotate=true;
setRenderMode(GLSurfaceView.RENDERMODE_CONTINUOUSLY);
}
@Override
public boolean onTouchEvent(MotionEvent event) {
float x = event.getX();
float y = event.getY();
float p1x, p1y, p2x, p2y;
// normalize mouse positions
p1x = (2.0f * OLD_MOUSE_X - WINDOW_W) / WINDOW_W;
p1y = (WINDOW_H - 2.0f * OLD_MOUSE_Y) / WINDOW_H;
p2x = (2.0f * x - WINDOW_W) / WINDOW_W;
p2y = (WINDOW_H - 2.0f * y) / WINDOW_H;
switch (event.getAction() & MotionEvent.ACTION_MASK) {
case MotionEvent.ACTION_DOWN:
touchState = ROTATE;
OLD_MOUSE_X = (int) x;
OLD_MOUSE_Y = (int) y;
break;
case MotionEvent.ACTION_POINTER_DOWN:
// secondary touch event starts: remember distance
oldDistance = (int) calcDistance(event);
// and midpoint
calcMidpoint(event);
oldCenterX = centerX;
oldCenterY = centerY;
if (oldDistance > MIN_DIST) {
if (guiZoom) {
touchState = ZOOM;
} else {
touchState = PAN;
}
}
break;
case MotionEvent.ACTION_MOVE:
if (touchState == ROTATE) {
// single finger rotate
Trackball.trackball(LAST_QUATERNION, p1x, p1y,
p2x, p2y);
OLD_MOUSE_X = (int) x;
OLD_MOUSE_Y = (int) y;
Trackball.add_quats(LAST_QUATERNION,
CURRENT_QUATERNION, CURRENT_QUATERNION);
requestRender();
} else if (touchState == ZOOM) {
// double-finger zoom, zoom depends on changing
distance
int dist = (int) calcDistance(event);
if (dist > MIN_DIST) {
if (dist > oldDistance)
EYE_DISTANCE -= EYE_DISTANCE_INC;
else if (dist < oldDistance)
EYE_DISTANCE += EYE_DISTANCE_INC;
oldDistance = dist;
requestRender();
}
} else if (touchState == PAN) {
int dist = (int) calcDistance(event);
calcMidpoint(event);
if (dist > MIN_DIST) {
if (centerX > oldCenterX)
PAN_X -= PAN_INC;
if (centerX < oldCenterX)
PAN_X += PAN_INC;
if (centerY > oldCenterY)
PAN_Y += PAN_INC;
if (centerY < oldCenterY)
PAN_Y -= PAN_INC;
oldCenterX = centerX;
oldCenterY = centerY;
requestRender();
}
}
break;
case MotionEvent.ACTION_UP:
touchState = NONE;
break;
case MotionEvent.ACTION_POINTER_UP:
touchState = ROTATE;
// update touch down location for drag event to holding finger
switch (event.getActionIndex()) {
case 0:
OLD_MOUSE_X = (int) event.getX(1);
OLD_MOUSE_Y = (int) event.getY(1);
break;
case 1:
OLD_MOUSE_X = (int) event.getX(0);
OLD_MOUSE_Y = (int) event.getY(0);
break;
}
break;
}
return true;
}
private float calcDistance(MotionEvent event) {
float x = event.getX(0) - event.getX(1);
float y = event.getY(0) - event.getY(1);
return FloatMath.sqrt(x * x + y * y);
}
private void calcMidpoint(MotionEvent event) {
centerX = (int) ((event.getX(0) + event.getX(1)) / 2);
centerY = (int) ((event.getY(0) + event.getY(1)) / 2);
}
// the implementation of the renderer interface
private class OurRenderer implements GLSurfaceView.Renderer {
//Declaration of some variables for our planets and moons
private Sphere sun;
private Sphere merkur;
private Sphere venus;
private Sphere erde;
private Sphere neptun;
private Sphere uranus;
private Sphere saturn;
private Sphere jupiter;
private long milSecPerRotation=20*1000;
private double angle=0.0f;
private long lastTime;
public boolean autoRotate=true;
public OurRenderer() {
// Defining our planets and moons
// spheres along z-axis with lightning
// radius: the radius of the sphere
// slices: the number of subdivisions along the z-axis
// stacks: the number of subdivisions around the z-axis
sun = new Sphere(4.0f, 10, 10);
merkur = new Sphere(0.5f, 10,10);
venus = new Sphere(0.9f, 10,10);
erde = new Sphere(1.0f, 10,10);
neptun = new Sphere(1.5f, 10,10);
uranus = new Sphere(1.5f, 10,10);
saturn = new Sphere(2.5f, 10,10);
jupiter = new Sphere(3.0f, 10,10);
}
public void onDrawFrame(GL10 gl) {
// the first thing to do: clear screen and depth buffer
gl.glClear(GL10.GL_COLOR_BUFFER_BIT | GL10.GL_DEPTH_BUFFER_BIT);
// reset modelview matrix
gl.glMatrixMode(GL10.GL_MODELVIEW);
gl.glLoadIdentity();
// set ambient light color
float model_ambient[] = { 0.5f, 0.5f, 0.5f, 1.0f };
ByteBuffer bb1 = ByteBuffer.allocateDirect(model_ambient.length * 4);
bb1.order(ByteOrder.nativeOrder());
FloatBuffer fb1 = bb1.asFloatBuffer();
fb1.put(model_ambient);
fb1.position(0);
gl.glLightModelfv(GL10.GL_LIGHT_MODEL_AMBIENT, fb1);
// set light position of LIGHT0
float light_position[] = { 1.0f, 1.0f, 1.0f, 0.0f };
ByteBuffer bb2 = ByteBuffer.allocateDirect(light_position.length * 4);
bb2.order(ByteOrder.nativeOrder());
FloatBuffer fb2 = bb2.asFloatBuffer();
fb2.put(light_position);
fb2.position(0);
gl.glLightfv(GL10.GL_LIGHT0, GL10.GL_POSITION, fb2);
// enable ligth and lighting
gl.glEnable(GL10.GL_LIGHT0);
gl.glEnable(GL10.GL_LIGHTING);
// manipulate modelview matrix by setting viewing transformation
gl.glTranslatef(-PAN_X, -PAN_Y, -EYE_DISTANCE);
Trackball.build_rotmatrix(TRANSFORM_MATRIX, CURRENT_QUATERNION);
gl.glMultMatrixf(TRANSFORM_MATRIX, 0);
gl.glEnableClientState(GL10.GL_VERTEX_ARRAY);
gl.glEnableClientState(GL10.GL_NORMAL_ARRAY);
gl.glEnableClientState(GL10.GL_COLOR_ARRAY);
gl.glColor4x(65536, 0, 0, 65536);
// create an automatic rotation
long time = System.currentTimeMillis();
long deltaTime = time-lastTime;
lastTime=time;
if (autoRotate) {
angle = (float) (angle + 360.0 / milSecPerRotation *
deltaTime);
if (angle > 360.0f)
angle -= 360;
}
//Building the planets and moons and defining position, rotation and
color
gl.glPushMatrix();
gl.glColor4f(1.0f, 0.0f, 0.0f, 1.0f);
sun.draw(gl);
gl.glPopMatrix();
gl.glPushMatrix();
gl.glTranslatef(0.0f, 8.0f, 0.0f);
gl.glRotatef((float) angle, 0.0f, 0.0f, -1.0f);
merkur.draw(gl);
gl.glPopMatrix();
gl.glPushMatrix();
gl.glTranslatef(0.0f, 16.0f, 0.0f);
gl.glRotatef((float) angle, 0.0f, 0.0f, -1.0f);
venus.draw(gl);
gl.glPopMatrix();
gl.glPushMatrix();
gl.glTranslatef(0.0f, 24.0f, 0.0f);
gl.glRotatef((float) angle, 0.0f, 0.0f, -1.0f);
erde.draw(gl);
gl.glPopMatrix();
gl.glPushMatrix();
gl.glTranslatef(0.0f, 32.0f, 0.0f);
gl.glRotatef((float) angle, 0.0f, 0.0f, -1.0f);
neptun.draw(gl);
gl.glPopMatrix();
gl.glPushMatrix();
gl.glTranslatef(0.0f, 40.0f, 0.0f);
gl.glRotatef((float) angle, 0.0f, 0.0f, -1.0f);
uranus.draw(gl);
gl.glPopMatrix();
gl.glPushMatrix();
gl.glTranslatef(0.0f, 48.0f, 0.0f);
gl.glRotatef((float) angle, 0.0f, 0.0f, -1.0f);
saturn.draw(gl);
gl.glPopMatrix();
gl.glPushMatrix();
gl.glTranslatef(0.0f, 56.0f, 0.0f);
gl.glRotatef((float) angle, 0.0f, 0.0f, -1.0f);
jupiter.draw(gl);
gl.glPopMatrix();
}
// resize of viewport
// set projection matrix
public void onSurfaceChanged(GL10 gl, int width, int height) {
gl.glViewport(0, 0, width, height);
float aspectRatio = (float) width / height;
gl.glMatrixMode(GL10.GL_PROJECTION);
gl.glLoadIdentity();
GLU.gluPerspective(gl, 45.0f, aspectRatio, zNear, zFar);
GLU.gluLookAt(gl, 0.0f, 0.0f, 5.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f,
0.0f);
gl.glMatrixMode(GL10.GL_MODELVIEW);
lastTime = System.currentTimeMillis();
}
// creation of viewport
// initialization of some opengl features
public void onSurfaceCreated(GL10 gl, EGLConfig config) {
gl.glDisable(GL10.GL_DITHER);
gl.glHint(GL10.GL_PERSPECTIVE_CORRECTION_HINT, GL10.GL_FASTEST);
gl.glClearColor(0, 0, 0, 1);
gl.glEnable(GL10.GL_CULL_FACE);
gl.glShadeModel(GL10.GL_SMOOTH);
//gl.glShadeModel(GL10.GL_FLAT);
gl.glEnable(GL10.GL_DEPTH_TEST);
resetViewing();
}
}
// reset of view parameters
static void resetViewing() {
EYE_DISTANCE = 0.5f;
EYE_DISTANCE_INC = 0.5f;
PAN_X = 0.0f;
PAN_Y = 0.0f;
PAN_INC = 0.1f;
// trackball init
Trackball.trackball(CURRENT_QUATERNION, 0.0f, 0.0f, 0.0f, 0.0f);
}
}