#!/usr/bin/newlisp # # SimpleAnim.c # # Example program illustrating a simple use # of OpenGL to animate motion. Creates rotating # overlapping triangles. # # Author: Samuel R. Buss # # Software accompanying the book # 3D Computer Graphics: A Mathematical Introduction with OpenGL, # by S. Buss, Cambridge University Press, 2003. # # Software is "as-is" and carries no warranty. It may be used without # restriction, but if you modify it, please change the filenames to # prevent confusion between different versions. # Bug reports: Sam Buss, sbuss@ucsd.edu. # Web page: http://math.ucsd.edu/~sbuss/MathCG # # USAGE: # Press "r" key to toggle (off and on) running the animation # Press "s" key to single-step animation # The up arrow key and down array key control the # time step used in the animation rate. Each key # press multiplies or divides the times by a factor # of sqrt(2). # Press ESCAPE to exit. # #------------------------------------------------------------------- # Ported to newLisp by Peter van Eerten. # # This is a 1-to-1 port of the original program. # October 18, 2005. #------------------------------------------------------------------- (load "GL.lsp" "freeglut.lsp") (set 'RunMode 1) # Used as a boolean (1 or 0) for "on" and "off" # The next global variable controls the animation's state and speed. (set 'CurrentAngle (flt 0.0)) # Angle in degrees (set 'AnimateStep (flt 3.0)) # Rotation step per update # These variables set the dimensions of the rectanglar region we wish to view. (constant 'Xmin (float 0.0)) (constant 'Xmax (float 3.0)) (constant 'Ymin (float 0.0)) (constant 'Ymax (float 3.0)) # glutKeyboardFunc is called below to set this function to handle # all "normal" key presses. (define (myKeyboardFunc key x y) (case key (114: #'r' (set 'RunMode (- 1 RunMode)) # Toggle to opposite value (if (= RunMode 1) (GLUT:glutPostRedisplay) ) ) (115: #'s' (set 'RunMode 1) (drawScene) (set 'RunMode 0) ) (27: # Escape key (exit) ) ) ) # glutSpecialFunc is called below to set this function to handle # all "special" key presses. See glut.h for the names of # special keys. (define (mySpecialKeyFunc key x y) (case key (0x0065: #GLUT_KEY_UP (if (< AnimateStep 1.0e3) # Avoid overflow problems (set 'AnimateStep (mul AnimateStep (sqrt 2.0))) # Increase the angle increment ) ) (0x0067: #GLUT_KEY_DOWN (if (> AnimateStep 1.0e-6) # Avoid underflow problems. (set 'AnimateStep (div AnimateStep (sqrt 2.0))) # Decrease the angle increment ) ) ) ) # drawScene() handles the animation and the redrawing of the # graphics window contents. (define (drawScene) # Clear the rendering window (GL:glClear (| GL:GL_COLOR_BUFFER_BIT GL:GL_DEPTH_BUFFER_BIT)) (if (= RunMode 1) (begin # Calculate animation parameters (set 'CurrentAngle (add CurrentAngle AnimateStep)) (if (> CurrentAngle 360.0) (set 'CurrentAngle (sub CurrentAngle (mul 360.0 (int (div CurrentAngle 360.0))))) # Don't allow overflow ) ) ) # Rotate the image (GL:glMatrixMode GL:GL_MODELVIEW) # Current matrix affects objects positions (GL:glLoadIdentity) # Initialize to the identity (GL:glTranslatef (flt 1.5) (flt 1.5) (flt 0.0)) # Translate rotation center from origin (GL:glRotatef (flt CurrentAngle) (flt 0.0) (flt 0.0) (flt 1.0)) # Rotate through animation angle (GL:glTranslatef (flt -1.5) (flt -1.5) (flt 0.0)) # Translate rotation center to origin # Draw three overlapping triangles of different colors (GL:glBegin GL:GL_TRIANGLES) (GL:glColor3f (flt 1.0) (flt 0.0) (flt 0.0)) (GL:glVertex3f (flt 0.3) (flt 1.0) (flt 0.5)) (GL:glVertex3f (flt 2.7) (flt 0.85) (flt 0.0)) (GL:glVertex3f (flt 2.7) (flt 1.15) (flt 0.0)) (GL:glColor3f (flt 0.0) (flt 1.0) (flt 0.0)) (GL:glVertex3f (flt 2.53) (flt 0.71) (flt 0.5)) (GL:glVertex3f (flt 1.46) (flt 2.86) (flt 0.0)) (GL:glVertex3f (flt 1.2) (flt 2.71) (flt 0.0)) (GL:glColor3f (flt 0.0) (flt 0.0) (flt 1.0)) (GL:glVertex3f (flt 1.667) (flt 2.79) (flt 0.5)) (GL:glVertex3f (flt 0.337) (flt 0.786) (flt 0.0)) (GL:glVertex3f (flt 0.597) (flt 0.636) (flt 0.0)) (GL:glEnd) # Flush the pipeline, swap the buffers (GL:glFlush) (GLUT:glutSwapBuffers) (if (= RunMode 1) (GLUT:glutPostRedisplay) # Trigger an automatic redraw for animation ) ) # Initialize OpenGL's rendering modes (define (initRendering) (GL:glShadeModel GL_FLAT) # The default value of GL_SMOOTH is usually better (GL:glEnable GL_DEPTH_TEST) # Depth testing must be turned on ) # Called when the window is resized # w, h - width and height of the window in pixels. (define (resizeWindow w h) # Define the portion of the window used for OpenGL rendering. (GL:glViewport 0 0 w h) # View port uses whole window # Set up the projection view matrix: orthographic projection # Determine the min and max values for x and y that should appear in the window. # The complication is that the aspect ratio of the window may not match the # aspect ratio of the scene we want to view. (if (= w 0) (set 'w 1)) (if (= h 0) (set 'h 1)) (if (< (div (sub Xmax Xmin) w) (div (sub Ymax Ymin) h) ) (begin (set 'scale (div (div (sub Ymax Ymin) h) (div (sub Xmax Xmin) w))) (set 'center (div (add Xmax Xmin) 2)) (set 'windowXmin (sub center (mul (sub center Xmin) scale))) (set 'windowXmax (add center (mul (sub Xmax center) scale))) (set 'windowYmin Ymin) (set 'windowYmax Ymax) ) (begin (set 'scale (div (div (sub Xmax Xmin) w) (div (sub Ymax Ymin) h))) (set 'center (div (add Ymax Ymin) 2)) (set 'windowYmin (sub center (mul (sub center Ymin) scale))) (set 'windowYmax (add center (mul (sub Ymax center) scale))) (set 'windowXmin Xmin) (set 'windowXmax Xmax) ) ) # Now that we know the max & min values for x & y # that should be visible in the window, # we set up the orthographic projection. (GL:glMatrixMode GL:GL_PROJECTION) (GL:glLoadIdentity) (GL:glOrtho (float windowXmin) (float windowXmax) (float windowYmin) (float windowYmax) (float -1) (float 1)) ) # Main routine # Set up OpenGL, define the callbacks and start the main loop (define (main argc argv) (GLUT:glutInit (address argc) (address argv)) # We're going to animate it, so double buffer (GLUT:glutInitDisplayMode (| GLUT:GLUT_DOUBLE GLUT:GLUT_RGB GLUT:GLUT_DEPTH)) # Window position (from top corner), and size (width% and hieght) (GLUT:glutInitWindowPosition 10 60) (GLUT:glutInitWindowSize 360 360) (GLUT:glutCreateWindow "SimpleAnim") # Initialize OpenGL as we like it.. (initRendering) # Set up callback functions for key presses (GLUT:glutKeyboardFunc 'myKeyboardFunc) # Handles "normal" ascii symbols (GLUT:glutSpecialFunc 'mySpecialKeyFunc) # Handles "special" keyboard keys # Set up the callback function for resizing windows (GLUT:glutReshapeFunc 'resizeWindow) # Call this for background processing # (GLUT:glutIdleFunc 'myIdleFunction) # call this whenever window needs redrawing (GLUT:glutDisplayFunc 'drawScene) (println {Arrow keys control speed. Press "r" to run, "s" to single step.}) # Start the main loop. glutMainLoop never returns. (GLUT:glutMainLoop) ) (main 0 0) (exit)