Clone of mesa.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656
  1. /*
  2. * Copyright (C) 2008 Tunsgten Graphics,Inc. All Rights Reserved.
  3. */
  4. /*
  5. * Draw a lit, textured torus with X/EGL and OpenGL ES 1.x
  6. * Brian Paul
  7. * July 2008
  8. */
  9. #include <assert.h>
  10. #include <math.h>
  11. #include <stdlib.h>
  12. #include <stdio.h>
  13. #include <string.h>
  14. #include <X11/Xlib.h>
  15. #include <X11/Xutil.h>
  16. #include <X11/keysym.h>
  17. #include <GLES/gl.h>
  18. #include <GLES/glext.h>
  19. #include <EGL/egl.h>
  20. static const struct {
  21. GLenum internalFormat;
  22. const char *name;
  23. GLuint num_entries;
  24. GLuint size;
  25. } cpal_formats[] = {
  26. { GL_PALETTE4_RGB8_OES, "GL_PALETTE4_RGB8_OES", 16, 3 },
  27. { GL_PALETTE4_RGBA8_OES, "GL_PALETTE4_RGBA8_OES", 16, 4 },
  28. { GL_PALETTE4_R5_G6_B5_OES, "GL_PALETTE4_R5_G6_B5_OES", 16, 2 },
  29. { GL_PALETTE4_RGBA4_OES, "GL_PALETTE4_RGBA4_OES", 16, 2 },
  30. { GL_PALETTE4_RGB5_A1_OES, "GL_PALETTE4_RGB5_A1_OES", 16, 2 },
  31. { GL_PALETTE8_RGB8_OES, "GL_PALETTE8_RGB8_OES", 256, 3 },
  32. { GL_PALETTE8_RGBA8_OES, "GL_PALETTE8_RGBA8_OES", 256, 4 },
  33. { GL_PALETTE8_R5_G6_B5_OES, "GL_PALETTE8_R5_G6_B5_OES", 256, 2 },
  34. { GL_PALETTE8_RGBA4_OES, "GL_PALETTE8_RGBA4_OES", 256, 2 },
  35. { GL_PALETTE8_RGB5_A1_OES, "GL_PALETTE8_RGB5_A1_OES", 256, 2 }
  36. };
  37. #define NUM_CPAL_FORMATS (sizeof(cpal_formats) / sizeof(cpal_formats[0]))
  38. static GLfloat view_rotx = 0.0, view_roty = 0.0, view_rotz = 0.0;
  39. static GLint tex_format = NUM_CPAL_FORMATS;
  40. static void
  41. Normal(GLfloat *n, GLfloat nx, GLfloat ny, GLfloat nz)
  42. {
  43. n[0] = nx;
  44. n[1] = ny;
  45. n[2] = nz;
  46. }
  47. static void
  48. Vertex(GLfloat *v, GLfloat vx, GLfloat vy, GLfloat vz)
  49. {
  50. v[0] = vx;
  51. v[1] = vy;
  52. v[2] = vz;
  53. }
  54. static void
  55. Texcoord(GLfloat *v, GLfloat s, GLfloat t)
  56. {
  57. v[0] = s;
  58. v[1] = t;
  59. }
  60. /* Borrowed from glut, adapted */
  61. static void
  62. draw_torus(GLfloat r, GLfloat R, GLint nsides, GLint rings)
  63. {
  64. int i, j;
  65. GLfloat theta, phi, theta1;
  66. GLfloat cosTheta, sinTheta;
  67. GLfloat cosTheta1, sinTheta1;
  68. GLfloat ringDelta, sideDelta;
  69. GLfloat varray[100][3], narray[100][3], tarray[100][2];
  70. int vcount;
  71. glVertexPointer(3, GL_FLOAT, 0, varray);
  72. glNormalPointer(GL_FLOAT, 0, narray);
  73. glTexCoordPointer(2, GL_FLOAT, 0, tarray);
  74. glEnableClientState(GL_VERTEX_ARRAY);
  75. glEnableClientState(GL_NORMAL_ARRAY);
  76. glEnableClientState(GL_TEXTURE_COORD_ARRAY);
  77. ringDelta = 2.0 * M_PI / rings;
  78. sideDelta = 2.0 * M_PI / nsides;
  79. theta = 0.0;
  80. cosTheta = 1.0;
  81. sinTheta = 0.0;
  82. for (i = rings - 1; i >= 0; i--) {
  83. theta1 = theta + ringDelta;
  84. cosTheta1 = cos(theta1);
  85. sinTheta1 = sin(theta1);
  86. vcount = 0; /* glBegin(GL_QUAD_STRIP); */
  87. phi = 0.0;
  88. for (j = nsides; j >= 0; j--) {
  89. GLfloat s0, s1, t;
  90. GLfloat cosPhi, sinPhi, dist;
  91. phi += sideDelta;
  92. cosPhi = cos(phi);
  93. sinPhi = sin(phi);
  94. dist = R + r * cosPhi;
  95. s0 = 20.0 * theta / (2.0 * M_PI);
  96. s1 = 20.0 * theta1 / (2.0 * M_PI);
  97. t = 8.0 * phi / (2.0 * M_PI);
  98. Normal(narray[vcount], cosTheta1 * cosPhi, -sinTheta1 * cosPhi, sinPhi);
  99. Texcoord(tarray[vcount], s1, t);
  100. Vertex(varray[vcount], cosTheta1 * dist, -sinTheta1 * dist, r * sinPhi);
  101. vcount++;
  102. Normal(narray[vcount], cosTheta * cosPhi, -sinTheta * cosPhi, sinPhi);
  103. Texcoord(tarray[vcount], s0, t);
  104. Vertex(varray[vcount], cosTheta * dist, -sinTheta * dist, r * sinPhi);
  105. vcount++;
  106. }
  107. /*glEnd();*/
  108. assert(vcount <= 100);
  109. glDrawArrays(GL_TRIANGLE_STRIP, 0, vcount);
  110. theta = theta1;
  111. cosTheta = cosTheta1;
  112. sinTheta = sinTheta1;
  113. }
  114. glDisableClientState(GL_VERTEX_ARRAY);
  115. glDisableClientState(GL_NORMAL_ARRAY);
  116. glDisableClientState(GL_TEXTURE_COORD_ARRAY);
  117. }
  118. static void
  119. draw(void)
  120. {
  121. glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
  122. glPushMatrix();
  123. glRotatef(view_rotx, 1, 0, 0);
  124. glRotatef(view_roty, 0, 1, 0);
  125. glRotatef(view_rotz, 0, 0, 1);
  126. glScalef(0.5, 0.5, 0.5);
  127. draw_torus(1.0, 3.0, 30, 60);
  128. glPopMatrix();
  129. }
  130. /* new window size or exposure */
  131. static void
  132. reshape(int width, int height)
  133. {
  134. GLfloat ar = (GLfloat) width / (GLfloat) height;
  135. glViewport(0, 0, (GLint) width, (GLint) height);
  136. glMatrixMode(GL_PROJECTION);
  137. glLoadIdentity();
  138. #ifdef GL_VERSION_ES_CM_1_0
  139. glFrustumf(-ar, ar, -1, 1, 5.0, 60.0);
  140. #else
  141. glFrustum(-ar, ar, -1, 1, 5.0, 60.0);
  142. #endif
  143. glMatrixMode(GL_MODELVIEW);
  144. glLoadIdentity();
  145. glTranslatef(0.0, 0.0, -15.0);
  146. }
  147. static GLint
  148. make_cpal_texture(GLint idx)
  149. {
  150. #define SZ 64
  151. GLenum internalFormat = GL_PALETTE4_RGB8_OES + idx;
  152. GLenum Filter = GL_LINEAR;
  153. GLubyte palette[256 * 4 + SZ * SZ];
  154. GLubyte *indices;
  155. GLsizei image_size;
  156. GLuint i, j;
  157. GLuint packed_indices = 0;
  158. assert(cpal_formats[idx].internalFormat == internalFormat);
  159. /* init palette */
  160. switch (internalFormat) {
  161. case GL_PALETTE4_RGB8_OES:
  162. case GL_PALETTE8_RGB8_OES:
  163. /* first entry */
  164. palette[0] = 255;
  165. palette[1] = 255;
  166. palette[2] = 255;
  167. /* second entry */
  168. palette[3] = 127;
  169. palette[4] = 127;
  170. palette[5] = 127;
  171. break;
  172. case GL_PALETTE4_RGBA8_OES:
  173. case GL_PALETTE8_RGBA8_OES:
  174. /* first entry */
  175. palette[0] = 255;
  176. palette[1] = 255;
  177. palette[2] = 255;
  178. palette[3] = 255;
  179. /* second entry */
  180. palette[4] = 127;
  181. palette[5] = 127;
  182. palette[6] = 127;
  183. palette[7] = 255;
  184. break;
  185. case GL_PALETTE4_R5_G6_B5_OES:
  186. case GL_PALETTE8_R5_G6_B5_OES:
  187. {
  188. GLushort *pal = (GLushort *) palette;
  189. /* first entry */
  190. pal[0] = (31 << 11 | 63 << 5 | 31);
  191. /* second entry */
  192. pal[1] = (15 << 11 | 31 << 5 | 15);
  193. }
  194. break;
  195. case GL_PALETTE4_RGBA4_OES:
  196. case GL_PALETTE8_RGBA4_OES:
  197. {
  198. GLushort *pal = (GLushort *) palette;
  199. /* first entry */
  200. pal[0] = (15 << 12 | 15 << 8 | 15 << 4 | 15);
  201. /* second entry */
  202. pal[1] = (7 << 12 | 7 << 8 | 7 << 4 | 15);
  203. }
  204. break;
  205. case GL_PALETTE4_RGB5_A1_OES:
  206. case GL_PALETTE8_RGB5_A1_OES:
  207. {
  208. GLushort *pal = (GLushort *) palette;
  209. /* first entry */
  210. pal[0] = (31 << 11 | 31 << 6 | 31 << 1 | 1);
  211. /* second entry */
  212. pal[1] = (15 << 11 | 15 << 6 | 15 << 1 | 1);
  213. }
  214. break;
  215. }
  216. image_size = cpal_formats[idx].size * cpal_formats[idx].num_entries;
  217. indices = palette + image_size;
  218. for (i = 0; i < SZ; i++) {
  219. for (j = 0; j < SZ; j++) {
  220. GLfloat d;
  221. GLint index;
  222. d = (i - SZ/2) * (i - SZ/2) + (j - SZ/2) * (j - SZ/2);
  223. d = sqrt(d);
  224. index = (d < SZ / 3) ? 0 : 1;
  225. if (cpal_formats[idx].num_entries == 16) {
  226. /* 4-bit indices packed in GLubyte */
  227. packed_indices |= index << (4 * (1 - (j % 2)));
  228. if (j % 2) {
  229. *(indices + (i * SZ + j - 1) / 2) = packed_indices & 0xff;
  230. packed_indices = 0;
  231. image_size += 1;
  232. }
  233. }
  234. else {
  235. /* 8-bit indices */
  236. *(indices + i * SZ + j) = index;
  237. image_size += 1;
  238. }
  239. }
  240. }
  241. glActiveTexture(GL_TEXTURE0); /* unit 0 */
  242. glBindTexture(GL_TEXTURE_2D, 42);
  243. glCompressedTexImage2D(GL_TEXTURE_2D, 0, internalFormat, SZ, SZ, 0,
  244. image_size, palette);
  245. glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, Filter);
  246. glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, Filter);
  247. glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
  248. glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
  249. #undef SZ
  250. return image_size;
  251. }
  252. static GLint
  253. make_texture(void)
  254. {
  255. #define SZ 64
  256. GLenum Filter = GL_LINEAR;
  257. GLubyte image[SZ][SZ][4];
  258. GLuint i, j;
  259. for (i = 0; i < SZ; i++) {
  260. for (j = 0; j < SZ; j++) {
  261. GLfloat d = (i - SZ/2) * (i - SZ/2) + (j - SZ/2) * (j - SZ/2);
  262. d = sqrt(d);
  263. if (d < SZ/3) {
  264. image[i][j][0] = 255;
  265. image[i][j][1] = 255;
  266. image[i][j][2] = 255;
  267. image[i][j][3] = 255;
  268. }
  269. else {
  270. image[i][j][0] = 127;
  271. image[i][j][1] = 127;
  272. image[i][j][2] = 127;
  273. image[i][j][3] = 255;
  274. }
  275. }
  276. }
  277. glActiveTexture(GL_TEXTURE0); /* unit 0 */
  278. glBindTexture(GL_TEXTURE_2D, 42);
  279. glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, SZ, SZ, 0,
  280. GL_RGBA, GL_UNSIGNED_BYTE, image);
  281. glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, Filter);
  282. glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, Filter);
  283. glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
  284. glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
  285. #undef SZ
  286. return sizeof(image);
  287. }
  288. static void
  289. init(void)
  290. {
  291. static const GLfloat red[4] = {1, 0, 0, 0};
  292. static const GLfloat white[4] = {1.0, 1.0, 1.0, 1.0};
  293. static const GLfloat diffuse[4] = {0.7, 0.7, 0.7, 1.0};
  294. static const GLfloat specular[4] = {0.001, 0.001, 0.001, 1.0};
  295. static const GLfloat pos[4] = {20, 20, 50, 1};
  296. glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, red);
  297. glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, white);
  298. glMaterialf(GL_FRONT_AND_BACK, GL_SHININESS, 9.0);
  299. glEnable(GL_LIGHTING);
  300. glEnable(GL_LIGHT0);
  301. glLightfv(GL_LIGHT0, GL_POSITION, pos);
  302. glLightfv(GL_LIGHT0, GL_DIFFUSE, diffuse);
  303. glLightfv(GL_LIGHT0, GL_SPECULAR, specular);
  304. glClearColor(0.4, 0.4, 0.4, 0.0);
  305. glEnable(GL_DEPTH_TEST);
  306. make_texture();
  307. glEnable(GL_TEXTURE_2D);
  308. }
  309. /*
  310. * Create an RGB, double-buffered X window.
  311. * Return the window and context handles.
  312. */
  313. static void
  314. make_x_window(Display *x_dpy, EGLDisplay egl_dpy,
  315. const char *name,
  316. int x, int y, int width, int height,
  317. Window *winRet,
  318. EGLContext *ctxRet,
  319. EGLSurface *surfRet)
  320. {
  321. static const EGLint attribs[] = {
  322. EGL_RED_SIZE, 1,
  323. EGL_GREEN_SIZE, 1,
  324. EGL_BLUE_SIZE, 1,
  325. EGL_DEPTH_SIZE, 1,
  326. EGL_NONE
  327. };
  328. int scrnum;
  329. XSetWindowAttributes attr;
  330. unsigned long mask;
  331. Window root;
  332. Window win;
  333. XVisualInfo *visInfo, visTemplate;
  334. int num_visuals;
  335. EGLContext ctx;
  336. EGLConfig config;
  337. EGLint num_configs;
  338. EGLint vid;
  339. scrnum = DefaultScreen( x_dpy );
  340. root = RootWindow( x_dpy, scrnum );
  341. if (!eglChooseConfig( egl_dpy, attribs, &config, 1, &num_configs)) {
  342. printf("Error: couldn't get an EGL visual config\n");
  343. exit(1);
  344. }
  345. assert(config);
  346. assert(num_configs > 0);
  347. if (!eglGetConfigAttrib(egl_dpy, config, EGL_NATIVE_VISUAL_ID, &vid)) {
  348. printf("Error: eglGetConfigAttrib() failed\n");
  349. exit(1);
  350. }
  351. /* The X window visual must match the EGL config */
  352. visTemplate.visualid = vid;
  353. visInfo = XGetVisualInfo(x_dpy, VisualIDMask, &visTemplate, &num_visuals);
  354. if (!visInfo) {
  355. printf("Error: couldn't get X visual\n");
  356. exit(1);
  357. }
  358. /* window attributes */
  359. attr.background_pixel = 0;
  360. attr.border_pixel = 0;
  361. attr.colormap = XCreateColormap( x_dpy, root, visInfo->visual, AllocNone);
  362. attr.event_mask = StructureNotifyMask | ExposureMask | KeyPressMask;
  363. mask = CWBackPixel | CWBorderPixel | CWColormap | CWEventMask;
  364. win = XCreateWindow( x_dpy, root, 0, 0, width, height,
  365. 0, visInfo->depth, InputOutput,
  366. visInfo->visual, mask, &attr );
  367. /* set hints and properties */
  368. {
  369. XSizeHints sizehints;
  370. sizehints.x = x;
  371. sizehints.y = y;
  372. sizehints.width = width;
  373. sizehints.height = height;
  374. sizehints.flags = USSize | USPosition;
  375. XSetNormalHints(x_dpy, win, &sizehints);
  376. XSetStandardProperties(x_dpy, win, name, name,
  377. None, (char **)NULL, 0, &sizehints);
  378. }
  379. eglBindAPI(EGL_OPENGL_ES_API);
  380. ctx = eglCreateContext(egl_dpy, config, EGL_NO_CONTEXT, NULL );
  381. if (!ctx) {
  382. printf("Error: eglCreateContext failed\n");
  383. exit(1);
  384. }
  385. *surfRet = eglCreateWindowSurface(egl_dpy, config, win, NULL);
  386. if (!*surfRet) {
  387. printf("Error: eglCreateWindowSurface failed\n");
  388. exit(1);
  389. }
  390. XFree(visInfo);
  391. *winRet = win;
  392. *ctxRet = ctx;
  393. }
  394. static void
  395. event_loop(Display *dpy, Window win,
  396. EGLDisplay egl_dpy, EGLSurface egl_surf)
  397. {
  398. int anim = 1;
  399. while (1) {
  400. int redraw = 0;
  401. if (!anim || XPending(dpy)) {
  402. XEvent event;
  403. XNextEvent(dpy, &event);
  404. switch (event.type) {
  405. case Expose:
  406. redraw = 1;
  407. break;
  408. case ConfigureNotify:
  409. reshape(event.xconfigure.width, event.xconfigure.height);
  410. break;
  411. case KeyPress:
  412. {
  413. char buffer[10];
  414. int r, code;
  415. code = XLookupKeysym(&event.xkey, 0);
  416. if (code == XK_Left) {
  417. view_roty += 5.0;
  418. }
  419. else if (code == XK_Right) {
  420. view_roty -= 5.0;
  421. }
  422. else if (code == XK_Up) {
  423. view_rotx += 5.0;
  424. }
  425. else if (code == XK_Down) {
  426. view_rotx -= 5.0;
  427. }
  428. else if (code == XK_t) {
  429. GLint size;
  430. tex_format = (tex_format + 1) % (NUM_CPAL_FORMATS + 1);
  431. if (tex_format < NUM_CPAL_FORMATS) {
  432. size = make_cpal_texture(tex_format);
  433. printf("Using %s (%d bytes)\n",
  434. cpal_formats[tex_format].name, size);
  435. }
  436. else {
  437. size = make_texture();
  438. printf("Using uncompressed texture (%d bytes)\n", size);
  439. }
  440. }
  441. else {
  442. r = XLookupString(&event.xkey, buffer, sizeof(buffer),
  443. NULL, NULL);
  444. if (buffer[0] == ' ') {
  445. anim = !anim;
  446. }
  447. else if (buffer[0] == 27) {
  448. /* escape */
  449. return;
  450. }
  451. }
  452. }
  453. redraw = 1;
  454. break;
  455. default:
  456. ; /*no-op*/
  457. }
  458. }
  459. if (anim) {
  460. view_rotx += 1.0;
  461. view_roty += 2.0;
  462. redraw = 1;
  463. }
  464. if (redraw) {
  465. draw();
  466. eglSwapBuffers(egl_dpy, egl_surf);
  467. }
  468. }
  469. }
  470. static void
  471. usage(void)
  472. {
  473. printf("Usage:\n");
  474. printf(" -display <displayname> set the display to run on\n");
  475. printf(" -info display OpenGL renderer info\n");
  476. }
  477. int
  478. main(int argc, char *argv[])
  479. {
  480. const int winWidth = 300, winHeight = 300;
  481. Display *x_dpy;
  482. Window win;
  483. EGLSurface egl_surf;
  484. EGLContext egl_ctx;
  485. EGLDisplay egl_dpy;
  486. char *dpyName = NULL;
  487. GLboolean printInfo = GL_FALSE;
  488. EGLint egl_major, egl_minor;
  489. int i;
  490. const char *s;
  491. for (i = 1; i < argc; i++) {
  492. if (strcmp(argv[i], "-display") == 0) {
  493. dpyName = argv[i+1];
  494. i++;
  495. }
  496. else if (strcmp(argv[i], "-info") == 0) {
  497. printInfo = GL_TRUE;
  498. }
  499. else {
  500. usage();
  501. return -1;
  502. }
  503. }
  504. x_dpy = XOpenDisplay(dpyName);
  505. if (!x_dpy) {
  506. printf("Error: couldn't open display %s\n",
  507. dpyName ? dpyName : getenv("DISPLAY"));
  508. return -1;
  509. }
  510. egl_dpy = eglGetDisplay(x_dpy);
  511. if (!egl_dpy) {
  512. printf("Error: eglGetDisplay() failed\n");
  513. return -1;
  514. }
  515. if (!eglInitialize(egl_dpy, &egl_major, &egl_minor)) {
  516. printf("Error: eglInitialize() failed\n");
  517. return -1;
  518. }
  519. s = eglQueryString(egl_dpy, EGL_VERSION);
  520. printf("EGL_VERSION = %s\n", s);
  521. s = eglQueryString(egl_dpy, EGL_VENDOR);
  522. printf("EGL_VENDOR = %s\n", s);
  523. s = eglQueryString(egl_dpy, EGL_EXTENSIONS);
  524. printf("EGL_EXTENSIONS = %s\n", s);
  525. s = eglQueryString(egl_dpy, EGL_CLIENT_APIS);
  526. printf("EGL_CLIENT_APIS = %s\n", s);
  527. make_x_window(x_dpy, egl_dpy,
  528. "torus", 0, 0, winWidth, winHeight,
  529. &win, &egl_ctx, &egl_surf);
  530. XMapWindow(x_dpy, win);
  531. if (!eglMakeCurrent(egl_dpy, egl_surf, egl_surf, egl_ctx)) {
  532. printf("Error: eglMakeCurrent() failed\n");
  533. return -1;
  534. }
  535. if (printInfo) {
  536. printf("GL_RENDERER = %s\n", (char *) glGetString(GL_RENDERER));
  537. printf("GL_VERSION = %s\n", (char *) glGetString(GL_VERSION));
  538. printf("GL_VENDOR = %s\n", (char *) glGetString(GL_VENDOR));
  539. printf("GL_EXTENSIONS = %s\n", (char *) glGetString(GL_EXTENSIONS));
  540. }
  541. init();
  542. /* Set initial projection/viewing transformation.
  543. * We can't be sure we'll get a ConfigureNotify event when the window
  544. * first appears.
  545. */
  546. reshape(winWidth, winHeight);
  547. event_loop(x_dpy, win, egl_dpy, egl_surf);
  548. eglDestroyContext(egl_dpy, egl_ctx);
  549. eglDestroySurface(egl_dpy, egl_surf);
  550. eglTerminate(egl_dpy);
  551. XDestroyWindow(x_dpy, win);
  552. XCloseDisplay(x_dpy);
  553. return 0;
  554. }