summaryrefslogtreecommitdiff
path: root/libs/glfw-3.3.8/examples/boing.c
diff options
context:
space:
mode:
authorsanine <sanine.not@pm.me>2022-08-23 13:38:27 -0500
committersanine <sanine.not@pm.me>2022-08-23 13:38:27 -0500
commit3afbf2a13b2dada445fb667bf25600407fea480a (patch)
tree551329e6f74fc9f177616de0d6739e8b5331ae96 /libs/glfw-3.3.8/examples/boing.c
parent261e3f991221fbad6bbf262f5e65b773e4b6c73e (diff)
parent25ed7eb9f84e9a822f698ad803901fbb2a5354cf (diff)
:wMerge branch 'gl-window' into main
Diffstat (limited to 'libs/glfw-3.3.8/examples/boing.c')
-rw-r--r--libs/glfw-3.3.8/examples/boing.c679
1 files changed, 679 insertions, 0 deletions
diff --git a/libs/glfw-3.3.8/examples/boing.c b/libs/glfw-3.3.8/examples/boing.c
new file mode 100644
index 0000000..ca38908
--- /dev/null
+++ b/libs/glfw-3.3.8/examples/boing.c
@@ -0,0 +1,679 @@
+/*****************************************************************************
+ * Title: GLBoing
+ * Desc: Tribute to Amiga Boing.
+ * Author: Jim Brooks <gfx@jimbrooks.org>
+ * Original Amiga authors were R.J. Mical and Dale Luck.
+ * GLFW conversion by Marcus Geelnard
+ * Notes: - 360' = 2*PI [radian]
+ *
+ * - Distances between objects are created by doing a relative
+ * Z translations.
+ *
+ * - Although OpenGL enticingly supports alpha-blending,
+ * the shadow of the original Boing didn't affect the color
+ * of the grid.
+ *
+ * - [Marcus] Changed timing scheme from interval driven to frame-
+ * time based animation steps (which results in much smoother
+ * movement)
+ *
+ * History of Amiga Boing:
+ *
+ * Boing was demonstrated on the prototype Amiga (codenamed "Lorraine") in
+ * 1985. According to legend, it was written ad-hoc in one night by
+ * R. J. Mical and Dale Luck. Because the bouncing ball animation was so fast
+ * and smooth, attendees did not believe the Amiga prototype was really doing
+ * the rendering. Suspecting a trick, they began looking around the booth for
+ * a hidden computer or VCR.
+ *****************************************************************************/
+
+#if defined(_MSC_VER)
+ // Make MS math.h define M_PI
+ #define _USE_MATH_DEFINES
+#endif
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <math.h>
+
+#include <glad/gl.h>
+#define GLFW_INCLUDE_NONE
+#include <GLFW/glfw3.h>
+
+#include <linmath.h>
+
+
+/*****************************************************************************
+ * Various declarations and macros
+ *****************************************************************************/
+
+/* Prototypes */
+void init( void );
+void display( void );
+void reshape( GLFWwindow* window, int w, int h );
+void key_callback( GLFWwindow* window, int key, int scancode, int action, int mods );
+void mouse_button_callback( GLFWwindow* window, int button, int action, int mods );
+void cursor_position_callback( GLFWwindow* window, double x, double y );
+void DrawBoingBall( void );
+void BounceBall( double dt );
+void DrawBoingBallBand( GLfloat long_lo, GLfloat long_hi );
+void DrawGrid( void );
+
+#define RADIUS 70.f
+#define STEP_LONGITUDE 22.5f /* 22.5 makes 8 bands like original Boing */
+#define STEP_LATITUDE 22.5f
+
+#define DIST_BALL (RADIUS * 2.f + RADIUS * 0.1f)
+
+#define VIEW_SCENE_DIST (DIST_BALL * 3.f + 200.f)/* distance from viewer to middle of boing area */
+#define GRID_SIZE (RADIUS * 4.5f) /* length (width) of grid */
+#define BOUNCE_HEIGHT (RADIUS * 2.1f)
+#define BOUNCE_WIDTH (RADIUS * 2.1f)
+
+#define SHADOW_OFFSET_X -20.f
+#define SHADOW_OFFSET_Y 10.f
+#define SHADOW_OFFSET_Z 0.f
+
+#define WALL_L_OFFSET 0.f
+#define WALL_R_OFFSET 5.f
+
+/* Animation speed (50.0 mimics the original GLUT demo speed) */
+#define ANIMATION_SPEED 50.f
+
+/* Maximum allowed delta time per physics iteration */
+#define MAX_DELTA_T 0.02f
+
+/* Draw ball, or its shadow */
+typedef enum { DRAW_BALL, DRAW_BALL_SHADOW } DRAW_BALL_ENUM;
+
+/* Vertex type */
+typedef struct {float x; float y; float z;} vertex_t;
+
+/* Global vars */
+int windowed_xpos, windowed_ypos, windowed_width, windowed_height;
+int width, height;
+GLfloat deg_rot_y = 0.f;
+GLfloat deg_rot_y_inc = 2.f;
+int override_pos = GLFW_FALSE;
+GLfloat cursor_x = 0.f;
+GLfloat cursor_y = 0.f;
+GLfloat ball_x = -RADIUS;
+GLfloat ball_y = -RADIUS;
+GLfloat ball_x_inc = 1.f;
+GLfloat ball_y_inc = 2.f;
+DRAW_BALL_ENUM drawBallHow;
+double t;
+double t_old = 0.f;
+double dt;
+
+/* Random number generator */
+#ifndef RAND_MAX
+ #define RAND_MAX 4095
+#endif
+
+
+/*****************************************************************************
+ * Truncate a degree.
+ *****************************************************************************/
+GLfloat TruncateDeg( GLfloat deg )
+{
+ if ( deg >= 360.f )
+ return (deg - 360.f);
+ else
+ return deg;
+}
+
+/*****************************************************************************
+ * Convert a degree (360-based) into a radian.
+ * 360' = 2 * PI
+ *****************************************************************************/
+double deg2rad( double deg )
+{
+ return deg / 360 * (2 * M_PI);
+}
+
+/*****************************************************************************
+ * 360' sin().
+ *****************************************************************************/
+double sin_deg( double deg )
+{
+ return sin( deg2rad( deg ) );
+}
+
+/*****************************************************************************
+ * 360' cos().
+ *****************************************************************************/
+double cos_deg( double deg )
+{
+ return cos( deg2rad( deg ) );
+}
+
+/*****************************************************************************
+ * Compute a cross product (for a normal vector).
+ *
+ * c = a x b
+ *****************************************************************************/
+void CrossProduct( vertex_t a, vertex_t b, vertex_t c, vertex_t *n )
+{
+ GLfloat u1, u2, u3;
+ GLfloat v1, v2, v3;
+
+ u1 = b.x - a.x;
+ u2 = b.y - a.y;
+ u3 = b.y - a.z;
+
+ v1 = c.x - a.x;
+ v2 = c.y - a.y;
+ v3 = c.z - a.z;
+
+ n->x = u2 * v3 - v2 * u3;
+ n->y = u3 * v1 - v3 * u1;
+ n->z = u1 * v2 - v1 * u2;
+}
+
+
+#define BOING_DEBUG 0
+
+
+/*****************************************************************************
+ * init()
+ *****************************************************************************/
+void init( void )
+{
+ /*
+ * Clear background.
+ */
+ glClearColor( 0.55f, 0.55f, 0.55f, 0.f );
+
+ glShadeModel( GL_FLAT );
+}
+
+
+/*****************************************************************************
+ * display()
+ *****************************************************************************/
+void display(void)
+{
+ glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );
+ glPushMatrix();
+
+ drawBallHow = DRAW_BALL_SHADOW;
+ DrawBoingBall();
+
+ DrawGrid();
+
+ drawBallHow = DRAW_BALL;
+ DrawBoingBall();
+
+ glPopMatrix();
+ glFlush();
+}
+
+
+/*****************************************************************************
+ * reshape()
+ *****************************************************************************/
+void reshape( GLFWwindow* window, int w, int h )
+{
+ mat4x4 projection, view;
+
+ glViewport( 0, 0, (GLsizei)w, (GLsizei)h );
+
+ glMatrixMode( GL_PROJECTION );
+ mat4x4_perspective( projection,
+ 2.f * (float) atan2( RADIUS, 200.f ),
+ (float)w / (float)h,
+ 1.f, VIEW_SCENE_DIST );
+ glLoadMatrixf((const GLfloat*) projection);
+
+ glMatrixMode( GL_MODELVIEW );
+ {
+ vec3 eye = { 0.f, 0.f, VIEW_SCENE_DIST };
+ vec3 center = { 0.f, 0.f, 0.f };
+ vec3 up = { 0.f, -1.f, 0.f };
+ mat4x4_look_at( view, eye, center, up );
+ }
+ glLoadMatrixf((const GLfloat*) view);
+}
+
+void key_callback( GLFWwindow* window, int key, int scancode, int action, int mods )
+{
+ if (action != GLFW_PRESS)
+ return;
+
+ if (key == GLFW_KEY_ESCAPE && mods == 0)
+ glfwSetWindowShouldClose(window, GLFW_TRUE);
+ if ((key == GLFW_KEY_ENTER && mods == GLFW_MOD_ALT) ||
+ (key == GLFW_KEY_F11 && mods == GLFW_MOD_ALT))
+ {
+ if (glfwGetWindowMonitor(window))
+ {
+ glfwSetWindowMonitor(window, NULL,
+ windowed_xpos, windowed_ypos,
+ windowed_width, windowed_height, 0);
+ }
+ else
+ {
+ GLFWmonitor* monitor = glfwGetPrimaryMonitor();
+ if (monitor)
+ {
+ const GLFWvidmode* mode = glfwGetVideoMode(monitor);
+ glfwGetWindowPos(window, &windowed_xpos, &windowed_ypos);
+ glfwGetWindowSize(window, &windowed_width, &windowed_height);
+ glfwSetWindowMonitor(window, monitor, 0, 0, mode->width, mode->height, mode->refreshRate);
+ }
+ }
+ }
+}
+
+static void set_ball_pos ( GLfloat x, GLfloat y )
+{
+ ball_x = (width / 2) - x;
+ ball_y = y - (height / 2);
+}
+
+void mouse_button_callback( GLFWwindow* window, int button, int action, int mods )
+{
+ if (button != GLFW_MOUSE_BUTTON_LEFT)
+ return;
+
+ if (action == GLFW_PRESS)
+ {
+ override_pos = GLFW_TRUE;
+ set_ball_pos(cursor_x, cursor_y);
+ }
+ else
+ {
+ override_pos = GLFW_FALSE;
+ }
+}
+
+void cursor_position_callback( GLFWwindow* window, double x, double y )
+{
+ cursor_x = (float) x;
+ cursor_y = (float) y;
+
+ if ( override_pos )
+ set_ball_pos(cursor_x, cursor_y);
+}
+
+/*****************************************************************************
+ * Draw the Boing ball.
+ *
+ * The Boing ball is sphere in which each facet is a rectangle.
+ * Facet colors alternate between red and white.
+ * The ball is built by stacking latitudinal circles. Each circle is composed
+ * of a widely-separated set of points, so that each facet is noticeably large.
+ *****************************************************************************/
+void DrawBoingBall( void )
+{
+ GLfloat lon_deg; /* degree of longitude */
+ double dt_total, dt2;
+
+ glPushMatrix();
+ glMatrixMode( GL_MODELVIEW );
+
+ /*
+ * Another relative Z translation to separate objects.
+ */
+ glTranslatef( 0.0, 0.0, DIST_BALL );
+
+ /* Update ball position and rotation (iterate if necessary) */
+ dt_total = dt;
+ while( dt_total > 0.0 )
+ {
+ dt2 = dt_total > MAX_DELTA_T ? MAX_DELTA_T : dt_total;
+ dt_total -= dt2;
+ BounceBall( dt2 );
+ deg_rot_y = TruncateDeg( deg_rot_y + deg_rot_y_inc*((float)dt2*ANIMATION_SPEED) );
+ }
+
+ /* Set ball position */
+ glTranslatef( ball_x, ball_y, 0.0 );
+
+ /*
+ * Offset the shadow.
+ */
+ if ( drawBallHow == DRAW_BALL_SHADOW )
+ {
+ glTranslatef( SHADOW_OFFSET_X,
+ SHADOW_OFFSET_Y,
+ SHADOW_OFFSET_Z );
+ }
+
+ /*
+ * Tilt the ball.
+ */
+ glRotatef( -20.0, 0.0, 0.0, 1.0 );
+
+ /*
+ * Continually rotate ball around Y axis.
+ */
+ glRotatef( deg_rot_y, 0.0, 1.0, 0.0 );
+
+ /*
+ * Set OpenGL state for Boing ball.
+ */
+ glCullFace( GL_FRONT );
+ glEnable( GL_CULL_FACE );
+ glEnable( GL_NORMALIZE );
+
+ /*
+ * Build a faceted latitude slice of the Boing ball,
+ * stepping same-sized vertical bands of the sphere.
+ */
+ for ( lon_deg = 0;
+ lon_deg < 180;
+ lon_deg += STEP_LONGITUDE )
+ {
+ /*
+ * Draw a latitude circle at this longitude.
+ */
+ DrawBoingBallBand( lon_deg,
+ lon_deg + STEP_LONGITUDE );
+ }
+
+ glPopMatrix();
+
+ return;
+}
+
+
+/*****************************************************************************
+ * Bounce the ball.
+ *****************************************************************************/
+void BounceBall( double delta_t )
+{
+ GLfloat sign;
+ GLfloat deg;
+
+ if ( override_pos )
+ return;
+
+ /* Bounce on walls */
+ if ( ball_x > (BOUNCE_WIDTH/2 + WALL_R_OFFSET ) )
+ {
+ ball_x_inc = -0.5f - 0.75f * (GLfloat)rand() / (GLfloat)RAND_MAX;
+ deg_rot_y_inc = -deg_rot_y_inc;
+ }
+ if ( ball_x < -(BOUNCE_HEIGHT/2 + WALL_L_OFFSET) )
+ {
+ ball_x_inc = 0.5f + 0.75f * (GLfloat)rand() / (GLfloat)RAND_MAX;
+ deg_rot_y_inc = -deg_rot_y_inc;
+ }
+
+ /* Bounce on floor / roof */
+ if ( ball_y > BOUNCE_HEIGHT/2 )
+ {
+ ball_y_inc = -0.75f - 1.f * (GLfloat)rand() / (GLfloat)RAND_MAX;
+ }
+ if ( ball_y < -BOUNCE_HEIGHT/2*0.85 )
+ {
+ ball_y_inc = 0.75f + 1.f * (GLfloat)rand() / (GLfloat)RAND_MAX;
+ }
+
+ /* Update ball position */
+ ball_x += ball_x_inc * ((float)delta_t*ANIMATION_SPEED);
+ ball_y += ball_y_inc * ((float)delta_t*ANIMATION_SPEED);
+
+ /*
+ * Simulate the effects of gravity on Y movement.
+ */
+ if ( ball_y_inc < 0 ) sign = -1.0; else sign = 1.0;
+
+ deg = (ball_y + BOUNCE_HEIGHT/2) * 90 / BOUNCE_HEIGHT;
+ if ( deg > 80 ) deg = 80;
+ if ( deg < 10 ) deg = 10;
+
+ ball_y_inc = sign * 4.f * (float) sin_deg( deg );
+}
+
+
+/*****************************************************************************
+ * Draw a faceted latitude band of the Boing ball.
+ *
+ * Parms: long_lo, long_hi
+ * Low and high longitudes of slice, resp.
+ *****************************************************************************/
+void DrawBoingBallBand( GLfloat long_lo,
+ GLfloat long_hi )
+{
+ vertex_t vert_ne; /* "ne" means south-east, so on */
+ vertex_t vert_nw;
+ vertex_t vert_sw;
+ vertex_t vert_se;
+ vertex_t vert_norm;
+ GLfloat lat_deg;
+ static int colorToggle = 0;
+
+ /*
+ * Iterate through the points of a latitude circle.
+ * A latitude circle is a 2D set of X,Z points.
+ */
+ for ( lat_deg = 0;
+ lat_deg <= (360 - STEP_LATITUDE);
+ lat_deg += STEP_LATITUDE )
+ {
+ /*
+ * Color this polygon with red or white.
+ */
+ if ( colorToggle )
+ glColor3f( 0.8f, 0.1f, 0.1f );
+ else
+ glColor3f( 0.95f, 0.95f, 0.95f );
+#if 0
+ if ( lat_deg >= 180 )
+ if ( colorToggle )
+ glColor3f( 0.1f, 0.8f, 0.1f );
+ else
+ glColor3f( 0.5f, 0.5f, 0.95f );
+#endif
+ colorToggle = ! colorToggle;
+
+ /*
+ * Change color if drawing shadow.
+ */
+ if ( drawBallHow == DRAW_BALL_SHADOW )
+ glColor3f( 0.35f, 0.35f, 0.35f );
+
+ /*
+ * Assign each Y.
+ */
+ vert_ne.y = vert_nw.y = (float) cos_deg(long_hi) * RADIUS;
+ vert_sw.y = vert_se.y = (float) cos_deg(long_lo) * RADIUS;
+
+ /*
+ * Assign each X,Z with sin,cos values scaled by latitude radius indexed by longitude.
+ * Eg, long=0 and long=180 are at the poles, so zero scale is sin(longitude),
+ * while long=90 (sin(90)=1) is at equator.
+ */
+ vert_ne.x = (float) cos_deg( lat_deg ) * (RADIUS * (float) sin_deg( long_lo + STEP_LONGITUDE ));
+ vert_se.x = (float) cos_deg( lat_deg ) * (RADIUS * (float) sin_deg( long_lo ));
+ vert_nw.x = (float) cos_deg( lat_deg + STEP_LATITUDE ) * (RADIUS * (float) sin_deg( long_lo + STEP_LONGITUDE ));
+ vert_sw.x = (float) cos_deg( lat_deg + STEP_LATITUDE ) * (RADIUS * (float) sin_deg( long_lo ));
+
+ vert_ne.z = (float) sin_deg( lat_deg ) * (RADIUS * (float) sin_deg( long_lo + STEP_LONGITUDE ));
+ vert_se.z = (float) sin_deg( lat_deg ) * (RADIUS * (float) sin_deg( long_lo ));
+ vert_nw.z = (float) sin_deg( lat_deg + STEP_LATITUDE ) * (RADIUS * (float) sin_deg( long_lo + STEP_LONGITUDE ));
+ vert_sw.z = (float) sin_deg( lat_deg + STEP_LATITUDE ) * (RADIUS * (float) sin_deg( long_lo ));
+
+ /*
+ * Draw the facet.
+ */
+ glBegin( GL_POLYGON );
+
+ CrossProduct( vert_ne, vert_nw, vert_sw, &vert_norm );
+ glNormal3f( vert_norm.x, vert_norm.y, vert_norm.z );
+
+ glVertex3f( vert_ne.x, vert_ne.y, vert_ne.z );
+ glVertex3f( vert_nw.x, vert_nw.y, vert_nw.z );
+ glVertex3f( vert_sw.x, vert_sw.y, vert_sw.z );
+ glVertex3f( vert_se.x, vert_se.y, vert_se.z );
+
+ glEnd();
+
+#if BOING_DEBUG
+ printf( "----------------------------------------------------------- \n" );
+ printf( "lat = %f long_lo = %f long_hi = %f \n", lat_deg, long_lo, long_hi );
+ printf( "vert_ne x = %.8f y = %.8f z = %.8f \n", vert_ne.x, vert_ne.y, vert_ne.z );
+ printf( "vert_nw x = %.8f y = %.8f z = %.8f \n", vert_nw.x, vert_nw.y, vert_nw.z );
+ printf( "vert_se x = %.8f y = %.8f z = %.8f \n", vert_se.x, vert_se.y, vert_se.z );
+ printf( "vert_sw x = %.8f y = %.8f z = %.8f \n", vert_sw.x, vert_sw.y, vert_sw.z );
+#endif
+
+ }
+
+ /*
+ * Toggle color so that next band will opposite red/white colors than this one.
+ */
+ colorToggle = ! colorToggle;
+
+ /*
+ * This circular band is done.
+ */
+ return;
+}
+
+
+/*****************************************************************************
+ * Draw the purple grid of lines, behind the Boing ball.
+ * When the Workbench is dropped to the bottom, Boing shows 12 rows.
+ *****************************************************************************/
+void DrawGrid( void )
+{
+ int row, col;
+ const int rowTotal = 12; /* must be divisible by 2 */
+ const int colTotal = rowTotal; /* must be same as rowTotal */
+ const GLfloat widthLine = 2.0; /* should be divisible by 2 */
+ const GLfloat sizeCell = GRID_SIZE / rowTotal;
+ const GLfloat z_offset = -40.0;
+ GLfloat xl, xr;
+ GLfloat yt, yb;
+
+ glPushMatrix();
+ glDisable( GL_CULL_FACE );
+
+ /*
+ * Another relative Z translation to separate objects.
+ */
+ glTranslatef( 0.0, 0.0, DIST_BALL );
+
+ /*
+ * Draw vertical lines (as skinny 3D rectangles).
+ */
+ for ( col = 0; col <= colTotal; col++ )
+ {
+ /*
+ * Compute co-ords of line.
+ */
+ xl = -GRID_SIZE / 2 + col * sizeCell;
+ xr = xl + widthLine;
+
+ yt = GRID_SIZE / 2;
+ yb = -GRID_SIZE / 2 - widthLine;
+
+ glBegin( GL_POLYGON );
+
+ glColor3f( 0.6f, 0.1f, 0.6f ); /* purple */
+
+ glVertex3f( xr, yt, z_offset ); /* NE */
+ glVertex3f( xl, yt, z_offset ); /* NW */
+ glVertex3f( xl, yb, z_offset ); /* SW */
+ glVertex3f( xr, yb, z_offset ); /* SE */
+
+ glEnd();
+ }
+
+ /*
+ * Draw horizontal lines (as skinny 3D rectangles).
+ */
+ for ( row = 0; row <= rowTotal; row++ )
+ {
+ /*
+ * Compute co-ords of line.
+ */
+ yt = GRID_SIZE / 2 - row * sizeCell;
+ yb = yt - widthLine;
+
+ xl = -GRID_SIZE / 2;
+ xr = GRID_SIZE / 2 + widthLine;
+
+ glBegin( GL_POLYGON );
+
+ glColor3f( 0.6f, 0.1f, 0.6f ); /* purple */
+
+ glVertex3f( xr, yt, z_offset ); /* NE */
+ glVertex3f( xl, yt, z_offset ); /* NW */
+ glVertex3f( xl, yb, z_offset ); /* SW */
+ glVertex3f( xr, yb, z_offset ); /* SE */
+
+ glEnd();
+ }
+
+ glPopMatrix();
+
+ return;
+}
+
+
+/*======================================================================*
+ * main()
+ *======================================================================*/
+
+int main( void )
+{
+ GLFWwindow* window;
+
+ /* Init GLFW */
+ if( !glfwInit() )
+ exit( EXIT_FAILURE );
+
+ window = glfwCreateWindow( 400, 400, "Boing (classic Amiga demo)", NULL, NULL );
+ if (!window)
+ {
+ glfwTerminate();
+ exit( EXIT_FAILURE );
+ }
+
+ glfwSetWindowAspectRatio(window, 1, 1);
+
+ glfwSetFramebufferSizeCallback(window, reshape);
+ glfwSetKeyCallback(window, key_callback);
+ glfwSetMouseButtonCallback(window, mouse_button_callback);
+ glfwSetCursorPosCallback(window, cursor_position_callback);
+
+ glfwMakeContextCurrent(window);
+ gladLoadGL(glfwGetProcAddress);
+ glfwSwapInterval( 1 );
+
+ glfwGetFramebufferSize(window, &width, &height);
+ reshape(window, width, height);
+
+ glfwSetTime( 0.0 );
+
+ init();
+
+ /* Main loop */
+ for (;;)
+ {
+ /* Timing */
+ t = glfwGetTime();
+ dt = t - t_old;
+ t_old = t;
+
+ /* Draw one frame */
+ display();
+
+ /* Swap buffers */
+ glfwSwapBuffers(window);
+ glfwPollEvents();
+
+ /* Check if we are still running */
+ if (glfwWindowShouldClose(window))
+ break;
+ }
+
+ glfwTerminate();
+ exit( EXIT_SUCCESS );
+}
+