/** * @(#) rings.java * @(#) author: Philip Winston (converted to Java by Ron Cemer) */ /* * Homework 4, Part 1: perspective, hierarchical coords, moving eye pos. * * Do a slow zoom on a bunch of rings (ala Superman III?) * * Philip Winston - 2/21/95 * pwinston@hmc.edu * http://www.cs.hmc.edu/people/pwinston * */ import java.applet.*; import java.awt.*; import java.awt.event.*; import java.lang.*; import java.util.*; import java.io.*; import java.util.*; import gl4java.GLContext; import gl4java.awt.GLAnimCanvas; import gl4java.applet.SimpleGLAnimApplet1; public class rings extends SimpleGLAnimApplet1 { /* Initialize the applet */ public void init() { super.init(); Dimension d = getSize(); canvas = new ringsCanvas(d.width, d.height); add("Center", canvas); } /* Local GLAnimCanvas extension class */ private class ringsCanvas extends GLAnimCanvas implements MouseListener, ActionListener { private final double M_PI = 3.14159265; private final String MENU_STARTOVER = "Start Over"; private final String MENU_ZOOM_OUT = "Zoom Out"; private final String MENU_START_RINGS = "Start rings"; private final String MENU_STOP_RINGS = "Stop rings"; private final String MENU_START_FADE = "Start fade"; private final String MENU_STOP_FADE = "Stop fade"; private final int CONE = 1, TORUS = 2, INNERMAT = 3, OUTTERMAT = 4; private final double STEPS = 30.0; private PopupMenu menu = null; private boolean menu_showing = false; private boolean save_suspended = false; private boolean Fade = true; /* Start moving out */ private float Axis = 0.0f; private float AxisInc = (float)(2.0 * M_PI / STEPS); private float InnerRad, OutterRad, Tilt, Trans, TransCone, Dist; public ringsCanvas(int w, int h) { super(w, h); GLContext.gljNativeDebug = false; GLContext.gljClassDebug = false; setAnimateFps(30.0); } public void preInit() { doubleBuffer = true; stereoView = false; } public void init() { System.out.println("init(): " + this); reshape(getSize().width, getSize().height); float sinoftilt; InnerRad = 0.70f; OutterRad = 5.0f; Tilt = 15.0f; Dist = 10.0f; sinoftilt = (float)Math.sin(Tilt * M_PI*2.0/360.0); Trans = (float) ((2.0f*OutterRad + InnerRad) * sinoftilt + InnerRad + ((1 - sinoftilt) * InnerRad) - (InnerRad * 0.1)); TransCone = Trans + (OutterRad * sinoftilt + InnerRad); /* I used code from the book's accnot.c as a starting point for lighting. I have one positional light in center, then one directional */ float light0_position[] = { 1.0f, 0.2f, 1.0f, 0.0f }; float light1_position[] = { 0.0f, 0.0f, 0.0f, 1.0f }; float light1_diffuse[] = { 1.0f, 1.0f, 1.0f, 1.0f }; float light1_specular[] = { 1.0f, 1.0f, 1.0f, 1.0f }; float lm_ambient[] = { 0.2f, 0.2f, 0.2f, 1.0f }; gl.glEnable(GL_NORMALIZE); gl.glMatrixMode(GL_PROJECTION); gl.glLoadIdentity(); gl.glMatrixMode(GL_MODELVIEW); gl.glLoadIdentity(); gl.glLightfv(GL_LIGHT0, GL_POSITION, light0_position); gl.glLightfv(GL_LIGHT1, GL_POSITION, light1_position); gl.glLightfv(GL_LIGHT1, GL_DIFFUSE, light1_diffuse); gl.glLightfv(GL_LIGHT1, GL_SPECULAR, light1_specular); gl.glLightf(GL_LIGHT1, GL_LINEAR_ATTENUATION, 0.2f); gl.glLightModelfv(GL_LIGHT_MODEL_AMBIENT, lm_ambient); gl.glEnable(GL_LIGHTING); gl.glEnable(GL_LIGHT0); gl.glEnable(GL_LIGHT1); gl.glDepthFunc(GL_LESS); gl.glEnable(GL_DEPTH_TEST); // Make display lists float cone_diffuse[] = { 0.0f, 0.7f, 0.7f, 1.0f }; float mat1_ambient[] = { 1.0f, 1.0f, 1.0f, 1.0f }; float mat2_ambient[] = { 0.0f, 0.0f, 0.0f, 0.0f }; float torus1_diffuse[] = { 0.7f, 0.7f, 0.0f, 1.0f }; float torus2_diffuse[] = { 0.3f, 0.0f, 0.0f, 1.0f }; float mat1_specular[] = { 1.0f, 1.0f, 1.0f, 1.0f }; float mat2_specular[] = { 0.5f, 0.5f, 0.5f, 1.0f }; gl.glNewList(INNERMAT, GL_COMPILE); gl.glMaterialfv(GL_FRONT, GL_SPECULAR, mat1_specular); gl.glMaterialf(GL_FRONT, GL_SHININESS, 50.0f); gl.glMaterialfv(GL_FRONT, GL_DIFFUSE, torus1_diffuse); gl.glMaterialfv(GL_FRONT, GL_AMBIENT, mat1_ambient); gl.glEndList(); gl.glNewList(OUTTERMAT, GL_COMPILE); gl.glMaterialfv(GL_FRONT, GL_SPECULAR, mat2_specular); gl.glMaterialf(GL_FRONT, GL_SHININESS, 25.0f); gl.glMaterialfv(GL_FRONT, GL_DIFFUSE, torus2_diffuse); gl.glMaterialfv(GL_FRONT, GL_AMBIENT, mat2_ambient); gl.glEndList(); gl.glNewList(CONE, GL_COMPILE); gl.glMaterialfv(GL_FRONT, GL_DIFFUSE, cone_diffuse); gl.glPushMatrix(); gl.glTranslatef(0, -TransCone, 0); gl.glRotatef(90, 1, 0, 0); glutSolidCone(OutterRad, 10, 8, 8); gl.glPopMatrix(); gl.glEndList(); gl.glNewList(TORUS, GL_COMPILE); gl.glPushMatrix(); gl.glRotatef(90, 1, 0, 0); glutSolidTorus(InnerRad, OutterRad, 15, 25); gl.glPopMatrix(); gl.glEndList(); glj.gljCheckGL(); menu = new PopupMenu("Options"); menu.add(MENU_STARTOVER); menu.add(MENU_ZOOM_OUT); menu.add(MENU_START_RINGS); menu.add(MENU_STOP_RINGS); menu.add(MENU_START_FADE); menu.add(MENU_STOP_FADE); menu.addActionListener(this); add(menu); addMouseListener(this); } public void doCleanup() { System.out.println("destroy(): " + this); removeMouseListener(this); menu.removeActionListener(this); } public void reshape(int width, int height) { gl.glViewport(0,0,width,height); } public void display() { if (glj.gljMakeCurrent() == false) return; Axis += AxisInc; if ( (Dist < 15.0f) && (Fade) ) /* start slow */ Dist += 0.1f; else if ( (Dist < 800.0f) && (Fade) ) /* don't go back too far */ Dist *= 1.005f; gl.glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); gl.glMatrixMode(GL_PROJECTION); gl.glLoadIdentity(); gl.glFrustum(-1.0f,1.0f,-1.0f,1.0f,10.0f,1000.0f); glu.gluLookAt(0.0f,0.0f,Dist,0.0f,0.0f,0.0f,0.0f,1.0f,0.0f); gl.glMatrixMode(GL_MODELVIEW); gl.glCallList(INNERMAT); DrawRings(Axis); gl.glCallList(CONE); gl.glCallList(OUTTERMAT); gl.glPushMatrix(); gl.glScalef(10, 10, 10); DrawRings(Axis/3.0f); gl.glPopMatrix(); glj.gljSwap(); glj.gljCheckGL(); glj.gljFree(); //if (!isSuspended()) repaint(); // Animate at full speed. } // Methods required for the implementation of MouseListener public void mouseEntered(MouseEvent evt) { } public void mouseExited(MouseEvent evt) { } public void mousePressed(MouseEvent evt) { // If user presses right mouse button within canvas area, // suspend animation and pop up menu. // If menu was already popped up and user presses either // mouse button within canvas area, resume animation // because the menu will have been removed automatically. if (!menu_showing) { if ((evt.getModifiers() & evt.BUTTON3_MASK) != 0) { menu_showing = true; save_suspended = isSuspended(); if (!save_suspended) { setSuspended(true); repaint(100); try { Thread.currentThread().sleep(200); } catch (Exception e) { } } menu.show(this,evt.getX(),evt.getY()); } } else { menu_showing = false; setSuspended(save_suspended); } } public void mouseReleased(MouseEvent evt) { } public void mouseClicked(MouseEvent evt) { } // Method required for the implementation of ActionListener public void actionPerformed(ActionEvent evt) { String c = evt.getActionCommand(); if (c.equals(MENU_STARTOVER)) { Dist = 10.0f; Axis = 0.0f; Fade = true; AxisInc = (float)(2.0 * M_PI / STEPS); } else if (c.equals(MENU_ZOOM_OUT)) { Dist = 800.0f; } else if (c.equals(MENU_START_RINGS)) { AxisInc = (float)(2.0 * M_PI / STEPS); } else if (c.equals(MENU_STOP_RINGS)) { AxisInc = 0.0f; } else if (c.equals(MENU_START_FADE)) { Fade = true; } else if (c.equals(MENU_STOP_FADE)) { Fade = false; } if (menu_showing) { menu_showing = false; setSuspended(save_suspended); } } /* Draw three rings, rotated and translate so they look cool */ private void DrawRings(float axis) { float x = (float)Math.sin(axis), y = (float)Math.cos(axis); gl.glPushMatrix(); gl.glTranslatef(0.0f, Trans, 0.0f); gl.glRotatef(Tilt, x, 0.0f, y); gl.glCallList(TORUS); gl.glPopMatrix(); gl.glPushMatrix(); gl.glRotatef(-Tilt, x, 0.0f, y); gl.glCallList(TORUS); gl.glPopMatrix(); gl.glPushMatrix(); gl.glTranslatef(0.0f, -Trans, 0.0f); gl.glRotatef(Tilt, x, 0.0f, y); gl.glCallList(TORUS); gl.glPopMatrix(); } // Imported from glut. private void glutSolidTorus (float innerRadius, float outerRadius, int nsides, int rings) { doughnut(innerRadius, outerRadius, nsides, rings); } // Imported from glut. private void glutSolidCone (float base, float height, int slices, int stacks) { long qobj = glu.gluNewQuadric(); glu.gluQuadricDrawStyle(qobj,GLU_FILL); glu.gluQuadricNormals(qobj,GLU_SMOOTH); glu.gluCylinder(qobj,base,0.0f,height,slices,stacks); glu.gluDeleteQuadric(qobj); } // Imported from glut. private void doughnut(float r, float R, int nsides, int rings) { int i, j; float theta, phi, theta1; float cosTheta, sinTheta; float cosTheta1, sinTheta1; float ringDelta, sideDelta; ringDelta = 2.0f * (float)M_PI / rings; sideDelta = 2.0f * (float)M_PI / nsides; theta = 0.0f; cosTheta = 1.0f; sinTheta = 0.0f; for (i = rings - 1; i >= 0; i--) { theta1 = theta + ringDelta; cosTheta1 = (float)Math.cos(theta1); sinTheta1 = (float)Math.sin(theta1); gl.glBegin(GL_QUAD_STRIP); phi = 0.0f; for (j = nsides; j >= 0; j--) { float cosPhi, sinPhi, dist; phi += sideDelta; cosPhi = (float)Math.cos(phi); sinPhi = (float)Math.sin(phi); dist = R + r * cosPhi; gl.glNormal3f(cosTheta1 * cosPhi, -sinTheta1 * cosPhi, sinPhi); gl.glVertex3f(cosTheta1 * dist, -sinTheta1 * dist, r * sinPhi); gl.glNormal3f(cosTheta * cosPhi, -sinTheta * cosPhi, sinPhi); gl.glVertex3f(cosTheta * dist, -sinTheta * dist, r * sinPhi); } gl.glEnd(); theta = theta1; cosTheta = cosTheta1; sinTheta = sinTheta1; } } } }