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 * This is a port of the infamous "gears" demo to straight GLX (i.e. no GLUT) 2432001f49Smrg * Port by Brian Paul 23 March 2001 2532001f49Smrg * 2632001f49Smrg * Modified by Ian Romanick <idr@us.ibm.com> 09 April 2003 to support 2732001f49Smrg * GLX_{MESA,SGI}_swap_control and GLX_OML_sync_control. 2832001f49Smrg * 2932001f49Smrg * Command line options: 3032001f49Smrg * -display Name of the display to use. 3132001f49Smrg * -info print GL implementation information 3232001f49Smrg * -swap N Attempt to set the swap interval to 1/N second 3332001f49Smrg * -forcegetrate Get the display refresh rate even if the required GLX 3432001f49Smrg * extension is not supported. 3532001f49Smrg */ 3632001f49Smrg 3732001f49Smrg 3832001f49Smrg#include <math.h> 3932001f49Smrg#include <stdlib.h> 4032001f49Smrg#include <stdio.h> 4132001f49Smrg#include <string.h> 4232001f49Smrg#include <X11/Xlib.h> 4332001f49Smrg#include <X11/keysym.h> 4432001f49Smrg#ifndef __VMS 4532001f49Smrg/*# include <stdint.h>*/ 4632001f49Smrg#endif 4732001f49Smrg# define GLX_GLXEXT_PROTOTYPES 4832001f49Smrg#include <GL/gl.h> 4932001f49Smrg#include <GL/glx.h> 5032001f49Smrg 5132001f49Smrg#ifndef GLX_MESA_swap_control 5232001f49Smrgtypedef GLint ( * PFNGLXSWAPINTERVALMESAPROC) (unsigned interval); 5332001f49Smrgtypedef GLint ( * PFNGLXGETSWAPINTERVALMESAPROC) ( void ); 5432001f49Smrg#endif 5532001f49Smrg 5632001f49Smrg#if !defined( GLX_OML_sync_control ) && defined( _STDINT_H ) 5732001f49Smrg#define GLX_OML_sync_control 1 5832001f49Smrgtypedef Bool ( * PFNGLXGETMSCRATEOMLPROC) (Display *dpy, GLXDrawable drawable, int32_t *numerator, int32_t *denominator); 5932001f49Smrg#endif 6032001f49Smrg 6132001f49Smrg#ifndef GLX_MESA_swap_frame_usage 6232001f49Smrg#define GLX_MESA_swap_frame_usage 1 6332001f49Smrgtypedef int ( * PFNGLXGETFRAMEUSAGEMESAPROC) (Display *dpy, GLXDrawable drawable, float * usage ); 6432001f49Smrg#endif 6532001f49Smrg 6632001f49Smrg#define BENCHMARK 6732001f49Smrg 6832001f49SmrgPFNGLXGETFRAMEUSAGEMESAPROC get_frame_usage = NULL; 6932001f49Smrg 7032001f49Smrg#ifdef BENCHMARK 7132001f49Smrg 7232001f49Smrg/* XXX this probably isn't very portable */ 7332001f49Smrg 7432001f49Smrg#include <sys/time.h> 7532001f49Smrg#include <unistd.h> 7632001f49Smrg 7732001f49Smrg#define NUL '\0' 7832001f49Smrg 7932001f49Smrg/* return current time (in seconds) */ 8032001f49Smrgstatic int 8132001f49Smrgcurrent_time(void) 8232001f49Smrg{ 8332001f49Smrg struct timeval tv; 8432001f49Smrg#ifdef __VMS 8532001f49Smrg (void) gettimeofday(&tv, NULL ); 8632001f49Smrg#else 8732001f49Smrg struct timezone tz; 8832001f49Smrg (void) gettimeofday(&tv, &tz); 8932001f49Smrg#endif 9032001f49Smrg return (int) tv.tv_sec; 9132001f49Smrg} 9232001f49Smrg 9332001f49Smrg#else /*BENCHMARK*/ 9432001f49Smrg 9532001f49Smrg/* dummy */ 9632001f49Smrgstatic int 9732001f49Smrgcurrent_time(void) 9832001f49Smrg{ 9932001f49Smrg return 0; 10032001f49Smrg} 10132001f49Smrg 10232001f49Smrg#endif /*BENCHMARK*/ 10332001f49Smrg 10432001f49Smrg 10532001f49Smrg 10632001f49Smrg#ifndef M_PI 10732001f49Smrg#define M_PI 3.14159265 10832001f49Smrg#endif 10932001f49Smrg 11032001f49Smrg 11132001f49Smrgstatic GLfloat view_rotx = 20.0, view_roty = 30.0, view_rotz = 0.0; 11232001f49Smrgstatic GLint gear1, gear2, gear3; 11332001f49Smrgstatic GLfloat angle = 0.0; 11432001f49Smrg 11532001f49Smrgstatic GLboolean has_OML_sync_control = GL_FALSE; 11632001f49Smrgstatic GLboolean has_SGI_swap_control = GL_FALSE; 11732001f49Smrgstatic GLboolean has_MESA_swap_control = GL_FALSE; 11832001f49Smrgstatic GLboolean has_MESA_swap_frame_usage = GL_FALSE; 11932001f49Smrg 12032001f49Smrgstatic char ** extension_table = NULL; 12132001f49Smrgstatic unsigned num_extensions; 12232001f49Smrg 12332001f49Smrgstatic GLboolean use_ztrick = GL_FALSE; 12432001f49Smrgstatic GLfloat aspectX = 1.0f, aspectY = 1.0f; 12532001f49Smrg 12632001f49Smrg/* 12732001f49Smrg * 12832001f49Smrg * Draw a gear wheel. You'll probably want to call this function when 12932001f49Smrg * building a display list since we do a lot of trig here. 13032001f49Smrg * 13132001f49Smrg * Input: inner_radius - radius of hole at center 13232001f49Smrg * outer_radius - radius at center of teeth 13332001f49Smrg * width - width of gear 13432001f49Smrg * teeth - number of teeth 13532001f49Smrg * tooth_depth - depth of tooth 13632001f49Smrg */ 13732001f49Smrgstatic void 13832001f49Smrggear(GLfloat inner_radius, GLfloat outer_radius, GLfloat width, 13932001f49Smrg GLint teeth, GLfloat tooth_depth) 14032001f49Smrg{ 14132001f49Smrg GLint i; 14232001f49Smrg GLfloat r0, r1, r2; 14332001f49Smrg GLfloat angle, da; 14432001f49Smrg GLfloat u, v, len; 14532001f49Smrg 14632001f49Smrg r0 = inner_radius; 14732001f49Smrg r1 = outer_radius - tooth_depth / 2.0; 14832001f49Smrg r2 = outer_radius + tooth_depth / 2.0; 14932001f49Smrg 15032001f49Smrg da = 2.0 * M_PI / teeth / 4.0; 15132001f49Smrg 15232001f49Smrg glShadeModel(GL_FLAT); 15332001f49Smrg 15432001f49Smrg glNormal3f(0.0, 0.0, 1.0); 15532001f49Smrg 15632001f49Smrg /* draw front face */ 15732001f49Smrg glBegin(GL_QUAD_STRIP); 15832001f49Smrg for (i = 0; i <= teeth; i++) { 15932001f49Smrg angle = i * 2.0 * M_PI / teeth; 16032001f49Smrg glVertex3f(r0 * cos(angle), r0 * sin(angle), width * 0.5); 16132001f49Smrg glVertex3f(r1 * cos(angle), r1 * sin(angle), width * 0.5); 16232001f49Smrg if (i < teeth) { 16332001f49Smrg glVertex3f(r0 * cos(angle), r0 * sin(angle), width * 0.5); 16432001f49Smrg glVertex3f(r1 * cos(angle + 3 * da), r1 * sin(angle + 3 * da), 16532001f49Smrg width * 0.5); 16632001f49Smrg } 16732001f49Smrg } 16832001f49Smrg glEnd(); 16932001f49Smrg 17032001f49Smrg /* draw front sides of teeth */ 17132001f49Smrg glBegin(GL_QUADS); 17232001f49Smrg da = 2.0 * M_PI / teeth / 4.0; 17332001f49Smrg for (i = 0; i < teeth; i++) { 17432001f49Smrg angle = i * 2.0 * M_PI / teeth; 17532001f49Smrg 17632001f49Smrg glVertex3f(r1 * cos(angle), r1 * sin(angle), width * 0.5); 17732001f49Smrg glVertex3f(r2 * cos(angle + da), r2 * sin(angle + da), width * 0.5); 17832001f49Smrg glVertex3f(r2 * cos(angle + 2 * da), r2 * sin(angle + 2 * da), 17932001f49Smrg width * 0.5); 18032001f49Smrg glVertex3f(r1 * cos(angle + 3 * da), r1 * sin(angle + 3 * da), 18132001f49Smrg width * 0.5); 18232001f49Smrg } 18332001f49Smrg glEnd(); 18432001f49Smrg 18532001f49Smrg glNormal3f(0.0, 0.0, -1.0); 18632001f49Smrg 18732001f49Smrg /* draw back face */ 18832001f49Smrg glBegin(GL_QUAD_STRIP); 18932001f49Smrg for (i = 0; i <= teeth; i++) { 19032001f49Smrg angle = i * 2.0 * M_PI / teeth; 19132001f49Smrg glVertex3f(r1 * cos(angle), r1 * sin(angle), -width * 0.5); 19232001f49Smrg glVertex3f(r0 * cos(angle), r0 * sin(angle), -width * 0.5); 19332001f49Smrg if (i < teeth) { 19432001f49Smrg glVertex3f(r1 * cos(angle + 3 * da), r1 * sin(angle + 3 * da), 19532001f49Smrg -width * 0.5); 19632001f49Smrg glVertex3f(r0 * cos(angle), r0 * sin(angle), -width * 0.5); 19732001f49Smrg } 19832001f49Smrg } 19932001f49Smrg glEnd(); 20032001f49Smrg 20132001f49Smrg /* draw back sides of teeth */ 20232001f49Smrg glBegin(GL_QUADS); 20332001f49Smrg da = 2.0 * M_PI / teeth / 4.0; 20432001f49Smrg for (i = 0; i < teeth; i++) { 20532001f49Smrg angle = i * 2.0 * M_PI / teeth; 20632001f49Smrg 20732001f49Smrg glVertex3f(r1 * cos(angle + 3 * da), r1 * sin(angle + 3 * da), 20832001f49Smrg -width * 0.5); 20932001f49Smrg glVertex3f(r2 * cos(angle + 2 * da), r2 * sin(angle + 2 * da), 21032001f49Smrg -width * 0.5); 21132001f49Smrg glVertex3f(r2 * cos(angle + da), r2 * sin(angle + da), -width * 0.5); 21232001f49Smrg glVertex3f(r1 * cos(angle), r1 * sin(angle), -width * 0.5); 21332001f49Smrg } 21432001f49Smrg glEnd(); 21532001f49Smrg 21632001f49Smrg /* draw outward faces of teeth */ 21732001f49Smrg glBegin(GL_QUAD_STRIP); 21832001f49Smrg for (i = 0; i < teeth; i++) { 21932001f49Smrg angle = i * 2.0 * M_PI / teeth; 22032001f49Smrg 22132001f49Smrg glVertex3f(r1 * cos(angle), r1 * sin(angle), width * 0.5); 22232001f49Smrg glVertex3f(r1 * cos(angle), r1 * sin(angle), -width * 0.5); 22332001f49Smrg u = r2 * cos(angle + da) - r1 * cos(angle); 22432001f49Smrg v = r2 * sin(angle + da) - r1 * sin(angle); 22532001f49Smrg len = sqrt(u * u + v * v); 22632001f49Smrg u /= len; 22732001f49Smrg v /= len; 22832001f49Smrg glNormal3f(v, -u, 0.0); 22932001f49Smrg glVertex3f(r2 * cos(angle + da), r2 * sin(angle + da), width * 0.5); 23032001f49Smrg glVertex3f(r2 * cos(angle + da), r2 * sin(angle + da), -width * 0.5); 23132001f49Smrg glNormal3f(cos(angle), sin(angle), 0.0); 23232001f49Smrg glVertex3f(r2 * cos(angle + 2 * da), r2 * sin(angle + 2 * da), 23332001f49Smrg width * 0.5); 23432001f49Smrg glVertex3f(r2 * cos(angle + 2 * da), r2 * sin(angle + 2 * da), 23532001f49Smrg -width * 0.5); 23632001f49Smrg u = r1 * cos(angle + 3 * da) - r2 * cos(angle + 2 * da); 23732001f49Smrg v = r1 * sin(angle + 3 * da) - r2 * sin(angle + 2 * da); 23832001f49Smrg glNormal3f(v, -u, 0.0); 23932001f49Smrg glVertex3f(r1 * cos(angle + 3 * da), r1 * sin(angle + 3 * da), 24032001f49Smrg width * 0.5); 24132001f49Smrg glVertex3f(r1 * cos(angle + 3 * da), r1 * sin(angle + 3 * da), 24232001f49Smrg -width * 0.5); 24332001f49Smrg glNormal3f(cos(angle), sin(angle), 0.0); 24432001f49Smrg } 24532001f49Smrg 24632001f49Smrg glVertex3f(r1 * cos(0), r1 * sin(0), width * 0.5); 24732001f49Smrg glVertex3f(r1 * cos(0), r1 * sin(0), -width * 0.5); 24832001f49Smrg 24932001f49Smrg glEnd(); 25032001f49Smrg 25132001f49Smrg glShadeModel(GL_SMOOTH); 25232001f49Smrg 25332001f49Smrg /* draw inside radius cylinder */ 25432001f49Smrg glBegin(GL_QUAD_STRIP); 25532001f49Smrg for (i = 0; i <= teeth; i++) { 25632001f49Smrg angle = i * 2.0 * M_PI / teeth; 25732001f49Smrg glNormal3f(-cos(angle), -sin(angle), 0.0); 25832001f49Smrg glVertex3f(r0 * cos(angle), r0 * sin(angle), -width * 0.5); 25932001f49Smrg glVertex3f(r0 * cos(angle), r0 * sin(angle), width * 0.5); 26032001f49Smrg } 26132001f49Smrg glEnd(); 26232001f49Smrg} 26332001f49Smrg 26432001f49Smrg 26532001f49Smrgstatic void 26632001f49Smrgdraw(void) 26732001f49Smrg{ 26832001f49Smrg if ( use_ztrick ) { 26932001f49Smrg static GLboolean flip = GL_FALSE; 27032001f49Smrg static const GLfloat vert[4][3] = { 27132001f49Smrg { -1, -1, -0.999 }, 27232001f49Smrg { 1, -1, -0.999 }, 27332001f49Smrg { 1, 1, -0.999 }, 27432001f49Smrg { -1, 1, -0.999 } 27532001f49Smrg }; 27632001f49Smrg static const GLfloat col[4][3] = { 27732001f49Smrg { 1.0, 0.6, 0.0 }, 27832001f49Smrg { 1.0, 0.6, 0.0 }, 27932001f49Smrg { 0.0, 0.0, 0.0 }, 28032001f49Smrg { 0.0, 0.0, 0.0 }, 28132001f49Smrg }; 28232001f49Smrg 28332001f49Smrg if ( flip ) { 28432001f49Smrg glDepthRange(0, 0.5); 28532001f49Smrg glDepthFunc(GL_LEQUAL); 28632001f49Smrg } 28732001f49Smrg else { 28832001f49Smrg glDepthRange(1.0, 0.4999); 28932001f49Smrg glDepthFunc(GL_GEQUAL); 29032001f49Smrg } 29132001f49Smrg 29232001f49Smrg flip = !flip; 29332001f49Smrg 29432001f49Smrg /* The famous Quake "Z trick" only works when the whole screen is 29532001f49Smrg * re-drawn each frame. 29632001f49Smrg */ 29732001f49Smrg 29832001f49Smrg glMatrixMode(GL_MODELVIEW); 29932001f49Smrg glLoadIdentity(); 30032001f49Smrg glMatrixMode(GL_PROJECTION); 30132001f49Smrg glLoadIdentity(); 30232001f49Smrg glOrtho(-1, 1, -1, 1, -1, 1); 30332001f49Smrg glDisable(GL_LIGHTING); 30432001f49Smrg glShadeModel(GL_SMOOTH); 30532001f49Smrg 30632001f49Smrg glEnableClientState( GL_VERTEX_ARRAY ); 30732001f49Smrg glEnableClientState( GL_COLOR_ARRAY ); 30832001f49Smrg glVertexPointer( 3, GL_FLOAT, 0, vert ); 30932001f49Smrg glColorPointer( 3, GL_FLOAT, 0, col ); 31032001f49Smrg glDrawArrays( GL_POLYGON, 0, 4 ); 31132001f49Smrg glDisableClientState( GL_COLOR_ARRAY ); 31232001f49Smrg glDisableClientState( GL_VERTEX_ARRAY ); 31332001f49Smrg 31432001f49Smrg glMatrixMode(GL_PROJECTION); 31532001f49Smrg glLoadIdentity(); 31632001f49Smrg glFrustum(-aspectX, aspectX, -aspectY, aspectY, 5.0, 60.0); 31732001f49Smrg 31832001f49Smrg glEnable(GL_LIGHTING); 31932001f49Smrg 32032001f49Smrg glMatrixMode(GL_MODELVIEW); 32132001f49Smrg glLoadIdentity(); 32232001f49Smrg glTranslatef(0.0, 0.0, -45.0); 32332001f49Smrg } 32432001f49Smrg else { 32532001f49Smrg glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); 32632001f49Smrg } 32732001f49Smrg 32832001f49Smrg glPushMatrix(); 32932001f49Smrg glRotatef(view_rotx, 1.0, 0.0, 0.0); 33032001f49Smrg glRotatef(view_roty, 0.0, 1.0, 0.0); 33132001f49Smrg glRotatef(view_rotz, 0.0, 0.0, 1.0); 33232001f49Smrg 33332001f49Smrg glPushMatrix(); 33432001f49Smrg glTranslatef(-3.0, -2.0, 0.0); 33532001f49Smrg glRotatef(angle, 0.0, 0.0, 1.0); 33632001f49Smrg glCallList(gear1); 33732001f49Smrg glPopMatrix(); 33832001f49Smrg 33932001f49Smrg glPushMatrix(); 34032001f49Smrg glTranslatef(3.1, -2.0, 0.0); 34132001f49Smrg glRotatef(-2.0 * angle - 9.0, 0.0, 0.0, 1.0); 34232001f49Smrg glCallList(gear2); 34332001f49Smrg glPopMatrix(); 34432001f49Smrg 34532001f49Smrg glPushMatrix(); 34632001f49Smrg glTranslatef(-3.1, 4.2, 0.0); 34732001f49Smrg glRotatef(-2.0 * angle - 25.0, 0.0, 0.0, 1.0); 34832001f49Smrg glCallList(gear3); 34932001f49Smrg glPopMatrix(); 35032001f49Smrg 35132001f49Smrg glPopMatrix(); 35232001f49Smrg} 35332001f49Smrg 35432001f49Smrg 35532001f49Smrg/* new window size or exposure */ 35632001f49Smrgstatic void 35732001f49Smrgreshape(int width, int height) 35832001f49Smrg{ 35932001f49Smrg if (width > height) { 36032001f49Smrg aspectX = (GLfloat) width / (GLfloat) height; 36132001f49Smrg aspectY = 1.0; 36232001f49Smrg } 36332001f49Smrg else { 36432001f49Smrg aspectX = 1.0; 36532001f49Smrg aspectY = (GLfloat) height / (GLfloat) width; 36632001f49Smrg } 36732001f49Smrg 36832001f49Smrg glViewport(0, 0, (GLint) width, (GLint) height); 36932001f49Smrg glMatrixMode(GL_PROJECTION); 37032001f49Smrg glLoadIdentity(); 37132001f49Smrg 37232001f49Smrg glFrustum(-aspectX, aspectX, -aspectY, aspectY, 5.0, 60.0); 37332001f49Smrg glMatrixMode(GL_MODELVIEW); 37432001f49Smrg glLoadIdentity(); 37532001f49Smrg glTranslatef(0.0, 0.0, -45.0); 37632001f49Smrg} 37732001f49Smrg 37832001f49Smrg 37932001f49Smrgstatic void 38032001f49Smrginit(void) 38132001f49Smrg{ 38232001f49Smrg static GLfloat pos[4] = { 5.0, 5.0, 10.0, 0.0 }; 38332001f49Smrg static GLfloat red[4] = { 0.8, 0.1, 0.0, 1.0 }; 38432001f49Smrg static GLfloat green[4] = { 0.0, 0.8, 0.2, 1.0 }; 38532001f49Smrg static GLfloat blue[4] = { 0.2, 0.2, 1.0, 1.0 }; 38632001f49Smrg 38732001f49Smrg glLightfv(GL_LIGHT0, GL_POSITION, pos); 38832001f49Smrg glEnable(GL_CULL_FACE); 38932001f49Smrg glEnable(GL_LIGHTING); 39032001f49Smrg glEnable(GL_LIGHT0); 39132001f49Smrg glEnable(GL_DEPTH_TEST); 39232001f49Smrg 39332001f49Smrg /* make the gears */ 39432001f49Smrg gear1 = glGenLists(1); 39532001f49Smrg glNewList(gear1, GL_COMPILE); 39632001f49Smrg glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, red); 39732001f49Smrg gear(1.0, 4.0, 1.0, 20, 0.7); 39832001f49Smrg glEndList(); 39932001f49Smrg 40032001f49Smrg gear2 = glGenLists(1); 40132001f49Smrg glNewList(gear2, GL_COMPILE); 40232001f49Smrg glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, green); 40332001f49Smrg gear(0.5, 2.0, 2.0, 10, 0.7); 40432001f49Smrg glEndList(); 40532001f49Smrg 40632001f49Smrg gear3 = glGenLists(1); 40732001f49Smrg glNewList(gear3, GL_COMPILE); 40832001f49Smrg glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, blue); 40932001f49Smrg gear(1.3, 2.0, 0.5, 10, 0.7); 41032001f49Smrg glEndList(); 41132001f49Smrg 41232001f49Smrg glEnable(GL_NORMALIZE); 41332001f49Smrg} 41432001f49Smrg 41532001f49Smrg 41632001f49Smrg/** 41732001f49Smrg * Remove window border/decorations. 41832001f49Smrg */ 41932001f49Smrgstatic void 42032001f49Smrgno_border( Display *dpy, Window w) 42132001f49Smrg{ 42232001f49Smrg static const unsigned MWM_HINTS_DECORATIONS = (1 << 1); 42332001f49Smrg static const int PROP_MOTIF_WM_HINTS_ELEMENTS = 5; 42432001f49Smrg 42532001f49Smrg typedef struct 42632001f49Smrg { 42732001f49Smrg unsigned long flags; 42832001f49Smrg unsigned long functions; 42932001f49Smrg unsigned long decorations; 43032001f49Smrg long inputMode; 43132001f49Smrg unsigned long status; 43232001f49Smrg } PropMotifWmHints; 43332001f49Smrg 43432001f49Smrg PropMotifWmHints motif_hints; 43532001f49Smrg Atom prop, proptype; 43632001f49Smrg unsigned long flags = 0; 43732001f49Smrg 43832001f49Smrg /* setup the property */ 43932001f49Smrg motif_hints.flags = MWM_HINTS_DECORATIONS; 44032001f49Smrg motif_hints.decorations = flags; 44132001f49Smrg 44232001f49Smrg /* get the atom for the property */ 44332001f49Smrg prop = XInternAtom( dpy, "_MOTIF_WM_HINTS", True ); 44432001f49Smrg if (!prop) { 44532001f49Smrg /* something went wrong! */ 44632001f49Smrg return; 44732001f49Smrg } 44832001f49Smrg 44932001f49Smrg /* not sure this is correct, seems to work, XA_WM_HINTS didn't work */ 45032001f49Smrg proptype = prop; 45132001f49Smrg 45232001f49Smrg XChangeProperty( dpy, w, /* display, window */ 45332001f49Smrg prop, proptype, /* property, type */ 45432001f49Smrg 32, /* format: 32-bit datums */ 45532001f49Smrg PropModeReplace, /* mode */ 45632001f49Smrg (unsigned char *) &motif_hints, /* data */ 45732001f49Smrg PROP_MOTIF_WM_HINTS_ELEMENTS /* nelements */ 45832001f49Smrg ); 45932001f49Smrg} 46032001f49Smrg 46132001f49Smrg 46232001f49Smrg/* 46332001f49Smrg * Create an RGB, double-buffered window. 46432001f49Smrg * Return the window and context handles. 46532001f49Smrg */ 46632001f49Smrgstatic void 46732001f49Smrgmake_window( Display *dpy, const char *name, 46832001f49Smrg int x, int y, int width, int height, GLboolean fullscreen, 46932001f49Smrg Window *winRet, GLXContext *ctxRet) 47032001f49Smrg{ 47132001f49Smrg int attrib[] = { GLX_RGBA, 47232001f49Smrg GLX_RED_SIZE, 1, 47332001f49Smrg GLX_GREEN_SIZE, 1, 47432001f49Smrg GLX_BLUE_SIZE, 1, 47532001f49Smrg GLX_DOUBLEBUFFER, 47632001f49Smrg GLX_DEPTH_SIZE, 1, 47732001f49Smrg None }; 47832001f49Smrg int scrnum; 47932001f49Smrg XSetWindowAttributes attr; 48032001f49Smrg unsigned long mask; 48132001f49Smrg Window root; 48232001f49Smrg Window win; 48332001f49Smrg GLXContext ctx; 48432001f49Smrg XVisualInfo *visinfo; 48532001f49Smrg 48632001f49Smrg scrnum = DefaultScreen( dpy ); 48732001f49Smrg root = RootWindow( dpy, scrnum ); 48832001f49Smrg 48932001f49Smrg if (fullscreen) { 49032001f49Smrg x = y = 0; 49132001f49Smrg width = DisplayWidth( dpy, scrnum ); 49232001f49Smrg height = DisplayHeight( dpy, scrnum ); 49332001f49Smrg } 49432001f49Smrg 49532001f49Smrg visinfo = glXChooseVisual( dpy, scrnum, attrib ); 49632001f49Smrg if (!visinfo) { 49732001f49Smrg printf("Error: couldn't get an RGB, Double-buffered visual\n"); 49832001f49Smrg exit(1); 49932001f49Smrg } 50032001f49Smrg 50132001f49Smrg /* window attributes */ 50232001f49Smrg attr.background_pixel = 0; 50332001f49Smrg attr.border_pixel = 0; 50432001f49Smrg attr.colormap = XCreateColormap( dpy, root, visinfo->visual, AllocNone); 50532001f49Smrg attr.event_mask = StructureNotifyMask | ExposureMask | KeyPressMask; 50632001f49Smrg mask = CWBackPixel | CWBorderPixel | CWColormap | CWEventMask; 50732001f49Smrg 50832001f49Smrg win = XCreateWindow( dpy, root, 0, 0, width, height, 50932001f49Smrg 0, visinfo->depth, InputOutput, 51032001f49Smrg visinfo->visual, mask, &attr ); 51132001f49Smrg 51232001f49Smrg /* set hints and properties */ 51332001f49Smrg { 51432001f49Smrg XSizeHints sizehints; 51532001f49Smrg sizehints.x = x; 51632001f49Smrg sizehints.y = y; 51732001f49Smrg sizehints.width = width; 51832001f49Smrg sizehints.height = height; 51932001f49Smrg sizehints.flags = USSize | USPosition; 52032001f49Smrg XSetNormalHints(dpy, win, &sizehints); 52132001f49Smrg XSetStandardProperties(dpy, win, name, name, 52232001f49Smrg None, (char **)NULL, 0, &sizehints); 52332001f49Smrg } 52432001f49Smrg 52532001f49Smrg if (fullscreen) 52632001f49Smrg no_border(dpy, win); 52732001f49Smrg 52832001f49Smrg ctx = glXCreateContext( dpy, visinfo, NULL, True ); 52932001f49Smrg if (!ctx) { 53032001f49Smrg printf("Error: glXCreateContext failed\n"); 53132001f49Smrg exit(1); 53232001f49Smrg } 53332001f49Smrg 53432001f49Smrg XFree(visinfo); 53532001f49Smrg 53632001f49Smrg *winRet = win; 53732001f49Smrg *ctxRet = ctx; 53832001f49Smrg} 53932001f49Smrg 54032001f49Smrg 54132001f49Smrgstatic void 54232001f49Smrgevent_loop(Display *dpy, Window win) 54332001f49Smrg{ 54432001f49Smrg float frame_usage = 0.0; 54532001f49Smrg 54632001f49Smrg while (1) { 54732001f49Smrg while (XPending(dpy) > 0) { 54832001f49Smrg XEvent event; 54932001f49Smrg XNextEvent(dpy, &event); 55032001f49Smrg switch (event.type) { 55132001f49Smrg case Expose: 55232001f49Smrg /* we'll redraw below */ 55332001f49Smrg break; 55432001f49Smrg case ConfigureNotify: 55532001f49Smrg reshape(event.xconfigure.width, event.xconfigure.height); 55632001f49Smrg break; 55732001f49Smrg case KeyPress: 55832001f49Smrg { 55932001f49Smrg char buffer[10]; 56032001f49Smrg int code; 56132001f49Smrg code = XLookupKeysym(&event.xkey, 0); 56232001f49Smrg if (code == XK_Left) { 56332001f49Smrg view_roty += 5.0; 56432001f49Smrg } 56532001f49Smrg else if (code == XK_Right) { 56632001f49Smrg view_roty -= 5.0; 56732001f49Smrg } 56832001f49Smrg else if (code == XK_Up) { 56932001f49Smrg view_rotx += 5.0; 57032001f49Smrg } 57132001f49Smrg else if (code == XK_Down) { 57232001f49Smrg view_rotx -= 5.0; 57332001f49Smrg } 57432001f49Smrg else { 57532001f49Smrg XLookupString(&event.xkey, buffer, sizeof(buffer), 57632001f49Smrg NULL, NULL); 57732001f49Smrg if (buffer[0] == 27) { 57832001f49Smrg /* escape */ 57932001f49Smrg return; 58032001f49Smrg } 58132001f49Smrg } 58232001f49Smrg } 58332001f49Smrg } 58432001f49Smrg } 58532001f49Smrg 58632001f49Smrg /* next frame */ 58732001f49Smrg angle += 2.0; 58832001f49Smrg 58932001f49Smrg draw(); 59032001f49Smrg 59132001f49Smrg glXSwapBuffers(dpy, win); 59232001f49Smrg 59332001f49Smrg if ( get_frame_usage != NULL ) { 59432001f49Smrg GLfloat temp; 59532001f49Smrg 59632001f49Smrg (*get_frame_usage)( dpy, win, & temp ); 59732001f49Smrg frame_usage += temp; 59832001f49Smrg } 59932001f49Smrg 60032001f49Smrg /* calc framerate */ 60132001f49Smrg { 60232001f49Smrg static int t0 = -1; 60332001f49Smrg static int frames = 0; 60432001f49Smrg int t = current_time(); 60532001f49Smrg 60632001f49Smrg if (t0 < 0) 60732001f49Smrg t0 = t; 60832001f49Smrg 60932001f49Smrg frames++; 61032001f49Smrg 61132001f49Smrg if (t - t0 >= 5.0) { 61232001f49Smrg GLfloat seconds = t - t0; 61332001f49Smrg GLfloat fps = frames / seconds; 61432001f49Smrg if ( get_frame_usage != NULL ) { 61532001f49Smrg printf("%d frames in %3.1f seconds = %6.3f FPS (%3.1f%% usage)\n", 61632001f49Smrg frames, seconds, fps, 61732001f49Smrg (frame_usage * 100.0) / (float) frames ); 61832001f49Smrg } 61932001f49Smrg else { 62032001f49Smrg printf("%d frames in %3.1f seconds = %6.3f FPS\n", 62132001f49Smrg frames, seconds, fps); 62232001f49Smrg } 62332001f49Smrg fflush(stdout); 62432001f49Smrg 62532001f49Smrg t0 = t; 62632001f49Smrg frames = 0; 62732001f49Smrg frame_usage = 0.0; 62832001f49Smrg } 62932001f49Smrg } 63032001f49Smrg } 63132001f49Smrg} 63232001f49Smrg 63332001f49Smrg 63432001f49Smrg/** 63532001f49Smrg * Display the refresh rate of the display using the GLX_OML_sync_control 63632001f49Smrg * extension. 63732001f49Smrg */ 63832001f49Smrgstatic void 63932001f49Smrgshow_refresh_rate( Display * dpy ) 64032001f49Smrg{ 64132001f49Smrg#if defined(GLX_OML_sync_control) && defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) 64232001f49Smrg PFNGLXGETMSCRATEOMLPROC get_msc_rate; 64332001f49Smrg int32_t n; 64432001f49Smrg int32_t d; 64532001f49Smrg 64632001f49Smrg get_msc_rate = (PFNGLXGETMSCRATEOMLPROC) glXGetProcAddressARB( (const GLubyte *) "glXGetMscRateOML" ); 64732001f49Smrg if ( get_msc_rate != NULL ) { 64832001f49Smrg (*get_msc_rate)( dpy, glXGetCurrentDrawable(), &n, &d ); 64932001f49Smrg printf( "refresh rate: %.1fHz\n", (float) n / d ); 65032001f49Smrg return; 65132001f49Smrg } 65232001f49Smrg#endif 65332001f49Smrg printf( "glXGetMscRateOML not supported.\n" ); 65432001f49Smrg} 65532001f49Smrg 65632001f49Smrg 65732001f49Smrg/** 65832001f49Smrg * Fill in the table of extension strings from a supplied extensions string 65932001f49Smrg * (as returned by glXQueryExtensionsString). 66032001f49Smrg * 66132001f49Smrg * \param string String of GLX extensions. 66232001f49Smrg * \sa is_extension_supported 66332001f49Smrg */ 66432001f49Smrgstatic void 66532001f49Smrgmake_extension_table( const char * string ) 66632001f49Smrg{ 66732001f49Smrg char ** string_tab; 66832001f49Smrg unsigned num_strings; 66932001f49Smrg unsigned base; 67032001f49Smrg unsigned idx; 67132001f49Smrg unsigned i; 67232001f49Smrg 67332001f49Smrg /* Count the number of spaces in the string. That gives a base-line 67432001f49Smrg * figure for the number of extension in the string. 67532001f49Smrg */ 67632001f49Smrg 67732001f49Smrg num_strings = 1; 67832001f49Smrg for ( i = 0 ; string[i] != NUL ; i++ ) { 67932001f49Smrg if ( string[i] == ' ' ) { 68032001f49Smrg num_strings++; 68132001f49Smrg } 68232001f49Smrg } 68332001f49Smrg 68432001f49Smrg string_tab = (char **) malloc( sizeof( char * ) * num_strings ); 68532001f49Smrg if ( string_tab == NULL ) { 68632001f49Smrg return; 68732001f49Smrg } 68832001f49Smrg 68932001f49Smrg base = 0; 69032001f49Smrg idx = 0; 69132001f49Smrg 69232001f49Smrg while ( string[ base ] != NUL ) { 69332001f49Smrg /* Determine the length of the next extension string. 69432001f49Smrg */ 69532001f49Smrg 69632001f49Smrg for ( i = 0 69732001f49Smrg ; (string[ base + i ] != NUL) && (string[ base + i ] != ' ') 69832001f49Smrg ; i++ ) { 69932001f49Smrg /* empty */ ; 70032001f49Smrg } 70132001f49Smrg 70232001f49Smrg if ( i > 0 ) { 70332001f49Smrg /* If the string was non-zero length, add it to the table. We 70432001f49Smrg * can get zero length strings if there is a space at the end of 70532001f49Smrg * the string or if there are two (or more) spaces next to each 70632001f49Smrg * other in the string. 70732001f49Smrg */ 70832001f49Smrg 70932001f49Smrg string_tab[ idx ] = malloc( sizeof( char ) * (i + 1) ); 71032001f49Smrg if ( string_tab[ idx ] == NULL ) { 71132001f49Smrg unsigned j = 0; 71232001f49Smrg 71332001f49Smrg for ( j = 0; j < idx; j++ ) { 71432001f49Smrg free( string_tab[j] ); 71532001f49Smrg } 71632001f49Smrg 71732001f49Smrg free( string_tab ); 71832001f49Smrg 71932001f49Smrg return; 72032001f49Smrg } 72132001f49Smrg 72232001f49Smrg (void) memcpy( string_tab[ idx ], & string[ base ], i ); 72332001f49Smrg string_tab[ idx ][i] = NUL; 72432001f49Smrg idx++; 72532001f49Smrg } 72632001f49Smrg 72732001f49Smrg 72832001f49Smrg /* Skip to the start of the next extension string. 72932001f49Smrg */ 73032001f49Smrg 73132001f49Smrg for ( base += i 73232001f49Smrg ; (string[ base ] == ' ') && (string[ base ] != NUL) 73332001f49Smrg ; base++ ) { 73432001f49Smrg /* empty */ ; 73532001f49Smrg } 73632001f49Smrg } 73732001f49Smrg 73832001f49Smrg extension_table = string_tab; 73932001f49Smrg num_extensions = idx; 74032001f49Smrg} 74132001f49Smrg 74232001f49Smrg 74332001f49Smrg/** 74432001f49Smrg * Determine of an extension is supported. The extension string table 74532001f49Smrg * must have already be initialized by calling \c make_extension_table. 74632001f49Smrg * 74732001f49Smrg * \praram ext Extension to be tested. 74832001f49Smrg * \return GL_TRUE of the extension is supported, GL_FALSE otherwise. 74932001f49Smrg * \sa make_extension_table 75032001f49Smrg */ 75132001f49Smrgstatic GLboolean 75232001f49Smrgis_extension_supported( const char * ext ) 75332001f49Smrg{ 75432001f49Smrg unsigned i; 75532001f49Smrg 75632001f49Smrg for ( i = 0 ; i < num_extensions ; i++ ) { 75732001f49Smrg if ( strcmp( ext, extension_table[i] ) == 0 ) { 75832001f49Smrg return GL_TRUE; 75932001f49Smrg } 76032001f49Smrg } 76132001f49Smrg 76232001f49Smrg return GL_FALSE; 76332001f49Smrg} 76432001f49Smrg 76532001f49Smrg 76632001f49Smrgint 76732001f49Smrgmain(int argc, char *argv[]) 76832001f49Smrg{ 76932001f49Smrg Display *dpy; 77032001f49Smrg Window win; 77132001f49Smrg GLXContext ctx; 77232001f49Smrg char *dpyName = NULL; 77332001f49Smrg int swap_interval = 1; 77432001f49Smrg GLboolean do_swap_interval = GL_FALSE; 77532001f49Smrg GLboolean force_get_rate = GL_FALSE; 77632001f49Smrg GLboolean fullscreen = GL_FALSE; 77732001f49Smrg GLboolean printInfo = GL_FALSE; 77832001f49Smrg int i; 77932001f49Smrg PFNGLXSWAPINTERVALMESAPROC set_swap_interval = NULL; 78032001f49Smrg PFNGLXGETSWAPINTERVALMESAPROC get_swap_interval = NULL; 78132001f49Smrg int width = 300, height = 300; 78232001f49Smrg 78332001f49Smrg for (i = 1; i < argc; i++) { 78432001f49Smrg if (strcmp(argv[i], "-display") == 0 && i + 1 < argc) { 78532001f49Smrg dpyName = argv[i+1]; 78632001f49Smrg i++; 78732001f49Smrg } 78832001f49Smrg else if (strcmp(argv[i], "-info") == 0) { 78932001f49Smrg printInfo = GL_TRUE; 79032001f49Smrg } 79132001f49Smrg else if (strcmp(argv[i], "-swap") == 0 && i + 1 < argc) { 79232001f49Smrg swap_interval = atoi( argv[i+1] ); 79332001f49Smrg do_swap_interval = GL_TRUE; 79432001f49Smrg i++; 79532001f49Smrg } 79632001f49Smrg else if (strcmp(argv[i], "-forcegetrate") == 0) { 79732001f49Smrg /* This option was put in because some DRI drivers don't support the 79832001f49Smrg * full GLX_OML_sync_control extension, but they do support 79932001f49Smrg * glXGetMscRateOML. 80032001f49Smrg */ 80132001f49Smrg force_get_rate = GL_TRUE; 80232001f49Smrg } 80332001f49Smrg else if (strcmp(argv[i], "-fullscreen") == 0) { 80432001f49Smrg fullscreen = GL_TRUE; 80532001f49Smrg } 80632001f49Smrg else if (strcmp(argv[i], "-ztrick") == 0) { 80732001f49Smrg use_ztrick = GL_TRUE; 80832001f49Smrg } 80932001f49Smrg else if (strcmp(argv[i], "-help") == 0) { 81032001f49Smrg printf("Usage:\n"); 81132001f49Smrg printf(" gears [options]\n"); 81232001f49Smrg printf("Options:\n"); 81332001f49Smrg printf(" -help Print this information\n"); 81432001f49Smrg printf(" -display displayName Specify X display\n"); 81532001f49Smrg printf(" -info Display GL information\n"); 81632001f49Smrg printf(" -swap N Swap no more than once per N vertical refreshes\n"); 81732001f49Smrg printf(" -forcegetrate Try to use glXGetMscRateOML function\n"); 81832001f49Smrg printf(" -fullscreen Full-screen window\n"); 81932001f49Smrg return 0; 82032001f49Smrg } 82132001f49Smrg } 82232001f49Smrg 82332001f49Smrg dpy = XOpenDisplay(dpyName); 82432001f49Smrg if (!dpy) { 82532001f49Smrg printf("Error: couldn't open display %s\n", XDisplayName(dpyName)); 82632001f49Smrg return -1; 82732001f49Smrg } 82832001f49Smrg 82932001f49Smrg make_window(dpy, "glxgears", 0, 0, width, height, fullscreen, &win, &ctx); 83032001f49Smrg XMapWindow(dpy, win); 83132001f49Smrg glXMakeCurrent(dpy, win, ctx); 83232001f49Smrg 83332001f49Smrg make_extension_table( (char *) glXQueryExtensionsString(dpy,DefaultScreen(dpy)) ); 83432001f49Smrg has_OML_sync_control = is_extension_supported( "GLX_OML_sync_control" ); 83532001f49Smrg has_SGI_swap_control = is_extension_supported( "GLX_SGI_swap_control" ); 83632001f49Smrg has_MESA_swap_control = is_extension_supported( "GLX_MESA_swap_control" ); 83732001f49Smrg has_MESA_swap_frame_usage = is_extension_supported( "GLX_MESA_swap_frame_usage" ); 83832001f49Smrg 83932001f49Smrg if ( has_MESA_swap_control ) { 84032001f49Smrg set_swap_interval = (PFNGLXSWAPINTERVALMESAPROC) glXGetProcAddressARB( (const GLubyte *) "glXSwapIntervalMESA" ); 84132001f49Smrg get_swap_interval = (PFNGLXGETSWAPINTERVALMESAPROC) glXGetProcAddressARB( (const GLubyte *) "glXGetSwapIntervalMESA" ); 84232001f49Smrg } 84332001f49Smrg else if ( has_SGI_swap_control ) { 84432001f49Smrg set_swap_interval = (PFNGLXSWAPINTERVALMESAPROC) glXGetProcAddressARB( (const GLubyte *) "glXSwapIntervalSGI" ); 84532001f49Smrg } 84632001f49Smrg 84732001f49Smrg 84832001f49Smrg if ( has_MESA_swap_frame_usage ) { 84932001f49Smrg get_frame_usage = (PFNGLXGETFRAMEUSAGEMESAPROC) glXGetProcAddressARB( (const GLubyte *) "glXGetFrameUsageMESA" ); 85032001f49Smrg } 85132001f49Smrg 85232001f49Smrg 85332001f49Smrg if (printInfo) { 85432001f49Smrg printf("GL_RENDERER = %s\n", (char *) glGetString(GL_RENDERER)); 85532001f49Smrg printf("GL_VERSION = %s\n", (char *) glGetString(GL_VERSION)); 85632001f49Smrg printf("GL_VENDOR = %s\n", (char *) glGetString(GL_VENDOR)); 85732001f49Smrg printf("GL_EXTENSIONS = %s\n", (char *) glGetString(GL_EXTENSIONS)); 85832001f49Smrg if ( has_OML_sync_control || force_get_rate ) { 85932001f49Smrg show_refresh_rate( dpy ); 86032001f49Smrg } 86132001f49Smrg 86232001f49Smrg if ( get_swap_interval != NULL ) { 86332001f49Smrg printf("Default swap interval = %d\n", (*get_swap_interval)() ); 86432001f49Smrg } 86532001f49Smrg } 86632001f49Smrg 86732001f49Smrg if ( do_swap_interval ) { 86832001f49Smrg if ( set_swap_interval != NULL ) { 86932001f49Smrg if ( ((swap_interval == 0) && !has_MESA_swap_control) 87032001f49Smrg || (swap_interval < 0) ) { 87132001f49Smrg printf( "Swap interval must be non-negative or greater than zero " 87232001f49Smrg "if GLX_MESA_swap_control is not supported.\n" ); 87332001f49Smrg } 87432001f49Smrg else { 87532001f49Smrg (*set_swap_interval)( swap_interval ); 87632001f49Smrg } 87732001f49Smrg 87832001f49Smrg if ( printInfo && (get_swap_interval != NULL) ) { 87932001f49Smrg printf("Current swap interval = %d\n", (*get_swap_interval)() ); 88032001f49Smrg } 88132001f49Smrg } 88232001f49Smrg else { 88332001f49Smrg printf("Unable to set swap-interval. Neither GLX_SGI_swap_control " 88432001f49Smrg "nor GLX_MESA_swap_control are supported.\n" ); 88532001f49Smrg } 88632001f49Smrg } 88732001f49Smrg 88832001f49Smrg init(); 88932001f49Smrg 89032001f49Smrg /* Set initial projection/viewing transformation. 89132001f49Smrg * same as glxgears.c 89232001f49Smrg */ 89332001f49Smrg reshape(width, height); 89432001f49Smrg 89532001f49Smrg event_loop(dpy, win); 89632001f49Smrg 89732001f49Smrg glXDestroyContext(dpy, ctx); 89832001f49Smrg XDestroyWindow(dpy, win); 89932001f49Smrg XCloseDisplay(dpy); 90032001f49Smrg 90132001f49Smrg return 0; 90232001f49Smrg} 903