132001f49Smrg/*
232001f49Smrg * Copyright (C) 1999-2001  Brian Paul   All Rights Reserved.
332001f49Smrg *
432001f49Smrg * Permission is hereby granted, free of charge, to any person obtaining a
532001f49Smrg * copy of this software and associated documentation files (the "Software"),
632001f49Smrg * to deal in the Software without restriction, including without limitation
732001f49Smrg * the rights to use, copy, modify, merge, publish, distribute, sublicense,
832001f49Smrg * and/or sell copies of the Software, and to permit persons to whom the
932001f49Smrg * Software is furnished to do so, subject to the following conditions:
1032001f49Smrg *
1132001f49Smrg * The above copyright notice and this permission notice shall be included
1232001f49Smrg * in all copies or substantial portions of the Software.
1332001f49Smrg *
1432001f49Smrg * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
1532001f49Smrg * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
1632001f49Smrg * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
1732001f49Smrg * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
1832001f49Smrg * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
1932001f49Smrg * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
2032001f49Smrg */
2132001f49Smrg
2232001f49Smrg/**
2332001f49Smrg * \file glxgears_fbconfig.c
2432001f49Smrg * Yet-another-version of gears.  Originally ported to GLX by Brian Paul on
2532001f49Smrg * 23 March 2001.  Modified to use fbconfigs by Ian Romanick on 10 Feb 2004.
2632001f49Smrg *
2732001f49Smrg * Command line options:
2832001f49Smrg *    -info      print GL implementation information
2932001f49Smrg *
3032001f49Smrg * \author Brian Paul
3132001f49Smrg * \author Ian Romanick <idr@us.ibm.com>
3232001f49Smrg */
3332001f49Smrg
3432001f49Smrg
3532001f49Smrg#define GLX_GLXEXT_PROTOTYPES
3632001f49Smrg
3732001f49Smrg#include <math.h>
3832001f49Smrg#include <stdlib.h>
3932001f49Smrg#include <stdio.h>
4032001f49Smrg#include <string.h>
4132001f49Smrg#include <X11/Xlib.h>
4232001f49Smrg#include <X11/keysym.h>
4332001f49Smrg#include <GL/gl.h>
4432001f49Smrg#include <GL/glx.h>
4532001f49Smrg#include <GL/glxext.h>
4632001f49Smrg#include <assert.h>
4732001f49Smrg#include "pbutil.h"
4832001f49Smrg
4932001f49Smrgstatic PFNGLXCHOOSEFBCONFIGPROC choose_fbconfig = NULL;
5032001f49Smrgstatic PFNGLXGETVISUALFROMFBCONFIGPROC get_visual_from_fbconfig = NULL;
5132001f49Smrgstatic PFNGLXCREATENEWCONTEXTPROC create_new_context = NULL;
5232001f49Smrgstatic PFNGLXCREATEWINDOWPROC create_window = NULL;
5332001f49Smrgstatic PFNGLXDESTROYWINDOWPROC destroy_window = NULL;
5432001f49Smrg
5532001f49Smrg#define BENCHMARK
5632001f49Smrg
5732001f49Smrg#ifdef BENCHMARK
5832001f49Smrg
5932001f49Smrg/* XXX this probably isn't very portable */
6032001f49Smrg
6132001f49Smrg#include <sys/time.h>
6232001f49Smrg#include <unistd.h>
6332001f49Smrg
6432001f49Smrg/* return current time (in seconds) */
6532001f49Smrgstatic int
6632001f49Smrgcurrent_time(void)
6732001f49Smrg{
6832001f49Smrg   struct timeval tv;
6932001f49Smrg#ifdef __VMS
7032001f49Smrg   (void) gettimeofday(&tv, NULL );
7132001f49Smrg#else
7232001f49Smrg   struct timezone tz;
7332001f49Smrg   (void) gettimeofday(&tv, &tz);
7432001f49Smrg#endif
7532001f49Smrg   return (int) tv.tv_sec;
7632001f49Smrg}
7732001f49Smrg
7832001f49Smrg#else /*BENCHMARK*/
7932001f49Smrg
8032001f49Smrg/* dummy */
8132001f49Smrgstatic int
8232001f49Smrgcurrent_time(void)
8332001f49Smrg{
8432001f49Smrg   return 0;
8532001f49Smrg}
8632001f49Smrg
8732001f49Smrg#endif /*BENCHMARK*/
8832001f49Smrg
8932001f49Smrg
9032001f49Smrg
9132001f49Smrg#ifndef M_PI
9232001f49Smrg#define M_PI 3.14159265
9332001f49Smrg#endif
9432001f49Smrg
9532001f49Smrg
9632001f49Smrgstatic GLfloat view_rotx = 20.0, view_roty = 30.0, view_rotz = 0.0;
9732001f49Smrgstatic GLint gear1, gear2, gear3;
9832001f49Smrgstatic GLfloat angle = 0.0;
9932001f49Smrg
10032001f49Smrg
10132001f49Smrg/*
10232001f49Smrg *
10332001f49Smrg *  Draw a gear wheel.  You'll probably want to call this function when
10432001f49Smrg *  building a display list since we do a lot of trig here.
10532001f49Smrg *
10632001f49Smrg *  Input:  inner_radius - radius of hole at center
10732001f49Smrg *          outer_radius - radius at center of teeth
10832001f49Smrg *          width - width of gear
10932001f49Smrg *          teeth - number of teeth
11032001f49Smrg *          tooth_depth - depth of tooth
11132001f49Smrg */
11232001f49Smrgstatic void
11332001f49Smrggear(GLfloat inner_radius, GLfloat outer_radius, GLfloat width,
11432001f49Smrg     GLint teeth, GLfloat tooth_depth)
11532001f49Smrg{
11632001f49Smrg   GLint i;
11732001f49Smrg   GLfloat r0, r1, r2;
11832001f49Smrg   GLfloat angle, da;
11932001f49Smrg   GLfloat u, v, len;
12032001f49Smrg
12132001f49Smrg   r0 = inner_radius;
12232001f49Smrg   r1 = outer_radius - tooth_depth / 2.0;
12332001f49Smrg   r2 = outer_radius + tooth_depth / 2.0;
12432001f49Smrg
12532001f49Smrg   da = 2.0 * M_PI / teeth / 4.0;
12632001f49Smrg
12732001f49Smrg   glShadeModel(GL_FLAT);
12832001f49Smrg
12932001f49Smrg   glNormal3f(0.0, 0.0, 1.0);
13032001f49Smrg
13132001f49Smrg   /* draw front face */
13232001f49Smrg   glBegin(GL_QUAD_STRIP);
13332001f49Smrg   for (i = 0; i <= teeth; i++) {
13432001f49Smrg      angle = i * 2.0 * M_PI / teeth;
13532001f49Smrg      glVertex3f(r0 * cos(angle), r0 * sin(angle), width * 0.5);
13632001f49Smrg      glVertex3f(r1 * cos(angle), r1 * sin(angle), width * 0.5);
13732001f49Smrg      if (i < teeth) {
13832001f49Smrg	 glVertex3f(r0 * cos(angle), r0 * sin(angle), width * 0.5);
13932001f49Smrg	 glVertex3f(r1 * cos(angle + 3 * da), r1 * sin(angle + 3 * da),
14032001f49Smrg		    width * 0.5);
14132001f49Smrg      }
14232001f49Smrg   }
14332001f49Smrg   glEnd();
14432001f49Smrg
14532001f49Smrg   /* draw front sides of teeth */
14632001f49Smrg   glBegin(GL_QUADS);
14732001f49Smrg   da = 2.0 * M_PI / teeth / 4.0;
14832001f49Smrg   for (i = 0; i < teeth; i++) {
14932001f49Smrg      angle = i * 2.0 * M_PI / teeth;
15032001f49Smrg
15132001f49Smrg      glVertex3f(r1 * cos(angle), r1 * sin(angle), width * 0.5);
15232001f49Smrg      glVertex3f(r2 * cos(angle + da), r2 * sin(angle + da), width * 0.5);
15332001f49Smrg      glVertex3f(r2 * cos(angle + 2 * da), r2 * sin(angle + 2 * da),
15432001f49Smrg		 width * 0.5);
15532001f49Smrg      glVertex3f(r1 * cos(angle + 3 * da), r1 * sin(angle + 3 * da),
15632001f49Smrg		 width * 0.5);
15732001f49Smrg   }
15832001f49Smrg   glEnd();
15932001f49Smrg
16032001f49Smrg   glNormal3f(0.0, 0.0, -1.0);
16132001f49Smrg
16232001f49Smrg   /* draw back face */
16332001f49Smrg   glBegin(GL_QUAD_STRIP);
16432001f49Smrg   for (i = 0; i <= teeth; i++) {
16532001f49Smrg      angle = i * 2.0 * M_PI / teeth;
16632001f49Smrg      glVertex3f(r1 * cos(angle), r1 * sin(angle), -width * 0.5);
16732001f49Smrg      glVertex3f(r0 * cos(angle), r0 * sin(angle), -width * 0.5);
16832001f49Smrg      if (i < teeth) {
16932001f49Smrg	 glVertex3f(r1 * cos(angle + 3 * da), r1 * sin(angle + 3 * da),
17032001f49Smrg		    -width * 0.5);
17132001f49Smrg	 glVertex3f(r0 * cos(angle), r0 * sin(angle), -width * 0.5);
17232001f49Smrg      }
17332001f49Smrg   }
17432001f49Smrg   glEnd();
17532001f49Smrg
17632001f49Smrg   /* draw back sides of teeth */
17732001f49Smrg   glBegin(GL_QUADS);
17832001f49Smrg   da = 2.0 * M_PI / teeth / 4.0;
17932001f49Smrg   for (i = 0; i < teeth; i++) {
18032001f49Smrg      angle = i * 2.0 * M_PI / teeth;
18132001f49Smrg
18232001f49Smrg      glVertex3f(r1 * cos(angle + 3 * da), r1 * sin(angle + 3 * da),
18332001f49Smrg		 -width * 0.5);
18432001f49Smrg      glVertex3f(r2 * cos(angle + 2 * da), r2 * sin(angle + 2 * da),
18532001f49Smrg		 -width * 0.5);
18632001f49Smrg      glVertex3f(r2 * cos(angle + da), r2 * sin(angle + da), -width * 0.5);
18732001f49Smrg      glVertex3f(r1 * cos(angle), r1 * sin(angle), -width * 0.5);
18832001f49Smrg   }
18932001f49Smrg   glEnd();
19032001f49Smrg
19132001f49Smrg   /* draw outward faces of teeth */
19232001f49Smrg   glBegin(GL_QUAD_STRIP);
19332001f49Smrg   for (i = 0; i < teeth; i++) {
19432001f49Smrg      angle = i * 2.0 * M_PI / teeth;
19532001f49Smrg
19632001f49Smrg      glVertex3f(r1 * cos(angle), r1 * sin(angle), width * 0.5);
19732001f49Smrg      glVertex3f(r1 * cos(angle), r1 * sin(angle), -width * 0.5);
19832001f49Smrg      u = r2 * cos(angle + da) - r1 * cos(angle);
19932001f49Smrg      v = r2 * sin(angle + da) - r1 * sin(angle);
20032001f49Smrg      len = sqrt(u * u + v * v);
20132001f49Smrg      u /= len;
20232001f49Smrg      v /= len;
20332001f49Smrg      glNormal3f(v, -u, 0.0);
20432001f49Smrg      glVertex3f(r2 * cos(angle + da), r2 * sin(angle + da), width * 0.5);
20532001f49Smrg      glVertex3f(r2 * cos(angle + da), r2 * sin(angle + da), -width * 0.5);
20632001f49Smrg      glNormal3f(cos(angle), sin(angle), 0.0);
20732001f49Smrg      glVertex3f(r2 * cos(angle + 2 * da), r2 * sin(angle + 2 * da),
20832001f49Smrg		 width * 0.5);
20932001f49Smrg      glVertex3f(r2 * cos(angle + 2 * da), r2 * sin(angle + 2 * da),
21032001f49Smrg		 -width * 0.5);
21132001f49Smrg      u = r1 * cos(angle + 3 * da) - r2 * cos(angle + 2 * da);
21232001f49Smrg      v = r1 * sin(angle + 3 * da) - r2 * sin(angle + 2 * da);
21332001f49Smrg      glNormal3f(v, -u, 0.0);
21432001f49Smrg      glVertex3f(r1 * cos(angle + 3 * da), r1 * sin(angle + 3 * da),
21532001f49Smrg		 width * 0.5);
21632001f49Smrg      glVertex3f(r1 * cos(angle + 3 * da), r1 * sin(angle + 3 * da),
21732001f49Smrg		 -width * 0.5);
21832001f49Smrg      glNormal3f(cos(angle), sin(angle), 0.0);
21932001f49Smrg   }
22032001f49Smrg
22132001f49Smrg   glVertex3f(r1 * cos(0), r1 * sin(0), width * 0.5);
22232001f49Smrg   glVertex3f(r1 * cos(0), r1 * sin(0), -width * 0.5);
22332001f49Smrg
22432001f49Smrg   glEnd();
22532001f49Smrg
22632001f49Smrg   glShadeModel(GL_SMOOTH);
22732001f49Smrg
22832001f49Smrg   /* draw inside radius cylinder */
22932001f49Smrg   glBegin(GL_QUAD_STRIP);
23032001f49Smrg   for (i = 0; i <= teeth; i++) {
23132001f49Smrg      angle = i * 2.0 * M_PI / teeth;
23232001f49Smrg      glNormal3f(-cos(angle), -sin(angle), 0.0);
23332001f49Smrg      glVertex3f(r0 * cos(angle), r0 * sin(angle), -width * 0.5);
23432001f49Smrg      glVertex3f(r0 * cos(angle), r0 * sin(angle), width * 0.5);
23532001f49Smrg   }
23632001f49Smrg   glEnd();
23732001f49Smrg}
23832001f49Smrg
23932001f49Smrg
24032001f49Smrgstatic void
24132001f49Smrgdraw(void)
24232001f49Smrg{
24332001f49Smrg   glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
24432001f49Smrg
24532001f49Smrg   glPushMatrix();
24632001f49Smrg   glRotatef(view_rotx, 1.0, 0.0, 0.0);
24732001f49Smrg   glRotatef(view_roty, 0.0, 1.0, 0.0);
24832001f49Smrg   glRotatef(view_rotz, 0.0, 0.0, 1.0);
24932001f49Smrg
25032001f49Smrg   glPushMatrix();
25132001f49Smrg   glTranslatef(-3.0, -2.0, 0.0);
25232001f49Smrg   glRotatef(angle, 0.0, 0.0, 1.0);
25332001f49Smrg   glCallList(gear1);
25432001f49Smrg   glPopMatrix();
25532001f49Smrg
25632001f49Smrg   glPushMatrix();
25732001f49Smrg   glTranslatef(3.1, -2.0, 0.0);
25832001f49Smrg   glRotatef(-2.0 * angle - 9.0, 0.0, 0.0, 1.0);
25932001f49Smrg   glCallList(gear2);
26032001f49Smrg   glPopMatrix();
26132001f49Smrg
26232001f49Smrg   glPushMatrix();
26332001f49Smrg   glTranslatef(-3.1, 4.2, 0.0);
26432001f49Smrg   glRotatef(-2.0 * angle - 25.0, 0.0, 0.0, 1.0);
26532001f49Smrg   glCallList(gear3);
26632001f49Smrg   glPopMatrix();
26732001f49Smrg
26832001f49Smrg   glPopMatrix();
26932001f49Smrg}
27032001f49Smrg
27132001f49Smrg
27232001f49Smrg/* new window size or exposure */
27332001f49Smrgstatic void
27432001f49Smrgreshape(int width, int height)
27532001f49Smrg{
27632001f49Smrg   GLfloat h = (GLfloat) height / (GLfloat) width;
27732001f49Smrg
27832001f49Smrg   glViewport(0, 0, (GLint) width, (GLint) height);
27932001f49Smrg   glMatrixMode(GL_PROJECTION);
28032001f49Smrg   glLoadIdentity();
28132001f49Smrg   glFrustum(-1.0, 1.0, -h, h, 5.0, 60.0);
28232001f49Smrg   glMatrixMode(GL_MODELVIEW);
28332001f49Smrg   glLoadIdentity();
28432001f49Smrg   glTranslatef(0.0, 0.0, -40.0);
28532001f49Smrg}
28632001f49Smrg
28732001f49Smrg
28832001f49Smrgstatic void
28932001f49Smrginit(void)
29032001f49Smrg{
29132001f49Smrg   static GLfloat pos[4] = { 5.0, 5.0, 10.0, 0.0 };
29232001f49Smrg   static GLfloat red[4] = { 0.8, 0.1, 0.0, 1.0 };
29332001f49Smrg   static GLfloat green[4] = { 0.0, 0.8, 0.2, 1.0 };
29432001f49Smrg   static GLfloat blue[4] = { 0.2, 0.2, 1.0, 1.0 };
29532001f49Smrg
29632001f49Smrg   glLightfv(GL_LIGHT0, GL_POSITION, pos);
29732001f49Smrg   glEnable(GL_CULL_FACE);
29832001f49Smrg   glEnable(GL_LIGHTING);
29932001f49Smrg   glEnable(GL_LIGHT0);
30032001f49Smrg   glEnable(GL_DEPTH_TEST);
30132001f49Smrg
30232001f49Smrg   /* make the gears */
30332001f49Smrg   gear1 = glGenLists(1);
30432001f49Smrg   glNewList(gear1, GL_COMPILE);
30532001f49Smrg   glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, red);
30632001f49Smrg   gear(1.0, 4.0, 1.0, 20, 0.7);
30732001f49Smrg   glEndList();
30832001f49Smrg
30932001f49Smrg   gear2 = glGenLists(1);
31032001f49Smrg   glNewList(gear2, GL_COMPILE);
31132001f49Smrg   glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, green);
31232001f49Smrg   gear(0.5, 2.0, 2.0, 10, 0.7);
31332001f49Smrg   glEndList();
31432001f49Smrg
31532001f49Smrg   gear3 = glGenLists(1);
31632001f49Smrg   glNewList(gear3, GL_COMPILE);
31732001f49Smrg   glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, blue);
31832001f49Smrg   gear(1.3, 2.0, 0.5, 10, 0.7);
31932001f49Smrg   glEndList();
32032001f49Smrg
32132001f49Smrg   glEnable(GL_NORMALIZE);
32232001f49Smrg}
32332001f49Smrg
32432001f49Smrg
32532001f49Smrgstatic GLXWindow
32632001f49Smrgdummy_create_window(Display *dpy, GLXFBConfig config, Window win,
32732001f49Smrg                   const int *attrib_list)
32832001f49Smrg{
32932001f49Smrg   (void) dpy;
33032001f49Smrg   (void) config;
33132001f49Smrg   (void) attrib_list;
33232001f49Smrg
33332001f49Smrg   return (GLXWindow) win;
33432001f49Smrg}
33532001f49Smrg
33632001f49Smrg
33732001f49Smrgstatic void
33832001f49Smrgdummy_destroy_window(Display *dpy, GLXWindow win)
33932001f49Smrg{
34032001f49Smrg   (void) dpy;
34132001f49Smrg   (void) win;
34232001f49Smrg}
34332001f49Smrg
34432001f49Smrg
34532001f49Smrg/**
34632001f49Smrg * Initialize fbconfig related function pointers.
34732001f49Smrg */
34832001f49Smrgstatic void
34932001f49Smrginit_fbconfig_functions(Display *dpy, int scrnum)
35032001f49Smrg{
35132001f49Smrg   const char * glx_extensions;
35232001f49Smrg   const char * match;
35332001f49Smrg   static const char ext_name[] = "GLX_SGIX_fbconfig";
35432001f49Smrg   const size_t len = strlen( ext_name );
35532001f49Smrg   int major;
35632001f49Smrg   int minor;
35732001f49Smrg   GLboolean ext_version_supported;
35832001f49Smrg   GLboolean glx_1_3_supported;
35932001f49Smrg
36032001f49Smrg
36132001f49Smrg   /* Determine if GLX 1.3 or greater is supported.
36232001f49Smrg    */
36332001f49Smrg   glXQueryVersion(dpy, & major, & minor);
36432001f49Smrg   glx_1_3_supported = (major == 1) && (minor >= 3);
36532001f49Smrg
36632001f49Smrg   /* Determine if GLX_SGIX_fbconfig is supported.
36732001f49Smrg    */
36832001f49Smrg   glx_extensions = glXQueryExtensionsString(dpy, scrnum);
36932001f49Smrg   match = strstr( glx_extensions, ext_name );
37032001f49Smrg
37132001f49Smrg   ext_version_supported = (match != NULL)
37232001f49Smrg       && ((match[len] == '\0') || (match[len] == ' '));
37332001f49Smrg
37432001f49Smrg   printf( "GLX 1.3 is %ssupported.\n",
37532001f49Smrg	   (glx_1_3_supported) ? "" : "not " );
37632001f49Smrg   printf( "%s is %ssupported.\n",
37732001f49Smrg	   ext_name, (ext_version_supported) ? "" : "not " );
37832001f49Smrg
37932001f49Smrg   if ( glx_1_3_supported ) {
38032001f49Smrg      choose_fbconfig = (PFNGLXCHOOSEFBCONFIGPROC)
38132001f49Smrg	 glXGetProcAddressARB((GLubyte *) "glXChooseFBConfig");
38232001f49Smrg      get_visual_from_fbconfig = (PFNGLXGETVISUALFROMFBCONFIGPROC)
38332001f49Smrg	 glXGetProcAddressARB((GLubyte *) "glXGetVisualFromFBConfig");
38432001f49Smrg      create_new_context = (PFNGLXCREATENEWCONTEXTPROC)
38532001f49Smrg	 glXGetProcAddressARB((GLubyte *) "glXCreateNewContext");
38632001f49Smrg      create_window = (PFNGLXCREATEWINDOWPROC)
38732001f49Smrg	 glXGetProcAddressARB((GLubyte *) "glXCreateWindow");
38832001f49Smrg      destroy_window = (PFNGLXDESTROYWINDOWPROC)
38932001f49Smrg	 glXGetProcAddressARB((GLubyte *) "glXDestroyWindow");
39032001f49Smrg   }
39132001f49Smrg   else if ( ext_version_supported ) {
39232001f49Smrg      choose_fbconfig = (PFNGLXCHOOSEFBCONFIGPROC)
39332001f49Smrg	 glXGetProcAddressARB((GLubyte *) "glXChooseFBConfigSGIX");
39432001f49Smrg      get_visual_from_fbconfig = (PFNGLXGETVISUALFROMFBCONFIGPROC)
39532001f49Smrg	 glXGetProcAddressARB((GLubyte *) "glXGetVisualFromFBConfigSGIX");
39632001f49Smrg      create_new_context = (PFNGLXCREATENEWCONTEXTPROC)
39732001f49Smrg	 glXGetProcAddressARB((GLubyte *) "glXCreateContextWithConfigSGIX");
39832001f49Smrg      create_window = dummy_create_window;
39932001f49Smrg      destroy_window = dummy_destroy_window;
40032001f49Smrg   }
40132001f49Smrg   else {
40232001f49Smrg      printf( "This demo requires either GLX 1.3 or %s be supported.\n",
40332001f49Smrg	      ext_name );
40432001f49Smrg      exit(1);
40532001f49Smrg   }
40632001f49Smrg
40732001f49Smrg   if ( choose_fbconfig == NULL ) {
40832001f49Smrg      printf( "glXChooseFBConfig not found!\n" );
40932001f49Smrg      exit(1);
41032001f49Smrg   }
41132001f49Smrg
41232001f49Smrg   if ( get_visual_from_fbconfig == NULL ) {
41332001f49Smrg      printf( "glXGetVisualFromFBConfig not found!\n" );
41432001f49Smrg      exit(1);
41532001f49Smrg   }
41632001f49Smrg
41732001f49Smrg   if ( create_new_context == NULL ) {
41832001f49Smrg      printf( "glXCreateNewContext not found!\n" );
41932001f49Smrg      exit(1);
42032001f49Smrg   }
42132001f49Smrg}
42232001f49Smrg
42332001f49Smrg
42432001f49Smrg/*
42532001f49Smrg * Create an RGB, double-buffered window.
42632001f49Smrg * Return the window and context handles.
42732001f49Smrg */
42832001f49Smrgstatic void
42932001f49Smrgmake_window( Display *dpy, const char *name,
43032001f49Smrg             int x, int y, int width, int height,
43132001f49Smrg             Window *winRet, GLXWindow *glxWinRet, GLXContext *ctxRet)
43232001f49Smrg{
43332001f49Smrg   int attrib[] = { GLX_DRAWABLE_TYPE, GLX_WINDOW_BIT,
43432001f49Smrg		    GLX_RENDER_TYPE,   GLX_RGBA_BIT,
43532001f49Smrg		    GLX_RED_SIZE,      1,
43632001f49Smrg		    GLX_GREEN_SIZE,    1,
43732001f49Smrg		    GLX_BLUE_SIZE,     1,
43832001f49Smrg		    GLX_DOUBLEBUFFER,  GL_TRUE,
43932001f49Smrg		    GLX_DEPTH_SIZE,    1,
44032001f49Smrg		    None };
44132001f49Smrg   GLXFBConfig * fbconfig;
44232001f49Smrg   int num_configs;
44332001f49Smrg   int scrnum;
44432001f49Smrg   int i;
44532001f49Smrg   XSetWindowAttributes attr;
44632001f49Smrg   unsigned long mask;
44732001f49Smrg   Window root;
44832001f49Smrg   Window win;
44932001f49Smrg   GLXWindow glxWin;
45032001f49Smrg   GLXContext ctx;
45132001f49Smrg   XVisualInfo *visinfo;
45232001f49Smrg
45332001f49Smrg   scrnum = DefaultScreen( dpy );
45432001f49Smrg   root = RootWindow( dpy, scrnum );
45532001f49Smrg
45632001f49Smrg   init_fbconfig_functions(dpy, scrnum);
45732001f49Smrg   fbconfig = (*choose_fbconfig)(dpy, scrnum, attrib, & num_configs);
45832001f49Smrg   if (fbconfig == NULL) {
45932001f49Smrg      printf("Error: couldn't get an RGB, Double-buffered visual\n");
46032001f49Smrg      exit(1);
46132001f49Smrg   }
46232001f49Smrg
46332001f49Smrg   printf("\nThe following fbconfigs meet the requirements.  The first one "
46432001f49Smrg	  "will be used.\n\n");
46532001f49Smrg   for ( i = 0 ; i < num_configs ; i++ ) {
46632001f49Smrg      PrintFBConfigInfo(dpy, scrnum, fbconfig[i], GL_TRUE);
46732001f49Smrg   }
46832001f49Smrg
46932001f49Smrg   /* window attributes */
47032001f49Smrg   visinfo = (*get_visual_from_fbconfig)(dpy, fbconfig[0]);
47132001f49Smrg   assert(visinfo != NULL);
47232001f49Smrg   attr.background_pixel = 0;
47332001f49Smrg   attr.border_pixel = 0;
47432001f49Smrg   attr.colormap = XCreateColormap( dpy, root, visinfo->visual, AllocNone);
47532001f49Smrg   attr.event_mask = StructureNotifyMask | ExposureMask | KeyPressMask;
47632001f49Smrg   mask = CWBackPixel | CWBorderPixel | CWColormap | CWEventMask;
47732001f49Smrg
47832001f49Smrg   win = XCreateWindow( dpy, root, 0, 0, width, height,
47932001f49Smrg		        0, visinfo->depth, InputOutput,
48032001f49Smrg		        visinfo->visual, mask, &attr );
48132001f49Smrg
48232001f49Smrg   /* set hints and properties */
48332001f49Smrg   {
48432001f49Smrg      XSizeHints sizehints;
48532001f49Smrg      sizehints.x = x;
48632001f49Smrg      sizehints.y = y;
48732001f49Smrg      sizehints.width  = width;
48832001f49Smrg      sizehints.height = height;
48932001f49Smrg      sizehints.flags = USSize | USPosition;
49032001f49Smrg      XSetNormalHints(dpy, win, &sizehints);
49132001f49Smrg      XSetStandardProperties(dpy, win, name, name,
49232001f49Smrg                              None, (char **)NULL, 0, &sizehints);
49332001f49Smrg   }
49432001f49Smrg
49532001f49Smrg   glxWin = (*create_window)(dpy, fbconfig[0], win, NULL);
49632001f49Smrg
49732001f49Smrg   ctx = (*create_new_context)(dpy, fbconfig[0], GLX_RGBA_TYPE, NULL, GL_TRUE);
49832001f49Smrg   if (!ctx) {
49932001f49Smrg      printf("Error: glXCreateNewContext failed\n");
50032001f49Smrg      exit(1);
50132001f49Smrg   }
50232001f49Smrg
50332001f49Smrg   XFree(fbconfig);
50432001f49Smrg
50532001f49Smrg   *glxWinRet = glxWin;
50632001f49Smrg   *winRet = win;
50732001f49Smrg   *ctxRet = ctx;
50832001f49Smrg}
50932001f49Smrg
51032001f49Smrg
51132001f49Smrgstatic void
51232001f49Smrgevent_loop(Display *dpy, GLXWindow win)
51332001f49Smrg{
51432001f49Smrg   while (1) {
51532001f49Smrg      while (XPending(dpy) > 0) {
51632001f49Smrg         XEvent event;
51732001f49Smrg         XNextEvent(dpy, &event);
51832001f49Smrg         switch (event.type) {
51932001f49Smrg	 case Expose:
52032001f49Smrg            /* we'll redraw below */
52132001f49Smrg	    break;
52232001f49Smrg	 case ConfigureNotify:
52332001f49Smrg	    reshape(event.xconfigure.width, event.xconfigure.height);
52432001f49Smrg	    break;
52532001f49Smrg         case KeyPress:
52632001f49Smrg            {
52732001f49Smrg               char buffer[10];
52832001f49Smrg               int code;
52932001f49Smrg               code = XLookupKeysym(&event.xkey, 0);
53032001f49Smrg               if (code == XK_Left) {
53132001f49Smrg                  view_roty += 5.0;
53232001f49Smrg               }
53332001f49Smrg               else if (code == XK_Right) {
53432001f49Smrg                  view_roty -= 5.0;
53532001f49Smrg               }
53632001f49Smrg               else if (code == XK_Up) {
53732001f49Smrg                  view_rotx += 5.0;
53832001f49Smrg               }
53932001f49Smrg               else if (code == XK_Down) {
54032001f49Smrg                  view_rotx -= 5.0;
54132001f49Smrg               }
54232001f49Smrg               else {
54332001f49Smrg                  XLookupString(&event.xkey, buffer, sizeof(buffer),
54432001f49Smrg                                NULL, NULL);
54532001f49Smrg                  if (buffer[0] == 27) {
54632001f49Smrg                     /* escape */
54732001f49Smrg                     return;
54832001f49Smrg                  }
54932001f49Smrg               }
55032001f49Smrg            }
55132001f49Smrg         }
55232001f49Smrg      }
55332001f49Smrg
55432001f49Smrg      /* next frame */
55532001f49Smrg      angle += 2.0;
55632001f49Smrg
55732001f49Smrg      draw();
55832001f49Smrg      glXSwapBuffers(dpy, win);
55932001f49Smrg
56032001f49Smrg      /* calc framerate */
56132001f49Smrg      {
56232001f49Smrg         static int t0 = -1;
56332001f49Smrg         static int frames = 0;
56432001f49Smrg         int t = current_time();
56532001f49Smrg
56632001f49Smrg         if (t0 < 0)
56732001f49Smrg            t0 = t;
56832001f49Smrg
56932001f49Smrg         frames++;
57032001f49Smrg
57132001f49Smrg         if (t - t0 >= 5.0) {
57232001f49Smrg            GLfloat seconds = t - t0;
57332001f49Smrg            GLfloat fps = frames / seconds;
57432001f49Smrg            printf("%d frames in %3.1f seconds = %6.3f FPS\n", frames, seconds,
57532001f49Smrg                   fps);
57632001f49Smrg            fflush(stdout);
57732001f49Smrg            t0 = t;
57832001f49Smrg            frames = 0;
57932001f49Smrg         }
58032001f49Smrg      }
58132001f49Smrg   }
58232001f49Smrg}
58332001f49Smrg
58432001f49Smrg
58532001f49Smrgint
58632001f49Smrgmain(int argc, char *argv[])
58732001f49Smrg{
58832001f49Smrg   Display *dpy;
58932001f49Smrg   Window win;
59032001f49Smrg   GLXWindow glxWin;
59132001f49Smrg   GLXContext ctx;
59232001f49Smrg   const char *dpyName = NULL;
59332001f49Smrg   GLboolean printInfo = GL_FALSE;
59432001f49Smrg   int i;
59532001f49Smrg
59632001f49Smrg   for (i = 1; i < argc; i++) {
59732001f49Smrg      if (strcmp(argv[i], "-display") == 0) {
59832001f49Smrg         dpyName = argv[i+1];
59932001f49Smrg         i++;
60032001f49Smrg      }
60132001f49Smrg      else if (strcmp(argv[i], "-info") == 0) {
60232001f49Smrg         printInfo = GL_TRUE;
60332001f49Smrg      }
60432001f49Smrg   }
60532001f49Smrg
60632001f49Smrg   dpy = XOpenDisplay(dpyName);
60732001f49Smrg   if (!dpy) {
60832001f49Smrg      printf("Error: couldn't open display %s\n", XDisplayName(dpyName));
60932001f49Smrg      return -1;
61032001f49Smrg   }
61132001f49Smrg
61232001f49Smrg   make_window(dpy, "glxgears", 0, 0, 300, 300, &win, &glxWin, &ctx);
61332001f49Smrg   XMapWindow(dpy, win);
61432001f49Smrg   glXMakeCurrent(dpy, glxWin, ctx);
61532001f49Smrg
61632001f49Smrg   if (printInfo) {
61732001f49Smrg      printf("GL_RENDERER   = %s\n", (char *) glGetString(GL_RENDERER));
61832001f49Smrg      printf("GL_VERSION    = %s\n", (char *) glGetString(GL_VERSION));
61932001f49Smrg      printf("GL_VENDOR     = %s\n", (char *) glGetString(GL_VENDOR));
62032001f49Smrg      printf("GL_EXTENSIONS = %s\n", (char *) glGetString(GL_EXTENSIONS));
62132001f49Smrg   }
62232001f49Smrg
62332001f49Smrg   init();
62432001f49Smrg
62532001f49Smrg   event_loop(dpy, glxWin);
62632001f49Smrg
62732001f49Smrg   glXDestroyContext(dpy, ctx);
62832001f49Smrg   destroy_window(dpy, glxWin);
62932001f49Smrg   XDestroyWindow(dpy, win);
63032001f49Smrg   XCloseDisplay(dpy);
63132001f49Smrg
63232001f49Smrg   return 0;
63332001f49Smrg}
634