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