glxgears.c 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810
  1. /*
  2. * Copyright (C) 1999-2001 Brian Paul All Rights Reserved.
  3. *
  4. * Permission is hereby granted, free of charge, to any person obtaining a
  5. * copy of this software and associated documentation files (the "Software"),
  6. * to deal in the Software without restriction, including without limitation
  7. * the rights to use, copy, modify, merge, publish, distribute, sublicense,
  8. * and/or sell copies of the Software, and to permit persons to whom the
  9. * Software is furnished to do so, subject to the following conditions:
  10. *
  11. * The above copyright notice and this permission notice shall be included
  12. * in all copies or substantial portions of the Software.
  13. *
  14. * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
  15. * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  16. * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
  17. * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
  18. * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
  19. * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
  20. */
  21. /*
  22. * This is a port of the infamous "gears" demo to straight GLX (i.e. no GLUT)
  23. * Port by Brian Paul 23 March 2001
  24. *
  25. * See usage() below for command line options.
  26. */
  27. #include <math.h>
  28. #include <stdlib.h>
  29. #include <stdio.h>
  30. #include <string.h>
  31. #include <X11/Xlib.h>
  32. #include <X11/keysym.h>
  33. #include <GL/gl.h>
  34. #include <GL/glx.h>
  35. #include <GL/glxext.h>
  36. #ifndef GLX_MESA_swap_control
  37. #define GLX_MESA_swap_control 1
  38. typedef int (*PFNGLXGETSWAPINTERVALMESAPROC)(void);
  39. #endif
  40. #define BENCHMARK
  41. #ifdef BENCHMARK
  42. /* XXX this probably isn't very portable */
  43. #include <sys/time.h>
  44. #include <unistd.h>
  45. /* return current time (in seconds) */
  46. static double
  47. current_time(void)
  48. {
  49. struct timeval tv;
  50. #ifdef __VMS
  51. (void) gettimeofday(&tv, NULL );
  52. #else
  53. struct timezone tz;
  54. (void) gettimeofday(&tv, &tz);
  55. #endif
  56. return (double) tv.tv_sec + tv.tv_usec / 1000000.0;
  57. }
  58. #else /*BENCHMARK*/
  59. /* dummy */
  60. static double
  61. current_time(void)
  62. {
  63. /* update this function for other platforms! */
  64. static double t = 0.0;
  65. static int warn = 1;
  66. if (warn) {
  67. fprintf(stderr, "Warning: current_time() not implemented!!\n");
  68. warn = 0;
  69. }
  70. return t += 1.0;
  71. }
  72. #endif /*BENCHMARK*/
  73. #ifndef M_PI
  74. #define M_PI 3.14159265
  75. #endif
  76. /** Event handler results: */
  77. #define NOP 0
  78. #define EXIT 1
  79. #define DRAW 2
  80. static GLfloat view_rotx = 20.0, view_roty = 30.0, view_rotz = 0.0;
  81. static GLint gear1, gear2, gear3;
  82. static GLfloat angle = 0.0;
  83. static GLboolean fullscreen = GL_FALSE; /* Create a single fullscreen window */
  84. static GLboolean stereo = GL_FALSE; /* Enable stereo. */
  85. static GLint samples = 0; /* Choose visual with at least N samples. */
  86. static GLboolean animate = GL_TRUE; /* Animation */
  87. static GLfloat eyesep = 5.0; /* Eye separation. */
  88. static GLfloat fix_point = 40.0; /* Fixation point distance. */
  89. static GLfloat left, right, asp; /* Stereo frustum params. */
  90. /*
  91. *
  92. * Draw a gear wheel. You'll probably want to call this function when
  93. * building a display list since we do a lot of trig here.
  94. *
  95. * Input: inner_radius - radius of hole at center
  96. * outer_radius - radius at center of teeth
  97. * width - width of gear
  98. * teeth - number of teeth
  99. * tooth_depth - depth of tooth
  100. */
  101. static void
  102. gear(GLfloat inner_radius, GLfloat outer_radius, GLfloat width,
  103. GLint teeth, GLfloat tooth_depth)
  104. {
  105. GLint i;
  106. GLfloat r0, r1, r2;
  107. GLfloat angle, da;
  108. GLfloat u, v, len;
  109. r0 = inner_radius;
  110. r1 = outer_radius - tooth_depth / 2.0;
  111. r2 = outer_radius + tooth_depth / 2.0;
  112. da = 2.0 * M_PI / teeth / 4.0;
  113. glShadeModel(GL_FLAT);
  114. glNormal3f(0.0, 0.0, 1.0);
  115. /* draw front face */
  116. glBegin(GL_QUAD_STRIP);
  117. for (i = 0; i <= teeth; i++) {
  118. angle = i * 2.0 * M_PI / teeth;
  119. glVertex3f(r0 * cos(angle), r0 * sin(angle), width * 0.5);
  120. glVertex3f(r1 * cos(angle), r1 * sin(angle), width * 0.5);
  121. if (i < teeth) {
  122. glVertex3f(r0 * cos(angle), r0 * sin(angle), width * 0.5);
  123. glVertex3f(r1 * cos(angle + 3 * da), r1 * sin(angle + 3 * da),
  124. width * 0.5);
  125. }
  126. }
  127. glEnd();
  128. /* draw front sides of teeth */
  129. glBegin(GL_QUADS);
  130. da = 2.0 * M_PI / teeth / 4.0;
  131. for (i = 0; i < teeth; i++) {
  132. angle = i * 2.0 * M_PI / teeth;
  133. glVertex3f(r1 * cos(angle), r1 * sin(angle), width * 0.5);
  134. glVertex3f(r2 * cos(angle + da), r2 * sin(angle + da), width * 0.5);
  135. glVertex3f(r2 * cos(angle + 2 * da), r2 * sin(angle + 2 * da),
  136. width * 0.5);
  137. glVertex3f(r1 * cos(angle + 3 * da), r1 * sin(angle + 3 * da),
  138. width * 0.5);
  139. }
  140. glEnd();
  141. glNormal3f(0.0, 0.0, -1.0);
  142. /* draw back face */
  143. glBegin(GL_QUAD_STRIP);
  144. for (i = 0; i <= teeth; i++) {
  145. angle = i * 2.0 * M_PI / teeth;
  146. glVertex3f(r1 * cos(angle), r1 * sin(angle), -width * 0.5);
  147. glVertex3f(r0 * cos(angle), r0 * sin(angle), -width * 0.5);
  148. if (i < teeth) {
  149. glVertex3f(r1 * cos(angle + 3 * da), r1 * sin(angle + 3 * da),
  150. -width * 0.5);
  151. glVertex3f(r0 * cos(angle), r0 * sin(angle), -width * 0.5);
  152. }
  153. }
  154. glEnd();
  155. /* draw back sides of teeth */
  156. glBegin(GL_QUADS);
  157. da = 2.0 * M_PI / teeth / 4.0;
  158. for (i = 0; i < teeth; i++) {
  159. angle = i * 2.0 * M_PI / teeth;
  160. glVertex3f(r1 * cos(angle + 3 * da), r1 * sin(angle + 3 * da),
  161. -width * 0.5);
  162. glVertex3f(r2 * cos(angle + 2 * da), r2 * sin(angle + 2 * da),
  163. -width * 0.5);
  164. glVertex3f(r2 * cos(angle + da), r2 * sin(angle + da), -width * 0.5);
  165. glVertex3f(r1 * cos(angle), r1 * sin(angle), -width * 0.5);
  166. }
  167. glEnd();
  168. /* draw outward faces of teeth */
  169. glBegin(GL_QUAD_STRIP);
  170. for (i = 0; i < teeth; i++) {
  171. angle = i * 2.0 * M_PI / teeth;
  172. glVertex3f(r1 * cos(angle), r1 * sin(angle), width * 0.5);
  173. glVertex3f(r1 * cos(angle), r1 * sin(angle), -width * 0.5);
  174. u = r2 * cos(angle + da) - r1 * cos(angle);
  175. v = r2 * sin(angle + da) - r1 * sin(angle);
  176. len = sqrt(u * u + v * v);
  177. u /= len;
  178. v /= len;
  179. glNormal3f(v, -u, 0.0);
  180. glVertex3f(r2 * cos(angle + da), r2 * sin(angle + da), width * 0.5);
  181. glVertex3f(r2 * cos(angle + da), r2 * sin(angle + da), -width * 0.5);
  182. glNormal3f(cos(angle), sin(angle), 0.0);
  183. glVertex3f(r2 * cos(angle + 2 * da), r2 * sin(angle + 2 * da),
  184. width * 0.5);
  185. glVertex3f(r2 * cos(angle + 2 * da), r2 * sin(angle + 2 * da),
  186. -width * 0.5);
  187. u = r1 * cos(angle + 3 * da) - r2 * cos(angle + 2 * da);
  188. v = r1 * sin(angle + 3 * da) - r2 * sin(angle + 2 * da);
  189. glNormal3f(v, -u, 0.0);
  190. glVertex3f(r1 * cos(angle + 3 * da), r1 * sin(angle + 3 * da),
  191. width * 0.5);
  192. glVertex3f(r1 * cos(angle + 3 * da), r1 * sin(angle + 3 * da),
  193. -width * 0.5);
  194. glNormal3f(cos(angle), sin(angle), 0.0);
  195. }
  196. glVertex3f(r1 * cos(0), r1 * sin(0), width * 0.5);
  197. glVertex3f(r1 * cos(0), r1 * sin(0), -width * 0.5);
  198. glEnd();
  199. glShadeModel(GL_SMOOTH);
  200. /* draw inside radius cylinder */
  201. glBegin(GL_QUAD_STRIP);
  202. for (i = 0; i <= teeth; i++) {
  203. angle = i * 2.0 * M_PI / teeth;
  204. glNormal3f(-cos(angle), -sin(angle), 0.0);
  205. glVertex3f(r0 * cos(angle), r0 * sin(angle), -width * 0.5);
  206. glVertex3f(r0 * cos(angle), r0 * sin(angle), width * 0.5);
  207. }
  208. glEnd();
  209. }
  210. static void
  211. draw(void)
  212. {
  213. glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
  214. glPushMatrix();
  215. glRotatef(view_rotx, 1.0, 0.0, 0.0);
  216. glRotatef(view_roty, 0.0, 1.0, 0.0);
  217. glRotatef(view_rotz, 0.0, 0.0, 1.0);
  218. glPushMatrix();
  219. glTranslatef(-3.0, -2.0, 0.0);
  220. glRotatef(angle, 0.0, 0.0, 1.0);
  221. glCallList(gear1);
  222. glPopMatrix();
  223. glPushMatrix();
  224. glTranslatef(3.1, -2.0, 0.0);
  225. glRotatef(-2.0 * angle - 9.0, 0.0, 0.0, 1.0);
  226. glCallList(gear2);
  227. glPopMatrix();
  228. glPushMatrix();
  229. glTranslatef(-3.1, 4.2, 0.0);
  230. glRotatef(-2.0 * angle - 25.0, 0.0, 0.0, 1.0);
  231. glCallList(gear3);
  232. glPopMatrix();
  233. glPopMatrix();
  234. }
  235. static void
  236. draw_gears(void)
  237. {
  238. if (stereo) {
  239. /* First left eye. */
  240. glDrawBuffer(GL_BACK_LEFT);
  241. glMatrixMode(GL_PROJECTION);
  242. glLoadIdentity();
  243. glFrustum(left, right, -asp, asp, 5.0, 60.0);
  244. glMatrixMode(GL_MODELVIEW);
  245. glPushMatrix();
  246. glTranslated(+0.5 * eyesep, 0.0, 0.0);
  247. draw();
  248. glPopMatrix();
  249. /* Then right eye. */
  250. glDrawBuffer(GL_BACK_RIGHT);
  251. glMatrixMode(GL_PROJECTION);
  252. glLoadIdentity();
  253. glFrustum(-right, -left, -asp, asp, 5.0, 60.0);
  254. glMatrixMode(GL_MODELVIEW);
  255. glPushMatrix();
  256. glTranslated(-0.5 * eyesep, 0.0, 0.0);
  257. draw();
  258. glPopMatrix();
  259. }
  260. else {
  261. draw();
  262. }
  263. }
  264. /** Draw single frame, do SwapBuffers, compute FPS */
  265. static void
  266. draw_frame(Display *dpy, Window win)
  267. {
  268. static int frames = 0;
  269. static double tRot0 = -1.0, tRate0 = -1.0;
  270. double dt, t = current_time();
  271. if (tRot0 < 0.0)
  272. tRot0 = t;
  273. dt = t - tRot0;
  274. tRot0 = t;
  275. if (animate) {
  276. /* advance rotation for next frame */
  277. angle += 70.0 * dt; /* 70 degrees per second */
  278. if (angle > 3600.0)
  279. angle -= 3600.0;
  280. }
  281. draw_gears();
  282. glXSwapBuffers(dpy, win);
  283. frames++;
  284. if (tRate0 < 0.0)
  285. tRate0 = t;
  286. if (t - tRate0 >= 5.0) {
  287. GLfloat seconds = t - tRate0;
  288. GLfloat fps = frames / seconds;
  289. printf("%d frames in %3.1f seconds = %6.3f FPS\n", frames, seconds,
  290. fps);
  291. fflush(stdout);
  292. tRate0 = t;
  293. frames = 0;
  294. }
  295. }
  296. /* new window size or exposure */
  297. static void
  298. reshape(int width, int height)
  299. {
  300. glViewport(0, 0, (GLint) width, (GLint) height);
  301. if (stereo) {
  302. GLfloat w;
  303. asp = (GLfloat) height / (GLfloat) width;
  304. w = fix_point * (1.0 / 5.0);
  305. left = -5.0 * ((w - 0.5 * eyesep) / fix_point);
  306. right = 5.0 * ((w + 0.5 * eyesep) / fix_point);
  307. }
  308. else {
  309. GLfloat h = (GLfloat) height / (GLfloat) width;
  310. glMatrixMode(GL_PROJECTION);
  311. glLoadIdentity();
  312. glFrustum(-1.0, 1.0, -h, h, 5.0, 60.0);
  313. }
  314. glMatrixMode(GL_MODELVIEW);
  315. glLoadIdentity();
  316. glTranslatef(0.0, 0.0, -40.0);
  317. }
  318. static void
  319. init(void)
  320. {
  321. static GLfloat pos[4] = { 5.0, 5.0, 10.0, 0.0 };
  322. static GLfloat red[4] = { 0.8, 0.1, 0.0, 1.0 };
  323. static GLfloat green[4] = { 0.0, 0.8, 0.2, 1.0 };
  324. static GLfloat blue[4] = { 0.2, 0.2, 1.0, 1.0 };
  325. glLightfv(GL_LIGHT0, GL_POSITION, pos);
  326. glEnable(GL_CULL_FACE);
  327. glEnable(GL_LIGHTING);
  328. glEnable(GL_LIGHT0);
  329. glEnable(GL_DEPTH_TEST);
  330. /* make the gears */
  331. gear1 = glGenLists(1);
  332. glNewList(gear1, GL_COMPILE);
  333. glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, red);
  334. gear(1.0, 4.0, 1.0, 20, 0.7);
  335. glEndList();
  336. gear2 = glGenLists(1);
  337. glNewList(gear2, GL_COMPILE);
  338. glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, green);
  339. gear(0.5, 2.0, 2.0, 10, 0.7);
  340. glEndList();
  341. gear3 = glGenLists(1);
  342. glNewList(gear3, GL_COMPILE);
  343. glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, blue);
  344. gear(1.3, 2.0, 0.5, 10, 0.7);
  345. glEndList();
  346. glEnable(GL_NORMALIZE);
  347. }
  348. /**
  349. * Remove window border/decorations.
  350. */
  351. static void
  352. no_border( Display *dpy, Window w)
  353. {
  354. static const unsigned MWM_HINTS_DECORATIONS = (1 << 1);
  355. static const int PROP_MOTIF_WM_HINTS_ELEMENTS = 5;
  356. typedef struct
  357. {
  358. unsigned long flags;
  359. unsigned long functions;
  360. unsigned long decorations;
  361. long inputMode;
  362. unsigned long status;
  363. } PropMotifWmHints;
  364. PropMotifWmHints motif_hints;
  365. Atom prop, proptype;
  366. unsigned long flags = 0;
  367. /* setup the property */
  368. motif_hints.flags = MWM_HINTS_DECORATIONS;
  369. motif_hints.decorations = flags;
  370. /* get the atom for the property */
  371. prop = XInternAtom( dpy, "_MOTIF_WM_HINTS", True );
  372. if (!prop) {
  373. /* something went wrong! */
  374. return;
  375. }
  376. /* not sure this is correct, seems to work, XA_WM_HINTS didn't work */
  377. proptype = prop;
  378. XChangeProperty( dpy, w, /* display, window */
  379. prop, proptype, /* property, type */
  380. 32, /* format: 32-bit datums */
  381. PropModeReplace, /* mode */
  382. (unsigned char *) &motif_hints, /* data */
  383. PROP_MOTIF_WM_HINTS_ELEMENTS /* nelements */
  384. );
  385. }
  386. /*
  387. * Create an RGB, double-buffered window.
  388. * Return the window and context handles.
  389. */
  390. static void
  391. make_window( Display *dpy, const char *name,
  392. int x, int y, int width, int height,
  393. Window *winRet, GLXContext *ctxRet, VisualID *visRet)
  394. {
  395. int attribs[64];
  396. int i = 0;
  397. int scrnum;
  398. XSetWindowAttributes attr;
  399. unsigned long mask;
  400. Window root;
  401. Window win;
  402. GLXContext ctx;
  403. XVisualInfo *visinfo;
  404. /* Singleton attributes. */
  405. attribs[i++] = GLX_RGBA;
  406. attribs[i++] = GLX_DOUBLEBUFFER;
  407. if (stereo)
  408. attribs[i++] = GLX_STEREO;
  409. /* Key/value attributes. */
  410. attribs[i++] = GLX_RED_SIZE;
  411. attribs[i++] = 1;
  412. attribs[i++] = GLX_GREEN_SIZE;
  413. attribs[i++] = 1;
  414. attribs[i++] = GLX_BLUE_SIZE;
  415. attribs[i++] = 1;
  416. attribs[i++] = GLX_DEPTH_SIZE;
  417. attribs[i++] = 1;
  418. if (samples > 0) {
  419. attribs[i++] = GLX_SAMPLE_BUFFERS;
  420. attribs[i++] = 1;
  421. attribs[i++] = GLX_SAMPLES;
  422. attribs[i++] = samples;
  423. }
  424. attribs[i++] = None;
  425. scrnum = DefaultScreen( dpy );
  426. root = RootWindow( dpy, scrnum );
  427. visinfo = glXChooseVisual(dpy, scrnum, attribs);
  428. if (!visinfo) {
  429. printf("Error: couldn't get an RGB, Double-buffered");
  430. if (stereo)
  431. printf(", Stereo");
  432. if (samples > 0)
  433. printf(", Multisample");
  434. printf(" visual\n");
  435. exit(1);
  436. }
  437. /* window attributes */
  438. attr.background_pixel = 0;
  439. attr.border_pixel = 0;
  440. attr.colormap = XCreateColormap( dpy, root, visinfo->visual, AllocNone);
  441. attr.event_mask = StructureNotifyMask | ExposureMask | KeyPressMask;
  442. /* XXX this is a bad way to get a borderless window! */
  443. mask = CWBackPixel | CWBorderPixel | CWColormap | CWEventMask;
  444. win = XCreateWindow( dpy, root, x, y, width, height,
  445. 0, visinfo->depth, InputOutput,
  446. visinfo->visual, mask, &attr );
  447. if (fullscreen)
  448. no_border(dpy, win);
  449. /* set hints and properties */
  450. {
  451. XSizeHints sizehints;
  452. sizehints.x = x;
  453. sizehints.y = y;
  454. sizehints.width = width;
  455. sizehints.height = height;
  456. sizehints.flags = USSize | USPosition;
  457. XSetNormalHints(dpy, win, &sizehints);
  458. XSetStandardProperties(dpy, win, name, name,
  459. None, (char **)NULL, 0, &sizehints);
  460. }
  461. ctx = glXCreateContext( dpy, visinfo, NULL, True );
  462. if (!ctx) {
  463. printf("Error: glXCreateContext failed\n");
  464. exit(1);
  465. }
  466. *winRet = win;
  467. *ctxRet = ctx;
  468. *visRet = visinfo->visualid;
  469. XFree(visinfo);
  470. }
  471. /**
  472. * Determine whether or not a GLX extension is supported.
  473. */
  474. static int
  475. is_glx_extension_supported(Display *dpy, const char *query)
  476. {
  477. const int scrnum = DefaultScreen(dpy);
  478. const char *glx_extensions = NULL;
  479. const size_t len = strlen(query);
  480. const char *ptr;
  481. if (glx_extensions == NULL) {
  482. glx_extensions = glXQueryExtensionsString(dpy, scrnum);
  483. }
  484. ptr = strstr(glx_extensions, query);
  485. return ((ptr != NULL) && ((ptr[len] == ' ') || (ptr[len] == '\0')));
  486. }
  487. /**
  488. * Attempt to determine whether or not the display is synched to vblank.
  489. */
  490. static void
  491. query_vsync(Display *dpy, GLXDrawable drawable)
  492. {
  493. int interval = 0;
  494. #if defined(GLX_EXT_swap_control)
  495. if (is_glx_extension_supported(dpy, "GLX_EXT_swap_control")) {
  496. unsigned int tmp = -1;
  497. glXQueryDrawable(dpy, drawable, GLX_SWAP_INTERVAL_EXT, &tmp);
  498. interval = tmp;
  499. } else
  500. #endif
  501. if (is_glx_extension_supported(dpy, "GLX_MESA_swap_control")) {
  502. PFNGLXGETSWAPINTERVALMESAPROC pglXGetSwapIntervalMESA =
  503. (PFNGLXGETSWAPINTERVALMESAPROC)
  504. glXGetProcAddressARB((const GLubyte *) "glXGetSwapIntervalMESA");
  505. interval = (*pglXGetSwapIntervalMESA)();
  506. } else if (is_glx_extension_supported(dpy, "GLX_SGI_swap_control")) {
  507. /* The default swap interval with this extension is 1. Assume that it
  508. * is set to the default.
  509. *
  510. * Many Mesa-based drivers default to 0, but all of these drivers also
  511. * export GLX_MESA_swap_control. In that case, this branch will never
  512. * be taken, and the correct result should be reported.
  513. */
  514. interval = 1;
  515. }
  516. if (interval > 0) {
  517. printf("Running synchronized to the vertical refresh. The framerate should be\n");
  518. if (interval == 1) {
  519. printf("approximately the same as the monitor refresh rate.\n");
  520. } else if (interval > 1) {
  521. printf("approximately 1/%d the monitor refresh rate.\n",
  522. interval);
  523. }
  524. }
  525. }
  526. /**
  527. * Handle one X event.
  528. * \return NOP, EXIT or DRAW
  529. */
  530. static int
  531. handle_event(Display *dpy, Window win, XEvent *event)
  532. {
  533. (void) dpy;
  534. (void) win;
  535. switch (event->type) {
  536. case Expose:
  537. return DRAW;
  538. case ConfigureNotify:
  539. reshape(event->xconfigure.width, event->xconfigure.height);
  540. break;
  541. case KeyPress:
  542. {
  543. char buffer[10];
  544. int code;
  545. code = XLookupKeysym(&event->xkey, 0);
  546. if (code == XK_Left) {
  547. view_roty += 5.0;
  548. }
  549. else if (code == XK_Right) {
  550. view_roty -= 5.0;
  551. }
  552. else if (code == XK_Up) {
  553. view_rotx += 5.0;
  554. }
  555. else if (code == XK_Down) {
  556. view_rotx -= 5.0;
  557. }
  558. else {
  559. XLookupString(&event->xkey, buffer, sizeof(buffer),
  560. NULL, NULL);
  561. if (buffer[0] == 27) {
  562. /* escape */
  563. return EXIT;
  564. }
  565. else if (buffer[0] == 'a' || buffer[0] == 'A') {
  566. animate = !animate;
  567. }
  568. }
  569. return DRAW;
  570. }
  571. }
  572. return NOP;
  573. }
  574. static void
  575. event_loop(Display *dpy, Window win)
  576. {
  577. while (1) {
  578. int op;
  579. while (!animate || XPending(dpy) > 0) {
  580. XEvent event;
  581. XNextEvent(dpy, &event);
  582. op = handle_event(dpy, win, &event);
  583. if (op == EXIT)
  584. return;
  585. else if (op == DRAW)
  586. break;
  587. }
  588. draw_frame(dpy, win);
  589. }
  590. }
  591. static void
  592. usage(void)
  593. {
  594. printf("Usage:\n");
  595. printf(" -display <displayname> set the display to run on\n");
  596. printf(" -stereo run in stereo mode\n");
  597. printf(" -samples N run in multisample mode with at least N samples\n");
  598. printf(" -fullscreen run in fullscreen mode\n");
  599. printf(" -info display OpenGL renderer info\n");
  600. printf(" -geometry WxH+X+Y window geometry\n");
  601. }
  602. int
  603. main(int argc, char *argv[])
  604. {
  605. unsigned int winWidth = 300, winHeight = 300;
  606. int x = 0, y = 0;
  607. Display *dpy;
  608. Window win;
  609. GLXContext ctx;
  610. char *dpyName = NULL;
  611. GLboolean printInfo = GL_FALSE;
  612. VisualID visId;
  613. int i;
  614. for (i = 1; i < argc; i++) {
  615. if (strcmp(argv[i], "-display") == 0) {
  616. dpyName = argv[i+1];
  617. i++;
  618. }
  619. else if (strcmp(argv[i], "-info") == 0) {
  620. printInfo = GL_TRUE;
  621. }
  622. else if (strcmp(argv[i], "-stereo") == 0) {
  623. stereo = GL_TRUE;
  624. }
  625. else if (i < argc-1 && strcmp(argv[i], "-samples") == 0) {
  626. samples = strtod(argv[i+1], NULL );
  627. ++i;
  628. }
  629. else if (strcmp(argv[i], "-fullscreen") == 0) {
  630. fullscreen = GL_TRUE;
  631. }
  632. else if (i < argc-1 && strcmp(argv[i], "-geometry") == 0) {
  633. XParseGeometry(argv[i+1], &x, &y, &winWidth, &winHeight);
  634. i++;
  635. }
  636. else {
  637. usage();
  638. return -1;
  639. }
  640. }
  641. dpy = XOpenDisplay(dpyName);
  642. if (!dpy) {
  643. printf("Error: couldn't open display %s\n",
  644. dpyName ? dpyName : getenv("DISPLAY"));
  645. return -1;
  646. }
  647. if (fullscreen) {
  648. int scrnum = DefaultScreen(dpy);
  649. x = 0; y = 0;
  650. winWidth = DisplayWidth(dpy, scrnum);
  651. winHeight = DisplayHeight(dpy, scrnum);
  652. }
  653. make_window(dpy, "glxgears", x, y, winWidth, winHeight, &win, &ctx, &visId);
  654. XMapWindow(dpy, win);
  655. glXMakeCurrent(dpy, win, ctx);
  656. query_vsync(dpy, win);
  657. if (printInfo) {
  658. printf("GL_RENDERER = %s\n", (char *) glGetString(GL_RENDERER));
  659. printf("GL_VERSION = %s\n", (char *) glGetString(GL_VERSION));
  660. printf("GL_VENDOR = %s\n", (char *) glGetString(GL_VENDOR));
  661. printf("GL_EXTENSIONS = %s\n", (char *) glGetString(GL_EXTENSIONS));
  662. printf("VisualID %d, 0x%x\n", (int) visId, (int) visId);
  663. }
  664. init();
  665. /* Set initial projection/viewing transformation.
  666. * We can't be sure we'll get a ConfigureNotify event when the window
  667. * first appears.
  668. */
  669. reshape(winWidth, winHeight);
  670. event_loop(dpy, win);
  671. glDeleteLists(gear1, 1);
  672. glDeleteLists(gear2, 1);
  673. glDeleteLists(gear3, 1);
  674. glXMakeCurrent(dpy, None, NULL);
  675. glXDestroyContext(dpy, ctx);
  676. XDestroyWindow(dpy, win);
  677. XCloseDisplay(dpy);
  678. return 0;
  679. }