1b877906bSopenharmony_ci/***************************************************************************** 2b877906bSopenharmony_ci * Title: GLBoing 3b877906bSopenharmony_ci * Desc: Tribute to Amiga Boing. 4b877906bSopenharmony_ci * Author: Jim Brooks <gfx@jimbrooks.org> 5b877906bSopenharmony_ci * Original Amiga authors were R.J. Mical and Dale Luck. 6b877906bSopenharmony_ci * GLFW conversion by Marcus Geelnard 7b877906bSopenharmony_ci * Notes: - 360' = 2*PI [radian] 8b877906bSopenharmony_ci * 9b877906bSopenharmony_ci * - Distances between objects are created by doing a relative 10b877906bSopenharmony_ci * Z translations. 11b877906bSopenharmony_ci * 12b877906bSopenharmony_ci * - Although OpenGL enticingly supports alpha-blending, 13b877906bSopenharmony_ci * the shadow of the original Boing didn't affect the color 14b877906bSopenharmony_ci * of the grid. 15b877906bSopenharmony_ci * 16b877906bSopenharmony_ci * - [Marcus] Changed timing scheme from interval driven to frame- 17b877906bSopenharmony_ci * time based animation steps (which results in much smoother 18b877906bSopenharmony_ci * movement) 19b877906bSopenharmony_ci * 20b877906bSopenharmony_ci * History of Amiga Boing: 21b877906bSopenharmony_ci * 22b877906bSopenharmony_ci * Boing was demonstrated on the prototype Amiga (codenamed "Lorraine") in 23b877906bSopenharmony_ci * 1985. According to legend, it was written ad-hoc in one night by 24b877906bSopenharmony_ci * R. J. Mical and Dale Luck. Because the bouncing ball animation was so fast 25b877906bSopenharmony_ci * and smooth, attendees did not believe the Amiga prototype was really doing 26b877906bSopenharmony_ci * the rendering. Suspecting a trick, they began looking around the booth for 27b877906bSopenharmony_ci * a hidden computer or VCR. 28b877906bSopenharmony_ci *****************************************************************************/ 29b877906bSopenharmony_ci 30b877906bSopenharmony_ci#if defined(_MSC_VER) 31b877906bSopenharmony_ci // Make MS math.h define M_PI 32b877906bSopenharmony_ci #define _USE_MATH_DEFINES 33b877906bSopenharmony_ci#endif 34b877906bSopenharmony_ci 35b877906bSopenharmony_ci#include <stdio.h> 36b877906bSopenharmony_ci#include <stdlib.h> 37b877906bSopenharmony_ci#include <math.h> 38b877906bSopenharmony_ci 39b877906bSopenharmony_ci#define GLAD_GL_IMPLEMENTATION 40b877906bSopenharmony_ci#include <glad/gl.h> 41b877906bSopenharmony_ci#define GLFW_INCLUDE_NONE 42b877906bSopenharmony_ci#include <GLFW/glfw3.h> 43b877906bSopenharmony_ci 44b877906bSopenharmony_ci#include <linmath.h> 45b877906bSopenharmony_ci 46b877906bSopenharmony_ci 47b877906bSopenharmony_ci/***************************************************************************** 48b877906bSopenharmony_ci * Various declarations and macros 49b877906bSopenharmony_ci *****************************************************************************/ 50b877906bSopenharmony_ci 51b877906bSopenharmony_ci/* Prototypes */ 52b877906bSopenharmony_civoid init( void ); 53b877906bSopenharmony_civoid display( void ); 54b877906bSopenharmony_civoid reshape( GLFWwindow* window, int w, int h ); 55b877906bSopenharmony_civoid key_callback( GLFWwindow* window, int key, int scancode, int action, int mods ); 56b877906bSopenharmony_civoid mouse_button_callback( GLFWwindow* window, int button, int action, int mods ); 57b877906bSopenharmony_civoid cursor_position_callback( GLFWwindow* window, double x, double y ); 58b877906bSopenharmony_civoid DrawBoingBall( void ); 59b877906bSopenharmony_civoid BounceBall( double dt ); 60b877906bSopenharmony_civoid DrawBoingBallBand( GLfloat long_lo, GLfloat long_hi ); 61b877906bSopenharmony_civoid DrawGrid( void ); 62b877906bSopenharmony_ci 63b877906bSopenharmony_ci#define RADIUS 70.f 64b877906bSopenharmony_ci#define STEP_LONGITUDE 22.5f /* 22.5 makes 8 bands like original Boing */ 65b877906bSopenharmony_ci#define STEP_LATITUDE 22.5f 66b877906bSopenharmony_ci 67b877906bSopenharmony_ci#define DIST_BALL (RADIUS * 2.f + RADIUS * 0.1f) 68b877906bSopenharmony_ci 69b877906bSopenharmony_ci#define VIEW_SCENE_DIST (DIST_BALL * 3.f + 200.f)/* distance from viewer to middle of boing area */ 70b877906bSopenharmony_ci#define GRID_SIZE (RADIUS * 4.5f) /* length (width) of grid */ 71b877906bSopenharmony_ci#define BOUNCE_HEIGHT (RADIUS * 2.1f) 72b877906bSopenharmony_ci#define BOUNCE_WIDTH (RADIUS * 2.1f) 73b877906bSopenharmony_ci 74b877906bSopenharmony_ci#define SHADOW_OFFSET_X -20.f 75b877906bSopenharmony_ci#define SHADOW_OFFSET_Y 10.f 76b877906bSopenharmony_ci#define SHADOW_OFFSET_Z 0.f 77b877906bSopenharmony_ci 78b877906bSopenharmony_ci#define WALL_L_OFFSET 0.f 79b877906bSopenharmony_ci#define WALL_R_OFFSET 5.f 80b877906bSopenharmony_ci 81b877906bSopenharmony_ci/* Animation speed (50.0 mimics the original GLUT demo speed) */ 82b877906bSopenharmony_ci#define ANIMATION_SPEED 50.f 83b877906bSopenharmony_ci 84b877906bSopenharmony_ci/* Maximum allowed delta time per physics iteration */ 85b877906bSopenharmony_ci#define MAX_DELTA_T 0.02f 86b877906bSopenharmony_ci 87b877906bSopenharmony_ci/* Draw ball, or its shadow */ 88b877906bSopenharmony_citypedef enum { DRAW_BALL, DRAW_BALL_SHADOW } DRAW_BALL_ENUM; 89b877906bSopenharmony_ci 90b877906bSopenharmony_ci/* Vertex type */ 91b877906bSopenharmony_citypedef struct {float x; float y; float z;} vertex_t; 92b877906bSopenharmony_ci 93b877906bSopenharmony_ci/* Global vars */ 94b877906bSopenharmony_ciint windowed_xpos, windowed_ypos, windowed_width, windowed_height; 95b877906bSopenharmony_ciint width, height; 96b877906bSopenharmony_ciGLfloat deg_rot_y = 0.f; 97b877906bSopenharmony_ciGLfloat deg_rot_y_inc = 2.f; 98b877906bSopenharmony_ciint override_pos = GLFW_FALSE; 99b877906bSopenharmony_ciGLfloat cursor_x = 0.f; 100b877906bSopenharmony_ciGLfloat cursor_y = 0.f; 101b877906bSopenharmony_ciGLfloat ball_x = -RADIUS; 102b877906bSopenharmony_ciGLfloat ball_y = -RADIUS; 103b877906bSopenharmony_ciGLfloat ball_x_inc = 1.f; 104b877906bSopenharmony_ciGLfloat ball_y_inc = 2.f; 105b877906bSopenharmony_ciDRAW_BALL_ENUM drawBallHow; 106b877906bSopenharmony_cidouble t; 107b877906bSopenharmony_cidouble t_old = 0.f; 108b877906bSopenharmony_cidouble dt; 109b877906bSopenharmony_ci 110b877906bSopenharmony_ci/* Random number generator */ 111b877906bSopenharmony_ci#ifndef RAND_MAX 112b877906bSopenharmony_ci #define RAND_MAX 4095 113b877906bSopenharmony_ci#endif 114b877906bSopenharmony_ci 115b877906bSopenharmony_ci 116b877906bSopenharmony_ci/***************************************************************************** 117b877906bSopenharmony_ci * Truncate a degree. 118b877906bSopenharmony_ci *****************************************************************************/ 119b877906bSopenharmony_ciGLfloat TruncateDeg( GLfloat deg ) 120b877906bSopenharmony_ci{ 121b877906bSopenharmony_ci if ( deg >= 360.f ) 122b877906bSopenharmony_ci return (deg - 360.f); 123b877906bSopenharmony_ci else 124b877906bSopenharmony_ci return deg; 125b877906bSopenharmony_ci} 126b877906bSopenharmony_ci 127b877906bSopenharmony_ci/***************************************************************************** 128b877906bSopenharmony_ci * Convert a degree (360-based) into a radian. 129b877906bSopenharmony_ci * 360' = 2 * PI 130b877906bSopenharmony_ci *****************************************************************************/ 131b877906bSopenharmony_cidouble deg2rad( double deg ) 132b877906bSopenharmony_ci{ 133b877906bSopenharmony_ci return deg / 360 * (2 * M_PI); 134b877906bSopenharmony_ci} 135b877906bSopenharmony_ci 136b877906bSopenharmony_ci/***************************************************************************** 137b877906bSopenharmony_ci * 360' sin(). 138b877906bSopenharmony_ci *****************************************************************************/ 139b877906bSopenharmony_cidouble sin_deg( double deg ) 140b877906bSopenharmony_ci{ 141b877906bSopenharmony_ci return sin( deg2rad( deg ) ); 142b877906bSopenharmony_ci} 143b877906bSopenharmony_ci 144b877906bSopenharmony_ci/***************************************************************************** 145b877906bSopenharmony_ci * 360' cos(). 146b877906bSopenharmony_ci *****************************************************************************/ 147b877906bSopenharmony_cidouble cos_deg( double deg ) 148b877906bSopenharmony_ci{ 149b877906bSopenharmony_ci return cos( deg2rad( deg ) ); 150b877906bSopenharmony_ci} 151b877906bSopenharmony_ci 152b877906bSopenharmony_ci/***************************************************************************** 153b877906bSopenharmony_ci * Compute a cross product (for a normal vector). 154b877906bSopenharmony_ci * 155b877906bSopenharmony_ci * c = a x b 156b877906bSopenharmony_ci *****************************************************************************/ 157b877906bSopenharmony_civoid CrossProduct( vertex_t a, vertex_t b, vertex_t c, vertex_t *n ) 158b877906bSopenharmony_ci{ 159b877906bSopenharmony_ci GLfloat u1, u2, u3; 160b877906bSopenharmony_ci GLfloat v1, v2, v3; 161b877906bSopenharmony_ci 162b877906bSopenharmony_ci u1 = b.x - a.x; 163b877906bSopenharmony_ci u2 = b.y - a.y; 164b877906bSopenharmony_ci u3 = b.y - a.z; 165b877906bSopenharmony_ci 166b877906bSopenharmony_ci v1 = c.x - a.x; 167b877906bSopenharmony_ci v2 = c.y - a.y; 168b877906bSopenharmony_ci v3 = c.z - a.z; 169b877906bSopenharmony_ci 170b877906bSopenharmony_ci n->x = u2 * v3 - v2 * u3; 171b877906bSopenharmony_ci n->y = u3 * v1 - v3 * u1; 172b877906bSopenharmony_ci n->z = u1 * v2 - v1 * u2; 173b877906bSopenharmony_ci} 174b877906bSopenharmony_ci 175b877906bSopenharmony_ci 176b877906bSopenharmony_ci#define BOING_DEBUG 0 177b877906bSopenharmony_ci 178b877906bSopenharmony_ci 179b877906bSopenharmony_ci/***************************************************************************** 180b877906bSopenharmony_ci * init() 181b877906bSopenharmony_ci *****************************************************************************/ 182b877906bSopenharmony_civoid init( void ) 183b877906bSopenharmony_ci{ 184b877906bSopenharmony_ci /* 185b877906bSopenharmony_ci * Clear background. 186b877906bSopenharmony_ci */ 187b877906bSopenharmony_ci glClearColor( 0.55f, 0.55f, 0.55f, 0.f ); 188b877906bSopenharmony_ci 189b877906bSopenharmony_ci glShadeModel( GL_FLAT ); 190b877906bSopenharmony_ci} 191b877906bSopenharmony_ci 192b877906bSopenharmony_ci 193b877906bSopenharmony_ci/***************************************************************************** 194b877906bSopenharmony_ci * display() 195b877906bSopenharmony_ci *****************************************************************************/ 196b877906bSopenharmony_civoid display(void) 197b877906bSopenharmony_ci{ 198b877906bSopenharmony_ci glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT ); 199b877906bSopenharmony_ci glPushMatrix(); 200b877906bSopenharmony_ci 201b877906bSopenharmony_ci drawBallHow = DRAW_BALL_SHADOW; 202b877906bSopenharmony_ci DrawBoingBall(); 203b877906bSopenharmony_ci 204b877906bSopenharmony_ci DrawGrid(); 205b877906bSopenharmony_ci 206b877906bSopenharmony_ci drawBallHow = DRAW_BALL; 207b877906bSopenharmony_ci DrawBoingBall(); 208b877906bSopenharmony_ci 209b877906bSopenharmony_ci glPopMatrix(); 210b877906bSopenharmony_ci glFlush(); 211b877906bSopenharmony_ci} 212b877906bSopenharmony_ci 213b877906bSopenharmony_ci 214b877906bSopenharmony_ci/***************************************************************************** 215b877906bSopenharmony_ci * reshape() 216b877906bSopenharmony_ci *****************************************************************************/ 217b877906bSopenharmony_civoid reshape( GLFWwindow* window, int w, int h ) 218b877906bSopenharmony_ci{ 219b877906bSopenharmony_ci mat4x4 projection, view; 220b877906bSopenharmony_ci 221b877906bSopenharmony_ci glViewport( 0, 0, (GLsizei)w, (GLsizei)h ); 222b877906bSopenharmony_ci 223b877906bSopenharmony_ci glMatrixMode( GL_PROJECTION ); 224b877906bSopenharmony_ci mat4x4_perspective( projection, 225b877906bSopenharmony_ci 2.f * (float) atan2( RADIUS, 200.f ), 226b877906bSopenharmony_ci (float)w / (float)h, 227b877906bSopenharmony_ci 1.f, VIEW_SCENE_DIST ); 228b877906bSopenharmony_ci glLoadMatrixf((const GLfloat*) projection); 229b877906bSopenharmony_ci 230b877906bSopenharmony_ci glMatrixMode( GL_MODELVIEW ); 231b877906bSopenharmony_ci { 232b877906bSopenharmony_ci vec3 eye = { 0.f, 0.f, VIEW_SCENE_DIST }; 233b877906bSopenharmony_ci vec3 center = { 0.f, 0.f, 0.f }; 234b877906bSopenharmony_ci vec3 up = { 0.f, -1.f, 0.f }; 235b877906bSopenharmony_ci mat4x4_look_at( view, eye, center, up ); 236b877906bSopenharmony_ci } 237b877906bSopenharmony_ci glLoadMatrixf((const GLfloat*) view); 238b877906bSopenharmony_ci} 239b877906bSopenharmony_ci 240b877906bSopenharmony_civoid key_callback( GLFWwindow* window, int key, int scancode, int action, int mods ) 241b877906bSopenharmony_ci{ 242b877906bSopenharmony_ci if (action != GLFW_PRESS) 243b877906bSopenharmony_ci return; 244b877906bSopenharmony_ci 245b877906bSopenharmony_ci if (key == GLFW_KEY_ESCAPE && mods == 0) 246b877906bSopenharmony_ci glfwSetWindowShouldClose(window, GLFW_TRUE); 247b877906bSopenharmony_ci if ((key == GLFW_KEY_ENTER && mods == GLFW_MOD_ALT) || 248b877906bSopenharmony_ci (key == GLFW_KEY_F11 && mods == GLFW_MOD_ALT)) 249b877906bSopenharmony_ci { 250b877906bSopenharmony_ci if (glfwGetWindowMonitor(window)) 251b877906bSopenharmony_ci { 252b877906bSopenharmony_ci glfwSetWindowMonitor(window, NULL, 253b877906bSopenharmony_ci windowed_xpos, windowed_ypos, 254b877906bSopenharmony_ci windowed_width, windowed_height, 0); 255b877906bSopenharmony_ci } 256b877906bSopenharmony_ci else 257b877906bSopenharmony_ci { 258b877906bSopenharmony_ci GLFWmonitor* monitor = glfwGetPrimaryMonitor(); 259b877906bSopenharmony_ci if (monitor) 260b877906bSopenharmony_ci { 261b877906bSopenharmony_ci const GLFWvidmode* mode = glfwGetVideoMode(monitor); 262b877906bSopenharmony_ci glfwGetWindowPos(window, &windowed_xpos, &windowed_ypos); 263b877906bSopenharmony_ci glfwGetWindowSize(window, &windowed_width, &windowed_height); 264b877906bSopenharmony_ci glfwSetWindowMonitor(window, monitor, 0, 0, mode->width, mode->height, mode->refreshRate); 265b877906bSopenharmony_ci } 266b877906bSopenharmony_ci } 267b877906bSopenharmony_ci } 268b877906bSopenharmony_ci} 269b877906bSopenharmony_ci 270b877906bSopenharmony_cistatic void set_ball_pos ( GLfloat x, GLfloat y ) 271b877906bSopenharmony_ci{ 272b877906bSopenharmony_ci ball_x = (width / 2) - x; 273b877906bSopenharmony_ci ball_y = y - (height / 2); 274b877906bSopenharmony_ci} 275b877906bSopenharmony_ci 276b877906bSopenharmony_civoid mouse_button_callback( GLFWwindow* window, int button, int action, int mods ) 277b877906bSopenharmony_ci{ 278b877906bSopenharmony_ci if (button != GLFW_MOUSE_BUTTON_LEFT) 279b877906bSopenharmony_ci return; 280b877906bSopenharmony_ci 281b877906bSopenharmony_ci if (action == GLFW_PRESS) 282b877906bSopenharmony_ci { 283b877906bSopenharmony_ci override_pos = GLFW_TRUE; 284b877906bSopenharmony_ci set_ball_pos(cursor_x, cursor_y); 285b877906bSopenharmony_ci } 286b877906bSopenharmony_ci else 287b877906bSopenharmony_ci { 288b877906bSopenharmony_ci override_pos = GLFW_FALSE; 289b877906bSopenharmony_ci } 290b877906bSopenharmony_ci} 291b877906bSopenharmony_ci 292b877906bSopenharmony_civoid cursor_position_callback( GLFWwindow* window, double x, double y ) 293b877906bSopenharmony_ci{ 294b877906bSopenharmony_ci cursor_x = (float) x; 295b877906bSopenharmony_ci cursor_y = (float) y; 296b877906bSopenharmony_ci 297b877906bSopenharmony_ci if ( override_pos ) 298b877906bSopenharmony_ci set_ball_pos(cursor_x, cursor_y); 299b877906bSopenharmony_ci} 300b877906bSopenharmony_ci 301b877906bSopenharmony_ci/***************************************************************************** 302b877906bSopenharmony_ci * Draw the Boing ball. 303b877906bSopenharmony_ci * 304b877906bSopenharmony_ci * The Boing ball is sphere in which each facet is a rectangle. 305b877906bSopenharmony_ci * Facet colors alternate between red and white. 306b877906bSopenharmony_ci * The ball is built by stacking latitudinal circles. Each circle is composed 307b877906bSopenharmony_ci * of a widely-separated set of points, so that each facet is noticeably large. 308b877906bSopenharmony_ci *****************************************************************************/ 309b877906bSopenharmony_civoid DrawBoingBall( void ) 310b877906bSopenharmony_ci{ 311b877906bSopenharmony_ci GLfloat lon_deg; /* degree of longitude */ 312b877906bSopenharmony_ci double dt_total, dt2; 313b877906bSopenharmony_ci 314b877906bSopenharmony_ci glPushMatrix(); 315b877906bSopenharmony_ci glMatrixMode( GL_MODELVIEW ); 316b877906bSopenharmony_ci 317b877906bSopenharmony_ci /* 318b877906bSopenharmony_ci * Another relative Z translation to separate objects. 319b877906bSopenharmony_ci */ 320b877906bSopenharmony_ci glTranslatef( 0.0, 0.0, DIST_BALL ); 321b877906bSopenharmony_ci 322b877906bSopenharmony_ci /* Update ball position and rotation (iterate if necessary) */ 323b877906bSopenharmony_ci dt_total = dt; 324b877906bSopenharmony_ci while( dt_total > 0.0 ) 325b877906bSopenharmony_ci { 326b877906bSopenharmony_ci dt2 = dt_total > MAX_DELTA_T ? MAX_DELTA_T : dt_total; 327b877906bSopenharmony_ci dt_total -= dt2; 328b877906bSopenharmony_ci BounceBall( dt2 ); 329b877906bSopenharmony_ci deg_rot_y = TruncateDeg( deg_rot_y + deg_rot_y_inc*((float)dt2*ANIMATION_SPEED) ); 330b877906bSopenharmony_ci } 331b877906bSopenharmony_ci 332b877906bSopenharmony_ci /* Set ball position */ 333b877906bSopenharmony_ci glTranslatef( ball_x, ball_y, 0.0 ); 334b877906bSopenharmony_ci 335b877906bSopenharmony_ci /* 336b877906bSopenharmony_ci * Offset the shadow. 337b877906bSopenharmony_ci */ 338b877906bSopenharmony_ci if ( drawBallHow == DRAW_BALL_SHADOW ) 339b877906bSopenharmony_ci { 340b877906bSopenharmony_ci glTranslatef( SHADOW_OFFSET_X, 341b877906bSopenharmony_ci SHADOW_OFFSET_Y, 342b877906bSopenharmony_ci SHADOW_OFFSET_Z ); 343b877906bSopenharmony_ci } 344b877906bSopenharmony_ci 345b877906bSopenharmony_ci /* 346b877906bSopenharmony_ci * Tilt the ball. 347b877906bSopenharmony_ci */ 348b877906bSopenharmony_ci glRotatef( -20.0, 0.0, 0.0, 1.0 ); 349b877906bSopenharmony_ci 350b877906bSopenharmony_ci /* 351b877906bSopenharmony_ci * Continually rotate ball around Y axis. 352b877906bSopenharmony_ci */ 353b877906bSopenharmony_ci glRotatef( deg_rot_y, 0.0, 1.0, 0.0 ); 354b877906bSopenharmony_ci 355b877906bSopenharmony_ci /* 356b877906bSopenharmony_ci * Set OpenGL state for Boing ball. 357b877906bSopenharmony_ci */ 358b877906bSopenharmony_ci glCullFace( GL_FRONT ); 359b877906bSopenharmony_ci glEnable( GL_CULL_FACE ); 360b877906bSopenharmony_ci glEnable( GL_NORMALIZE ); 361b877906bSopenharmony_ci 362b877906bSopenharmony_ci /* 363b877906bSopenharmony_ci * Build a faceted latitude slice of the Boing ball, 364b877906bSopenharmony_ci * stepping same-sized vertical bands of the sphere. 365b877906bSopenharmony_ci */ 366b877906bSopenharmony_ci for ( lon_deg = 0; 367b877906bSopenharmony_ci lon_deg < 180; 368b877906bSopenharmony_ci lon_deg += STEP_LONGITUDE ) 369b877906bSopenharmony_ci { 370b877906bSopenharmony_ci /* 371b877906bSopenharmony_ci * Draw a latitude circle at this longitude. 372b877906bSopenharmony_ci */ 373b877906bSopenharmony_ci DrawBoingBallBand( lon_deg, 374b877906bSopenharmony_ci lon_deg + STEP_LONGITUDE ); 375b877906bSopenharmony_ci } 376b877906bSopenharmony_ci 377b877906bSopenharmony_ci glPopMatrix(); 378b877906bSopenharmony_ci 379b877906bSopenharmony_ci return; 380b877906bSopenharmony_ci} 381b877906bSopenharmony_ci 382b877906bSopenharmony_ci 383b877906bSopenharmony_ci/***************************************************************************** 384b877906bSopenharmony_ci * Bounce the ball. 385b877906bSopenharmony_ci *****************************************************************************/ 386b877906bSopenharmony_civoid BounceBall( double delta_t ) 387b877906bSopenharmony_ci{ 388b877906bSopenharmony_ci GLfloat sign; 389b877906bSopenharmony_ci GLfloat deg; 390b877906bSopenharmony_ci 391b877906bSopenharmony_ci if ( override_pos ) 392b877906bSopenharmony_ci return; 393b877906bSopenharmony_ci 394b877906bSopenharmony_ci /* Bounce on walls */ 395b877906bSopenharmony_ci if ( ball_x > (BOUNCE_WIDTH/2 + WALL_R_OFFSET ) ) 396b877906bSopenharmony_ci { 397b877906bSopenharmony_ci ball_x_inc = -0.5f - 0.75f * (GLfloat)rand() / (GLfloat)RAND_MAX; 398b877906bSopenharmony_ci deg_rot_y_inc = -deg_rot_y_inc; 399b877906bSopenharmony_ci } 400b877906bSopenharmony_ci if ( ball_x < -(BOUNCE_HEIGHT/2 + WALL_L_OFFSET) ) 401b877906bSopenharmony_ci { 402b877906bSopenharmony_ci ball_x_inc = 0.5f + 0.75f * (GLfloat)rand() / (GLfloat)RAND_MAX; 403b877906bSopenharmony_ci deg_rot_y_inc = -deg_rot_y_inc; 404b877906bSopenharmony_ci } 405b877906bSopenharmony_ci 406b877906bSopenharmony_ci /* Bounce on floor / roof */ 407b877906bSopenharmony_ci if ( ball_y > BOUNCE_HEIGHT/2 ) 408b877906bSopenharmony_ci { 409b877906bSopenharmony_ci ball_y_inc = -0.75f - 1.f * (GLfloat)rand() / (GLfloat)RAND_MAX; 410b877906bSopenharmony_ci } 411b877906bSopenharmony_ci if ( ball_y < -BOUNCE_HEIGHT/2*0.85 ) 412b877906bSopenharmony_ci { 413b877906bSopenharmony_ci ball_y_inc = 0.75f + 1.f * (GLfloat)rand() / (GLfloat)RAND_MAX; 414b877906bSopenharmony_ci } 415b877906bSopenharmony_ci 416b877906bSopenharmony_ci /* Update ball position */ 417b877906bSopenharmony_ci ball_x += ball_x_inc * ((float)delta_t*ANIMATION_SPEED); 418b877906bSopenharmony_ci ball_y += ball_y_inc * ((float)delta_t*ANIMATION_SPEED); 419b877906bSopenharmony_ci 420b877906bSopenharmony_ci /* 421b877906bSopenharmony_ci * Simulate the effects of gravity on Y movement. 422b877906bSopenharmony_ci */ 423b877906bSopenharmony_ci if ( ball_y_inc < 0 ) sign = -1.0; else sign = 1.0; 424b877906bSopenharmony_ci 425b877906bSopenharmony_ci deg = (ball_y + BOUNCE_HEIGHT/2) * 90 / BOUNCE_HEIGHT; 426b877906bSopenharmony_ci if ( deg > 80 ) deg = 80; 427b877906bSopenharmony_ci if ( deg < 10 ) deg = 10; 428b877906bSopenharmony_ci 429b877906bSopenharmony_ci ball_y_inc = sign * 4.f * (float) sin_deg( deg ); 430b877906bSopenharmony_ci} 431b877906bSopenharmony_ci 432b877906bSopenharmony_ci 433b877906bSopenharmony_ci/***************************************************************************** 434b877906bSopenharmony_ci * Draw a faceted latitude band of the Boing ball. 435b877906bSopenharmony_ci * 436b877906bSopenharmony_ci * Parms: long_lo, long_hi 437b877906bSopenharmony_ci * Low and high longitudes of slice, resp. 438b877906bSopenharmony_ci *****************************************************************************/ 439b877906bSopenharmony_civoid DrawBoingBallBand( GLfloat long_lo, 440b877906bSopenharmony_ci GLfloat long_hi ) 441b877906bSopenharmony_ci{ 442b877906bSopenharmony_ci vertex_t vert_ne; /* "ne" means south-east, so on */ 443b877906bSopenharmony_ci vertex_t vert_nw; 444b877906bSopenharmony_ci vertex_t vert_sw; 445b877906bSopenharmony_ci vertex_t vert_se; 446b877906bSopenharmony_ci vertex_t vert_norm; 447b877906bSopenharmony_ci GLfloat lat_deg; 448b877906bSopenharmony_ci static int colorToggle = 0; 449b877906bSopenharmony_ci 450b877906bSopenharmony_ci /* 451b877906bSopenharmony_ci * Iterate through the points of a latitude circle. 452b877906bSopenharmony_ci * A latitude circle is a 2D set of X,Z points. 453b877906bSopenharmony_ci */ 454b877906bSopenharmony_ci for ( lat_deg = 0; 455b877906bSopenharmony_ci lat_deg <= (360 - STEP_LATITUDE); 456b877906bSopenharmony_ci lat_deg += STEP_LATITUDE ) 457b877906bSopenharmony_ci { 458b877906bSopenharmony_ci /* 459b877906bSopenharmony_ci * Color this polygon with red or white. 460b877906bSopenharmony_ci */ 461b877906bSopenharmony_ci if ( colorToggle ) 462b877906bSopenharmony_ci glColor3f( 0.8f, 0.1f, 0.1f ); 463b877906bSopenharmony_ci else 464b877906bSopenharmony_ci glColor3f( 0.95f, 0.95f, 0.95f ); 465b877906bSopenharmony_ci#if 0 466b877906bSopenharmony_ci if ( lat_deg >= 180 ) 467b877906bSopenharmony_ci if ( colorToggle ) 468b877906bSopenharmony_ci glColor3f( 0.1f, 0.8f, 0.1f ); 469b877906bSopenharmony_ci else 470b877906bSopenharmony_ci glColor3f( 0.5f, 0.5f, 0.95f ); 471b877906bSopenharmony_ci#endif 472b877906bSopenharmony_ci colorToggle = ! colorToggle; 473b877906bSopenharmony_ci 474b877906bSopenharmony_ci /* 475b877906bSopenharmony_ci * Change color if drawing shadow. 476b877906bSopenharmony_ci */ 477b877906bSopenharmony_ci if ( drawBallHow == DRAW_BALL_SHADOW ) 478b877906bSopenharmony_ci glColor3f( 0.35f, 0.35f, 0.35f ); 479b877906bSopenharmony_ci 480b877906bSopenharmony_ci /* 481b877906bSopenharmony_ci * Assign each Y. 482b877906bSopenharmony_ci */ 483b877906bSopenharmony_ci vert_ne.y = vert_nw.y = (float) cos_deg(long_hi) * RADIUS; 484b877906bSopenharmony_ci vert_sw.y = vert_se.y = (float) cos_deg(long_lo) * RADIUS; 485b877906bSopenharmony_ci 486b877906bSopenharmony_ci /* 487b877906bSopenharmony_ci * Assign each X,Z with sin,cos values scaled by latitude radius indexed by longitude. 488b877906bSopenharmony_ci * Eg, long=0 and long=180 are at the poles, so zero scale is sin(longitude), 489b877906bSopenharmony_ci * while long=90 (sin(90)=1) is at equator. 490b877906bSopenharmony_ci */ 491b877906bSopenharmony_ci vert_ne.x = (float) cos_deg( lat_deg ) * (RADIUS * (float) sin_deg( long_lo + STEP_LONGITUDE )); 492b877906bSopenharmony_ci vert_se.x = (float) cos_deg( lat_deg ) * (RADIUS * (float) sin_deg( long_lo )); 493b877906bSopenharmony_ci vert_nw.x = (float) cos_deg( lat_deg + STEP_LATITUDE ) * (RADIUS * (float) sin_deg( long_lo + STEP_LONGITUDE )); 494b877906bSopenharmony_ci vert_sw.x = (float) cos_deg( lat_deg + STEP_LATITUDE ) * (RADIUS * (float) sin_deg( long_lo )); 495b877906bSopenharmony_ci 496b877906bSopenharmony_ci vert_ne.z = (float) sin_deg( lat_deg ) * (RADIUS * (float) sin_deg( long_lo + STEP_LONGITUDE )); 497b877906bSopenharmony_ci vert_se.z = (float) sin_deg( lat_deg ) * (RADIUS * (float) sin_deg( long_lo )); 498b877906bSopenharmony_ci vert_nw.z = (float) sin_deg( lat_deg + STEP_LATITUDE ) * (RADIUS * (float) sin_deg( long_lo + STEP_LONGITUDE )); 499b877906bSopenharmony_ci vert_sw.z = (float) sin_deg( lat_deg + STEP_LATITUDE ) * (RADIUS * (float) sin_deg( long_lo )); 500b877906bSopenharmony_ci 501b877906bSopenharmony_ci /* 502b877906bSopenharmony_ci * Draw the facet. 503b877906bSopenharmony_ci */ 504b877906bSopenharmony_ci glBegin( GL_POLYGON ); 505b877906bSopenharmony_ci 506b877906bSopenharmony_ci CrossProduct( vert_ne, vert_nw, vert_sw, &vert_norm ); 507b877906bSopenharmony_ci glNormal3f( vert_norm.x, vert_norm.y, vert_norm.z ); 508b877906bSopenharmony_ci 509b877906bSopenharmony_ci glVertex3f( vert_ne.x, vert_ne.y, vert_ne.z ); 510b877906bSopenharmony_ci glVertex3f( vert_nw.x, vert_nw.y, vert_nw.z ); 511b877906bSopenharmony_ci glVertex3f( vert_sw.x, vert_sw.y, vert_sw.z ); 512b877906bSopenharmony_ci glVertex3f( vert_se.x, vert_se.y, vert_se.z ); 513b877906bSopenharmony_ci 514b877906bSopenharmony_ci glEnd(); 515b877906bSopenharmony_ci 516b877906bSopenharmony_ci#if BOING_DEBUG 517b877906bSopenharmony_ci printf( "----------------------------------------------------------- \n" ); 518b877906bSopenharmony_ci printf( "lat = %f long_lo = %f long_hi = %f \n", lat_deg, long_lo, long_hi ); 519b877906bSopenharmony_ci printf( "vert_ne x = %.8f y = %.8f z = %.8f \n", vert_ne.x, vert_ne.y, vert_ne.z ); 520b877906bSopenharmony_ci printf( "vert_nw x = %.8f y = %.8f z = %.8f \n", vert_nw.x, vert_nw.y, vert_nw.z ); 521b877906bSopenharmony_ci printf( "vert_se x = %.8f y = %.8f z = %.8f \n", vert_se.x, vert_se.y, vert_se.z ); 522b877906bSopenharmony_ci printf( "vert_sw x = %.8f y = %.8f z = %.8f \n", vert_sw.x, vert_sw.y, vert_sw.z ); 523b877906bSopenharmony_ci#endif 524b877906bSopenharmony_ci 525b877906bSopenharmony_ci } 526b877906bSopenharmony_ci 527b877906bSopenharmony_ci /* 528b877906bSopenharmony_ci * Toggle color so that next band will opposite red/white colors than this one. 529b877906bSopenharmony_ci */ 530b877906bSopenharmony_ci colorToggle = ! colorToggle; 531b877906bSopenharmony_ci 532b877906bSopenharmony_ci /* 533b877906bSopenharmony_ci * This circular band is done. 534b877906bSopenharmony_ci */ 535b877906bSopenharmony_ci return; 536b877906bSopenharmony_ci} 537b877906bSopenharmony_ci 538b877906bSopenharmony_ci 539b877906bSopenharmony_ci/***************************************************************************** 540b877906bSopenharmony_ci * Draw the purple grid of lines, behind the Boing ball. 541b877906bSopenharmony_ci * When the Workbench is dropped to the bottom, Boing shows 12 rows. 542b877906bSopenharmony_ci *****************************************************************************/ 543b877906bSopenharmony_civoid DrawGrid( void ) 544b877906bSopenharmony_ci{ 545b877906bSopenharmony_ci int row, col; 546b877906bSopenharmony_ci const int rowTotal = 12; /* must be divisible by 2 */ 547b877906bSopenharmony_ci const int colTotal = rowTotal; /* must be same as rowTotal */ 548b877906bSopenharmony_ci const GLfloat widthLine = 2.0; /* should be divisible by 2 */ 549b877906bSopenharmony_ci const GLfloat sizeCell = GRID_SIZE / rowTotal; 550b877906bSopenharmony_ci const GLfloat z_offset = -40.0; 551b877906bSopenharmony_ci GLfloat xl, xr; 552b877906bSopenharmony_ci GLfloat yt, yb; 553b877906bSopenharmony_ci 554b877906bSopenharmony_ci glPushMatrix(); 555b877906bSopenharmony_ci glDisable( GL_CULL_FACE ); 556b877906bSopenharmony_ci 557b877906bSopenharmony_ci /* 558b877906bSopenharmony_ci * Another relative Z translation to separate objects. 559b877906bSopenharmony_ci */ 560b877906bSopenharmony_ci glTranslatef( 0.0, 0.0, DIST_BALL ); 561b877906bSopenharmony_ci 562b877906bSopenharmony_ci /* 563b877906bSopenharmony_ci * Draw vertical lines (as skinny 3D rectangles). 564b877906bSopenharmony_ci */ 565b877906bSopenharmony_ci for ( col = 0; col <= colTotal; col++ ) 566b877906bSopenharmony_ci { 567b877906bSopenharmony_ci /* 568b877906bSopenharmony_ci * Compute co-ords of line. 569b877906bSopenharmony_ci */ 570b877906bSopenharmony_ci xl = -GRID_SIZE / 2 + col * sizeCell; 571b877906bSopenharmony_ci xr = xl + widthLine; 572b877906bSopenharmony_ci 573b877906bSopenharmony_ci yt = GRID_SIZE / 2; 574b877906bSopenharmony_ci yb = -GRID_SIZE / 2 - widthLine; 575b877906bSopenharmony_ci 576b877906bSopenharmony_ci glBegin( GL_POLYGON ); 577b877906bSopenharmony_ci 578b877906bSopenharmony_ci glColor3f( 0.6f, 0.1f, 0.6f ); /* purple */ 579b877906bSopenharmony_ci 580b877906bSopenharmony_ci glVertex3f( xr, yt, z_offset ); /* NE */ 581b877906bSopenharmony_ci glVertex3f( xl, yt, z_offset ); /* NW */ 582b877906bSopenharmony_ci glVertex3f( xl, yb, z_offset ); /* SW */ 583b877906bSopenharmony_ci glVertex3f( xr, yb, z_offset ); /* SE */ 584b877906bSopenharmony_ci 585b877906bSopenharmony_ci glEnd(); 586b877906bSopenharmony_ci } 587b877906bSopenharmony_ci 588b877906bSopenharmony_ci /* 589b877906bSopenharmony_ci * Draw horizontal lines (as skinny 3D rectangles). 590b877906bSopenharmony_ci */ 591b877906bSopenharmony_ci for ( row = 0; row <= rowTotal; row++ ) 592b877906bSopenharmony_ci { 593b877906bSopenharmony_ci /* 594b877906bSopenharmony_ci * Compute co-ords of line. 595b877906bSopenharmony_ci */ 596b877906bSopenharmony_ci yt = GRID_SIZE / 2 - row * sizeCell; 597b877906bSopenharmony_ci yb = yt - widthLine; 598b877906bSopenharmony_ci 599b877906bSopenharmony_ci xl = -GRID_SIZE / 2; 600b877906bSopenharmony_ci xr = GRID_SIZE / 2 + widthLine; 601b877906bSopenharmony_ci 602b877906bSopenharmony_ci glBegin( GL_POLYGON ); 603b877906bSopenharmony_ci 604b877906bSopenharmony_ci glColor3f( 0.6f, 0.1f, 0.6f ); /* purple */ 605b877906bSopenharmony_ci 606b877906bSopenharmony_ci glVertex3f( xr, yt, z_offset ); /* NE */ 607b877906bSopenharmony_ci glVertex3f( xl, yt, z_offset ); /* NW */ 608b877906bSopenharmony_ci glVertex3f( xl, yb, z_offset ); /* SW */ 609b877906bSopenharmony_ci glVertex3f( xr, yb, z_offset ); /* SE */ 610b877906bSopenharmony_ci 611b877906bSopenharmony_ci glEnd(); 612b877906bSopenharmony_ci } 613b877906bSopenharmony_ci 614b877906bSopenharmony_ci glPopMatrix(); 615b877906bSopenharmony_ci 616b877906bSopenharmony_ci return; 617b877906bSopenharmony_ci} 618b877906bSopenharmony_ci 619b877906bSopenharmony_ci 620b877906bSopenharmony_ci/*======================================================================* 621b877906bSopenharmony_ci * main() 622b877906bSopenharmony_ci *======================================================================*/ 623b877906bSopenharmony_ci 624b877906bSopenharmony_ciint main( void ) 625b877906bSopenharmony_ci{ 626b877906bSopenharmony_ci GLFWwindow* window; 627b877906bSopenharmony_ci 628b877906bSopenharmony_ci /* Init GLFW */ 629b877906bSopenharmony_ci if( !glfwInit() ) 630b877906bSopenharmony_ci exit( EXIT_FAILURE ); 631b877906bSopenharmony_ci 632b877906bSopenharmony_ci window = glfwCreateWindow( 400, 400, "Boing (classic Amiga demo)", NULL, NULL ); 633b877906bSopenharmony_ci if (!window) 634b877906bSopenharmony_ci { 635b877906bSopenharmony_ci glfwTerminate(); 636b877906bSopenharmony_ci exit( EXIT_FAILURE ); 637b877906bSopenharmony_ci } 638b877906bSopenharmony_ci 639b877906bSopenharmony_ci glfwSetWindowAspectRatio(window, 1, 1); 640b877906bSopenharmony_ci 641b877906bSopenharmony_ci glfwSetFramebufferSizeCallback(window, reshape); 642b877906bSopenharmony_ci glfwSetKeyCallback(window, key_callback); 643b877906bSopenharmony_ci glfwSetMouseButtonCallback(window, mouse_button_callback); 644b877906bSopenharmony_ci glfwSetCursorPosCallback(window, cursor_position_callback); 645b877906bSopenharmony_ci 646b877906bSopenharmony_ci glfwMakeContextCurrent(window); 647b877906bSopenharmony_ci gladLoadGL(glfwGetProcAddress); 648b877906bSopenharmony_ci glfwSwapInterval( 1 ); 649b877906bSopenharmony_ci 650b877906bSopenharmony_ci glfwGetFramebufferSize(window, &width, &height); 651b877906bSopenharmony_ci reshape(window, width, height); 652b877906bSopenharmony_ci 653b877906bSopenharmony_ci glfwSetTime( 0.0 ); 654b877906bSopenharmony_ci 655b877906bSopenharmony_ci init(); 656b877906bSopenharmony_ci 657b877906bSopenharmony_ci /* Main loop */ 658b877906bSopenharmony_ci for (;;) 659b877906bSopenharmony_ci { 660b877906bSopenharmony_ci /* Timing */ 661b877906bSopenharmony_ci t = glfwGetTime(); 662b877906bSopenharmony_ci dt = t - t_old; 663b877906bSopenharmony_ci t_old = t; 664b877906bSopenharmony_ci 665b877906bSopenharmony_ci /* Draw one frame */ 666b877906bSopenharmony_ci display(); 667b877906bSopenharmony_ci 668b877906bSopenharmony_ci /* Swap buffers */ 669b877906bSopenharmony_ci glfwSwapBuffers(window); 670b877906bSopenharmony_ci glfwPollEvents(); 671b877906bSopenharmony_ci 672b877906bSopenharmony_ci /* Check if we are still running */ 673b877906bSopenharmony_ci if (glfwWindowShouldClose(window)) 674b877906bSopenharmony_ci break; 675b877906bSopenharmony_ci } 676b877906bSopenharmony_ci 677b877906bSopenharmony_ci glfwTerminate(); 678b877906bSopenharmony_ci exit( EXIT_SUCCESS ); 679b877906bSopenharmony_ci} 680b877906bSopenharmony_ci 681