NEVERMIND! I figured it out, and it is so stupid.
All through the openGL programming guide so far (ch. 8) (correct me if I am wrong), it NEVER mentioned glutPostRedisplay(), and I must have overlooked it in the example programs; I just assumed that it automatically redisplayed everything (I would never usually asume stuff like that, but I overlooked it, and it just seemed to redisplay automatically)
ANYWAYS, here is the corrected code, which I think is very good (if know java, you could use this; it is a great setup for hierchial models with movable parts; subclass it to define one specific model (you can still create as many sperate instances as you want of such a defined model, each with its parts in their own place), or you can just create an instance of the class to quickly use and define one model) (I use jGL, which looks VERY similar to GL4JAVA; they seem to be the best; java is good to use OpenGL with because it is so easy and fast to use, and OpenGL is fast by itself anyways):
/* glAbstractModel.java
* -created by Dan Cook
*
* Represents an OOP 3D model for use with jGL (a great java
* binding for OpenGL). To use glAbstractModel, create a new
* instance of it and fill in the draw() method with commands
* to draw the object (these should be jGL commands so that a
* call to getList() can store the whole drawing process into
* a display list to improve efficiency when the object is
* rendered). The other methods are all "final" because they
* do not need to be modified/changed.
*
* Call render() to render the model with all of its [movable]
* parts. Calling addPart() or setPart() add/set a part with
* the current transformation of GL_MODELVIEW_MATRIX (to use a
* default transformation, call glLoadIdentity() before you add
* or modify a part; this is done automatically for parts that
* are specified in the constructor).
*
* Points are included so that you can reference the same ones;
* that does not make much difference, but it does same memory
* in that you do not have to redeclare every point in the draw
* method.
*
* Transformation matrices (array of 16 = 4x4 matrix) are used
* to represent the transformation of each of the movable parts;
* the reason that each glAbstractModel does not just have its
* own transformation is because they are only needed for the
* movable parts and NOT for the model itself (transformation of
* the model can be done by transforming the model/view matrix,
* or from a specified transformation because the model is part
* of another model). "Nonmovable parts" should be drawn as part
* of the model because there is no need for the extra recursion
* and GL commands where they are not neccessary.
*/
import jgl.GL;
public abstract class glAbstractModel {
public GL myGL;
public float[][] points;
public glAbstractModel[] parts;
public float[][] transform;
private boolean set;
private int list;
public glAbstractModel(GL gl, float[][] pts) {
myGL = gl;
points = pts;
parts = new glAbstractModel[0];
transform = new float[0][];
set = false;
}
public glAbstractModel(GL gl, float[][] pts, glAbstractModel[] prts) {
myGL = gl;
points = pts;
parts = prts;
transform = new float[parts.length][];
resetPart(0);
for(int i=1; i<transform.length; i++)
transform[i] = transform[0];
set = false;
}
protected abstract void draw();
public final void render() {
draw();
for(int i=0; i<parts.length; i++) {
myGL.glPushMatrix();
myGL.glMultMatrixf(transform[i]);
parts[i].render();
myGL.glPopMatrix();
}
}
public boolean isList() {
return set;
}
public final int getList() {
if(set)
return list;
list = myGL.glGenLists(1);
myGL.glNewList(list,myGL.GL_COMPILE);
render();
myGL.glEndList();
set = true;
return list;
}
public final void deleteList() {
if(set) myGL.glDeleteLists(list,1);
set = false;
}
public final void deleteLists() {
deleteList();
for(int i=0; i<parts.length; i++)
parts[i].deleteLists();
}
public final void loadPart(int part) {
myGL.glLoadMatrixf(transform[part]);
}
public final void setPart(int part) {
myGL.glGetFloatv(myGL.GL_MODELVIEW_MATRIX, transform[part]);
}
public final void setPart(int part, glAbstractModel model) {
parts[part] = model;
setPart(part);
}
public final void resetPart(int part) {
myGL.glPushMatrix();
myGL.glLoadIdentity();
myGL.glGetFloatv(myGL.GL_MODELVIEW_MATRIX, transform[part]);
myGL.glPopMatrix();
}
public final void addPart(glAbstractModel part) {
int size = parts.length;
glAbstractModel[] prts = new glAbstractModel[size+1];
float[][] trnsfrm = new float[size+1][];
for(int i=0; i<size; i++) {
prts[i] = parts[i];
trnsfrm[i] = transform[i];
}
parts = prts;
parts[size] = part;
transform = trnsfrm;
resetPart(size);
}
public final void deletePart(int part) {
int size = parts.length-1;
glAbstractModel[] prts = new glAbstractModel[size];
float[][] trnsfrm = new float[size][];
for(int i=0; i<part; i++) {
prts[i] = parts[i];
trnsfrm[i] = transform[i];
}
for(int i=part; i<size; i++) {
prts[i] = parts[i+1];
trnsfrm[i] = transform[i+1];
}
parts = prts;
trnsfrm = transform;
}
public final glAbstractModel removePart(int part) {
glAbstractModel removed = parts[part];
deletePart(part);
return removed;
}
}
/* test.java
*
* a simple program to test
* the glAbstractModel class
*/
import jgl.GL;
import jgl.GLCanvas;
import java.awt.Frame;
public class test extends GLCanvas {
public glAbstractModel model;
public int xAngle;
public int yAngle;
public void myinit() {
xAngle = 0;
yAngle = 0;
float[] mat_specular = {1.0f, 1.0f, 1.0f, 1.0f};
float[] mat_shininess = {50.0f};
float[] light_position = {1.0f, 1.0f, 1.0f, 0.0f};
myGL.glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
myGL.glShadeModel(GL.GL_SMOOTH);
myGL.glMaterialfv(GL.GL_FRONT, GL.GL_SPECULAR, mat_specular);
myGL.glMaterialfv(GL.GL_FRONT, GL.GL_SHININESS, mat_shininess);
myGL.glLightfv(GL.GL_LIGHT0, GL.GL_POSITION, light_position);
myGL.glEnable(GL.GL_LIGHTING);
myGL.glEnable(GL.GL_LIGHT0);
myGL.glEnable(GL.GL_DEPTH_TEST);
model = new glAbstractModel(
myGL,
new float[][] {
{ 1.0f, 1.0f, 1.0f},{ 1.0f, 1.0f,-1.0f},
{ 1.0f,-1.0f, 1.0f},{ 1.0f,-1.0f,-1.0f},
{-1.0f, 1.0f, 1.0f},{-1.0f, 1.0f,-1.0f},
{-1.0f,-1.0f, 1.0f},{-1.0f,-1.0f,-1.0f}
}
) {
public void draw() {
myGL.glBegin(myGL.GL_QUAD_STRIP);
myGL.glNormal3fv(points[0]);
myGL.glVertex3fv(points[0]);
myGL.glNormal3fv(points[1]);
myGL.glVertex3fv(points[1]);
myGL.glNormal3fv(points[2]);
myGL.glVertex3fv(points[2]);
myGL.glNormal3fv(points[3]);
myGL.glVertex3fv(points[3]);
myGL.glNormal3fv(points[6]);
myGL.glVertex3fv(points[6]);
myGL.glNormal3fv(points[7]);
myGL.glVertex3fv(points[7]);
myGL.glNormal3fv(points[4]);
myGL.glVertex3fv(points[4]);
myGL.glNormal3fv(points[5]);
myGL.glVertex3fv(points[5]);
myGL.glNormal3fv(points[0]);
myGL.glVertex3fv(points[0]);
myGL.glNormal3fv(points[1]);
myGL.glVertex3fv(points[1]);
myGL.glEnd();
myGL.glBegin(myGL.GL_QUADS);
myGL.glNormal3fv(points[0]);
myGL.glVertex3fv(points[0]);
myGL.glNormal3fv(points[4]);
myGL.glVertex3fv(points[4]);
myGL.glNormal3fv(points[6]);
myGL.glVertex3fv(points[6]);
myGL.glNormal3fv(points[2]);
myGL.glVertex3fv(points[2]);
myGL.glNormal3fv(points[1]);
myGL.glVertex3fv(points[1]);
myGL.glNormal3fv(points[3]);
myGL.glVertex3fv(points[3]);
myGL.glNormal3fv(points[7]);
myGL.glVertex3fv(points[7]);
myGL.glNormal3fv(points[5]);
myGL.glVertex3fv(points[5]);
myGL.glEnd();
}
};
myGL.glTranslatef(0.0f, 0.0f, 2.0f);
}
public void display() {
myGL.glClear(GL.GL_COLOR_BUFFER_BIT | GL.GL_DEPTH_BUFFER_BIT);
myGL.glPushMatrix();
myGL.glRotatef(xAngle, 1.0f, 0.0f, 0.0f);
myGL.glRotatef(yAngle, 0.0f, 1.0f, 0.0f);
model.render();
myGL.glPopMatrix();
myGL.glFlush();
}
public void myReshape (int w, int h) {
myGL.glViewport(0, 0, w, h);
myGL.glMatrixMode(GL.GL_PROJECTION);
myGL.glLoadIdentity();
if (w <= h)
myGL.glOrtho(
-5.0f, 5.0f,
-5.0f *(float)h/(float)w,
5.0f *(float)h/(float)w,
-5.0f, 5.0f
);
else
myGL.glOrtho(
-5.0f *(float)w/(float)h,
5.0f *(float)w/(float)h,
-5.0f, 5.0f,
-5.0f, 5.0f
);
myGL.glMatrixMode(GL.GL_MODELVIEW);
myGL.glLoadIdentity();
}
public void keyboard(char key, int x, int y) {
switch (key) {
case 'x': xAngle = (xAngle+5)%360; break;
case 'X': xAngle = (xAngle-5)%360; break;
case 'y': yAngle = (yAngle+5)%360; break;
case 'Y': yAngle = (yAngle-5)%360; break;
case 27: System.exit(0);
default: return;
}
myUT.glutPostRedisplay();
}
public void init() {
myUT.glutInitWindowSize(500,500);
myUT.glutInitWindowPosition(0,0);
myUT.glutCreateWindow(this);
myinit();
myUT.glutDisplayFunc("display");
myUT.glutReshapeFunc("myReshape");
myUT.glutKeyboardFunc("keyboard");
myUT.glutMainLoop();
}
public static void main (String args[]) {
Frame mainFrame = new Frame();
mainFrame.setSize(508,527);
test mainCanvas = new test();
mainCanvas.init();
mainFrame.add(mainCanvas);
mainFrame.setVisible(true);
}
}