Merge branch '7.8'
[mesa.git] / progs / egl / opengl / xeglgears.c
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 /*
23 * Ported to X/EGL/GLES. XXX Actually, uses full OpenGL ATM.
24 * Brian Paul
25 * 30 May 2008
26 */
27
28 /*
29 * Command line options:
30 * -info print GL implementation information
31 *
32 */
33
34
35 #define GL_GLEXT_PROTOTYPES
36 #define EGL_EGLEXT_PROTOTYPES
37
38 #include <math.h>
39 #include <stdlib.h>
40 #include <stdio.h>
41 #include <string.h>
42 #include <X11/Xlib.h>
43 #include <X11/Xutil.h>
44 #include <X11/keysym.h>
45 #include <GL/gl.h>
46 #include <EGL/egl.h>
47
48 #include <EGL/eglext.h>
49
50
51 #define BENCHMARK
52
53 #ifdef BENCHMARK
54
55 /* XXX this probably isn't very portable */
56
57 #include <sys/time.h>
58 #include <unistd.h>
59
60 /* return current time (in seconds) */
61 static double
62 current_time(void)
63 {
64 struct timeval tv;
65 #ifdef __VMS
66 (void) gettimeofday(&tv, NULL );
67 #else
68 struct timezone tz;
69 (void) gettimeofday(&tv, &tz);
70 #endif
71 return (double) tv.tv_sec + tv.tv_usec / 1000000.0;
72 }
73
74 #else /*BENCHMARK*/
75
76 /* dummy */
77 static double
78 current_time(void)
79 {
80 /* update this function for other platforms! */
81 static double t = 0.0;
82 static int warn = 1;
83 if (warn) {
84 fprintf(stderr, "Warning: current_time() not implemented!!\n");
85 warn = 0;
86 }
87 return t += 1.0;
88 }
89
90 #endif /*BENCHMARK*/
91
92
93
94 #ifndef M_PI
95 #define M_PI 3.14159265
96 #endif
97
98
99 static GLfloat view_rotx = 20.0, view_roty = 30.0, view_rotz = 0.0;
100 static GLint gear1, gear2, gear3;
101 static GLfloat angle = 0.0;
102
103 /*
104 *
105 * Draw a gear wheel. You'll probably want to call this function when
106 * building a display list since we do a lot of trig here.
107 *
108 * Input: inner_radius - radius of hole at center
109 * outer_radius - radius at center of teeth
110 * width - width of gear
111 * teeth - number of teeth
112 * tooth_depth - depth of tooth
113 */
114 static void
115 gear(GLfloat inner_radius, GLfloat outer_radius, GLfloat width,
116 GLint teeth, GLfloat tooth_depth)
117 {
118 GLint i;
119 GLfloat r0, r1, r2;
120 GLfloat angle, da;
121 GLfloat u, v, len;
122
123 r0 = inner_radius;
124 r1 = outer_radius - tooth_depth / 2.0;
125 r2 = outer_radius + tooth_depth / 2.0;
126
127 da = 2.0 * M_PI / teeth / 4.0;
128
129 glShadeModel(GL_FLAT);
130
131 glNormal3f(0.0, 0.0, 1.0);
132
133 /* draw front face */
134 glBegin(GL_QUAD_STRIP);
135 for (i = 0; i <= teeth; i++) {
136 angle = i * 2.0 * M_PI / teeth;
137 glVertex3f(r0 * cos(angle), r0 * sin(angle), width * 0.5);
138 glVertex3f(r1 * cos(angle), r1 * sin(angle), width * 0.5);
139 if (i < teeth) {
140 glVertex3f(r0 * cos(angle), r0 * sin(angle), width * 0.5);
141 glVertex3f(r1 * cos(angle + 3 * da), r1 * sin(angle + 3 * da),
142 width * 0.5);
143 }
144 }
145 glEnd();
146
147 /* draw front sides of teeth */
148 glBegin(GL_QUADS);
149 da = 2.0 * M_PI / teeth / 4.0;
150 for (i = 0; i < teeth; i++) {
151 angle = i * 2.0 * M_PI / teeth;
152
153 glVertex3f(r1 * cos(angle), r1 * sin(angle), width * 0.5);
154 glVertex3f(r2 * cos(angle + da), r2 * sin(angle + da), width * 0.5);
155 glVertex3f(r2 * cos(angle + 2 * da), r2 * sin(angle + 2 * da),
156 width * 0.5);
157 glVertex3f(r1 * cos(angle + 3 * da), r1 * sin(angle + 3 * da),
158 width * 0.5);
159 }
160 glEnd();
161
162 glNormal3f(0.0, 0.0, -1.0);
163
164 /* draw back face */
165 glBegin(GL_QUAD_STRIP);
166 for (i = 0; i <= teeth; i++) {
167 angle = i * 2.0 * M_PI / teeth;
168 glVertex3f(r1 * cos(angle), r1 * sin(angle), -width * 0.5);
169 glVertex3f(r0 * cos(angle), r0 * sin(angle), -width * 0.5);
170 if (i < teeth) {
171 glVertex3f(r1 * cos(angle + 3 * da), r1 * sin(angle + 3 * da),
172 -width * 0.5);
173 glVertex3f(r0 * cos(angle), r0 * sin(angle), -width * 0.5);
174 }
175 }
176 glEnd();
177
178 /* draw back sides of teeth */
179 glBegin(GL_QUADS);
180 da = 2.0 * M_PI / teeth / 4.0;
181 for (i = 0; i < teeth; i++) {
182 angle = i * 2.0 * M_PI / teeth;
183
184 glVertex3f(r1 * cos(angle + 3 * da), r1 * sin(angle + 3 * da),
185 -width * 0.5);
186 glVertex3f(r2 * cos(angle + 2 * da), r2 * sin(angle + 2 * da),
187 -width * 0.5);
188 glVertex3f(r2 * cos(angle + da), r2 * sin(angle + da), -width * 0.5);
189 glVertex3f(r1 * cos(angle), r1 * sin(angle), -width * 0.5);
190 }
191 glEnd();
192
193 /* draw outward faces of teeth */
194 glBegin(GL_QUAD_STRIP);
195 for (i = 0; i < teeth; i++) {
196 angle = i * 2.0 * M_PI / teeth;
197
198 glVertex3f(r1 * cos(angle), r1 * sin(angle), width * 0.5);
199 glVertex3f(r1 * cos(angle), r1 * sin(angle), -width * 0.5);
200 u = r2 * cos(angle + da) - r1 * cos(angle);
201 v = r2 * sin(angle + da) - r1 * sin(angle);
202 len = sqrt(u * u + v * v);
203 u /= len;
204 v /= len;
205 glNormal3f(v, -u, 0.0);
206 glVertex3f(r2 * cos(angle + da), r2 * sin(angle + da), width * 0.5);
207 glVertex3f(r2 * cos(angle + da), r2 * sin(angle + da), -width * 0.5);
208 glNormal3f(cos(angle), sin(angle), 0.0);
209 glVertex3f(r2 * cos(angle + 2 * da), r2 * sin(angle + 2 * da),
210 width * 0.5);
211 glVertex3f(r2 * cos(angle + 2 * da), r2 * sin(angle + 2 * da),
212 -width * 0.5);
213 u = r1 * cos(angle + 3 * da) - r2 * cos(angle + 2 * da);
214 v = r1 * sin(angle + 3 * da) - r2 * sin(angle + 2 * da);
215 glNormal3f(v, -u, 0.0);
216 glVertex3f(r1 * cos(angle + 3 * da), r1 * sin(angle + 3 * da),
217 width * 0.5);
218 glVertex3f(r1 * cos(angle + 3 * da), r1 * sin(angle + 3 * da),
219 -width * 0.5);
220 glNormal3f(cos(angle), sin(angle), 0.0);
221 }
222
223 glVertex3f(r1 * cos(0), r1 * sin(0), width * 0.5);
224 glVertex3f(r1 * cos(0), r1 * sin(0), -width * 0.5);
225
226 glEnd();
227
228 glShadeModel(GL_SMOOTH);
229
230 /* draw inside radius cylinder */
231 glBegin(GL_QUAD_STRIP);
232 for (i = 0; i <= teeth; i++) {
233 angle = i * 2.0 * M_PI / teeth;
234 glNormal3f(-cos(angle), -sin(angle), 0.0);
235 glVertex3f(r0 * cos(angle), r0 * sin(angle), -width * 0.5);
236 glVertex3f(r0 * cos(angle), r0 * sin(angle), width * 0.5);
237 }
238 glEnd();
239 }
240
241
242 static void
243 draw(void)
244 {
245 glClearColor(0.2, 0.2, 0.2, 0.2);
246 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
247
248 glPushMatrix();
249 glRotatef(view_rotx, 1.0, 0.0, 0.0);
250 glRotatef(view_roty, 0.0, 1.0, 0.0);
251 glRotatef(view_rotz, 0.0, 0.0, 1.0);
252
253 glPushMatrix();
254 glTranslatef(-3.0, -2.0, 0.0);
255 glRotatef(angle, 0.0, 0.0, 1.0);
256 glCallList(gear1);
257 glPopMatrix();
258
259 glPushMatrix();
260 glTranslatef(3.1, -2.0, 0.0);
261 glRotatef(-2.0 * angle - 9.0, 0.0, 0.0, 1.0);
262 glCallList(gear2);
263 glPopMatrix();
264
265 glPushMatrix();
266 glTranslatef(-3.1, 4.2, 0.0);
267 glRotatef(-2.0 * angle - 25.0, 0.0, 0.0, 1.0);
268 glCallList(gear3);
269 glPopMatrix();
270
271 glPopMatrix();
272 }
273
274
275 /* new window size or exposure */
276 static void
277 reshape(int width, int height)
278 {
279 GLfloat ar = (GLfloat) width / (GLfloat) height;
280
281 glViewport(0, 0, (GLint) width, (GLint) height);
282
283 glMatrixMode(GL_PROJECTION);
284 glLoadIdentity();
285 glFrustum(-ar, ar, -1, 1, 5.0, 60.0);
286
287 glMatrixMode(GL_MODELVIEW);
288 glLoadIdentity();
289 glTranslatef(0.0, 0.0, -40.0);
290 }
291
292
293
294 static void
295 init(void)
296 {
297 static GLfloat pos[4] = { 5.0, 5.0, 10.0, 0.0 };
298 static GLfloat red[4] = { 0.8, 0.1, 0.0, 1.0 };
299 static GLfloat green[4] = { 0.0, 0.8, 0.2, 1.0 };
300 static GLfloat blue[4] = { 0.2, 0.2, 1.0, 1.0 };
301
302 glLightfv(GL_LIGHT0, GL_POSITION, pos);
303 glEnable(GL_CULL_FACE);
304 glEnable(GL_LIGHTING);
305 glEnable(GL_LIGHT0);
306 glEnable(GL_DEPTH_TEST);
307
308 /* make the gears */
309 gear1 = glGenLists(1);
310 glNewList(gear1, GL_COMPILE);
311 glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, red);
312 gear(1.0, 4.0, 1.0, 20, 0.7);
313 glEndList();
314
315 gear2 = glGenLists(1);
316 glNewList(gear2, GL_COMPILE);
317 glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, green);
318 gear(0.5, 2.0, 2.0, 10, 0.7);
319 glEndList();
320
321 gear3 = glGenLists(1);
322 glNewList(gear3, GL_COMPILE);
323 glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, blue);
324 gear(1.3, 2.0, 0.5, 10, 0.7);
325 glEndList();
326
327 glEnable(GL_NORMALIZE);
328 }
329
330
331 struct egl_manager {
332 EGLNativeDisplayType xdpy;
333 EGLNativeWindowType xwin;
334 EGLNativePixmapType xpix;
335
336 EGLDisplay dpy;
337 EGLConfig conf;
338 EGLContext ctx;
339
340 EGLSurface win;
341 EGLSurface pix;
342 EGLSurface pbuf;
343 EGLImageKHR image;
344
345 EGLBoolean verbose;
346 EGLint major, minor;
347
348 GC gc;
349 GLuint fbo;
350 };
351
352 static struct egl_manager *
353 egl_manager_new(EGLNativeDisplayType xdpy, const EGLint *attrib_list,
354 EGLBoolean verbose)
355 {
356 struct egl_manager *eman;
357 const char *ver;
358 EGLint num_conf;
359
360 eman = calloc(1, sizeof(*eman));
361 if (!eman)
362 return NULL;
363
364 eman->verbose = verbose;
365 eman->xdpy = xdpy;
366
367 eman->dpy = eglGetDisplay(eman->xdpy);
368 if (eman->dpy == EGL_NO_DISPLAY) {
369 printf("eglGetDisplay() failed\n");
370 free(eman);
371 return NULL;
372 }
373
374 if (!eglInitialize(eman->dpy, &eman->major, &eman->minor)) {
375 printf("eglInitialize() failed\n");
376 free(eman);
377 return NULL;
378 }
379
380 ver = eglQueryString(eman->dpy, EGL_VERSION);
381 printf("EGL_VERSION = %s\n", ver);
382
383 if (!eglChooseConfig(eman->dpy, attrib_list, &eman->conf, 1, &num_conf) ||
384 !num_conf) {
385 printf("eglChooseConfig() failed\n");
386 eglTerminate(eman->dpy);
387 free(eman);
388 return NULL;
389 }
390
391 eman->ctx = eglCreateContext(eman->dpy, eman->conf, EGL_NO_CONTEXT, NULL);
392 if (eman->ctx == EGL_NO_CONTEXT) {
393 printf("eglCreateContext() failed\n");
394 eglTerminate(eman->dpy);
395 free(eman);
396 return NULL;
397 }
398
399 return eman;
400 }
401
402 static EGLBoolean
403 egl_manager_create_window(struct egl_manager *eman, const char *name,
404 EGLint w, EGLint h, EGLBoolean need_surface,
405 EGLBoolean fullscreen, const EGLint *attrib_list)
406 {
407 XVisualInfo vinfo_template, *vinfo = NULL;
408 EGLint val, num_vinfo;
409 Window root;
410 XSetWindowAttributes attrs;
411 unsigned long mask;
412 EGLint x = 0, y = 0;
413
414 if (!eglGetConfigAttrib(eman->dpy, eman->conf,
415 EGL_NATIVE_VISUAL_ID, &val)) {
416 printf("eglGetConfigAttrib() failed\n");
417 return EGL_FALSE;
418 }
419 if (val) {
420 vinfo_template.visualid = (VisualID) val;
421 vinfo = XGetVisualInfo(eman->xdpy, VisualIDMask, &vinfo_template, &num_vinfo);
422 }
423 /* try harder if window surface is not needed */
424 if (!vinfo && !need_surface &&
425 eglGetConfigAttrib(eman->dpy, eman->conf, EGL_BUFFER_SIZE, &val)) {
426 if (val == 32)
427 val = 24;
428 vinfo_template.depth = val;
429 vinfo = XGetVisualInfo(eman->xdpy, VisualDepthMask, &vinfo_template, &num_vinfo);
430 }
431
432 if (!vinfo) {
433 printf("XGetVisualInfo() failed\n");
434 return EGL_FALSE;
435 }
436
437 root = DefaultRootWindow(eman->xdpy);
438 if (fullscreen) {
439 x = y = 0;
440 w = DisplayWidth(eman->xdpy, DefaultScreen(eman->xdpy));
441 h = DisplayHeight(eman->xdpy, DefaultScreen(eman->xdpy));
442 }
443
444 /* window attributes */
445 attrs.background_pixel = 0;
446 attrs.border_pixel = 0;
447 attrs.colormap = XCreateColormap(eman->xdpy, root, vinfo->visual, AllocNone);
448 attrs.event_mask = StructureNotifyMask | ExposureMask | KeyPressMask;
449 attrs.override_redirect = fullscreen;
450 mask = CWBackPixel | CWBorderPixel | CWColormap | CWEventMask | CWOverrideRedirect;
451
452 eman->xwin = XCreateWindow(eman->xdpy, root, x, y, w, h,
453 0, vinfo->depth, InputOutput,
454 vinfo->visual, mask, &attrs);
455 XFree(vinfo);
456
457 /* set hints and properties */
458 {
459 XSizeHints sizehints;
460 sizehints.x = x;
461 sizehints.y = y;
462 sizehints.width = w;
463 sizehints.height = h;
464 sizehints.flags = USSize | USPosition;
465 XSetNormalHints(eman->xdpy, eman->xwin, &sizehints);
466 XSetStandardProperties(eman->xdpy, eman->xwin, name, name,
467 None, (char **)NULL, 0, &sizehints);
468 }
469
470 if (need_surface) {
471 eman->win = eglCreateWindowSurface(eman->dpy, eman->conf,
472 eman->xwin, attrib_list);
473 if (eman->win == EGL_NO_SURFACE) {
474 printf("eglCreateWindowSurface() failed\n");
475 XDestroyWindow(eman->xdpy, eman->xwin);
476 eman->xwin = None;
477 return EGL_FALSE;
478 }
479 }
480
481 eman->gc = XCreateGC(eman->xdpy, eman->xwin, 0, NULL);
482
483 XMapWindow(eman->xdpy, eman->xwin);
484
485 return EGL_TRUE;
486 }
487
488 static EGLBoolean
489 egl_manager_create_pixmap(struct egl_manager *eman, EGLNativeWindowType xwin,
490 EGLBoolean need_surface, const EGLint *attrib_list)
491 {
492 XWindowAttributes attrs;
493
494 if (!XGetWindowAttributes(eman->xdpy, xwin, &attrs)) {
495 printf("XGetWindowAttributes() failed\n");
496 return EGL_FALSE;
497 }
498
499 eman->xpix = XCreatePixmap(eman->xdpy, xwin,
500 attrs.width, attrs.height, attrs.depth);
501
502 if (need_surface) {
503 eman->pix = eglCreatePixmapSurface(eman->dpy, eman->conf,
504 eman->xpix, attrib_list);
505 if (eman->pix == EGL_NO_SURFACE) {
506 printf("eglCreatePixmapSurface() failed\n");
507 XFreePixmap(eman->xdpy, eman->xpix);
508 eman->xpix = None;
509 return EGL_FALSE;
510 }
511 }
512
513 return EGL_TRUE;
514 }
515
516 static EGLBoolean
517 egl_manager_create_pbuffer(struct egl_manager *eman, const EGLint *attrib_list)
518 {
519 eman->pbuf = eglCreatePbufferSurface(eman->dpy, eman->conf, attrib_list);
520 if (eman->pbuf == EGL_NO_SURFACE) {
521 printf("eglCreatePbufferSurface() failed\n");
522 return EGL_FALSE;
523 }
524
525 return EGL_TRUE;
526 }
527
528 static void
529 egl_manager_destroy(struct egl_manager *eman)
530 {
531 eglMakeCurrent(eman->dpy, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
532 eglTerminate(eman->dpy);
533
534 if (eman->xwin != None)
535 XDestroyWindow(eman->xdpy, eman->xwin);
536 if (eman->xpix != None)
537 XFreePixmap(eman->xdpy, eman->xpix);
538
539 XFreeGC(eman->xdpy, eman->gc);
540
541 free(eman);
542 }
543
544 enum {
545 GEARS_WINDOW,
546 GEARS_PIXMAP,
547 GEARS_PIXMAP_TEXTURE,
548 GEARS_PBUFFER,
549 GEARS_PBUFFER_TEXTURE,
550 GEARS_RENDERBUFFER
551 };
552
553 static void
554 texture_gears(struct egl_manager *eman, int surface_type)
555 {
556 static const GLint verts[12] =
557 { -5, -6, -10, 5, -6, -10, -5, 4, 10, 5, 4, 10 };
558 static const GLint tex_coords[8] = { 0, 0, 1, 0, 0, 1, 1, 1 };
559
560 eglMakeCurrent(eman->dpy, eman->win, eman->win, eman->ctx);
561
562 glClearColor(0, 0, 0, 0);
563 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
564
565 glEnable(GL_TEXTURE_2D);
566 glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
567 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_R, GL_REPEAT);
568 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
569 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
570
571 glEnableClientState(GL_VERTEX_ARRAY);
572 glEnableClientState(GL_TEXTURE_COORD_ARRAY);
573 glVertexPointer(3, GL_INT, 0, verts);
574 glTexCoordPointer(2, GL_INT, 0, tex_coords);
575
576 if (surface_type == GEARS_PBUFFER_TEXTURE)
577 eglBindTexImage(eman->dpy, eman->pbuf, EGL_BACK_BUFFER);
578
579 glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
580
581 glDisableClientState(GL_VERTEX_ARRAY);
582 glDisableClientState(GL_COLOR_ARRAY);
583 glDisable(GL_TEXTURE_2D);
584
585 if (surface_type == GEARS_PBUFFER_TEXTURE)
586 eglReleaseTexImage(eman->dpy, eman->pbuf, EGL_BACK_BUFFER);
587
588 eglSwapBuffers(eman->dpy, eman->win);
589 }
590
591 static void
592 copy_gears(struct egl_manager *eman,
593 EGLint tile_w, EGLint tile_h, EGLint w, EGLint h)
594 {
595 int x, y;
596
597 eglWaitClient();
598
599 for (x = 0; x < w; x += tile_w) {
600 for (y = 0; y < h; y += tile_h) {
601
602 XCopyArea(eman->xdpy, eman->xpix, eman->xwin, eman->gc,
603 0, 0, tile_w, tile_h, x, y);
604 }
605 }
606 }
607
608 static void
609 event_loop(struct egl_manager *eman, EGLint surface_type, EGLint w, EGLint h)
610 {
611 int window_w = w, window_h = h;
612
613 if (surface_type == EGL_PBUFFER_BIT)
614 printf("there will be no screen update if "
615 "eglCopyBuffers() is not implemented\n");
616
617 while (1) {
618 while (XPending(eman->xdpy) > 0) {
619 XEvent event;
620 XNextEvent(eman->xdpy, &event);
621 switch (event.type) {
622 case Expose:
623 /* we'll redraw below */
624 break;
625 case ConfigureNotify:
626 window_w = event.xconfigure.width;
627 window_h = event.xconfigure.height;
628 if (surface_type == EGL_WINDOW_BIT)
629 reshape(window_w, window_h);
630 break;
631 case KeyPress:
632 {
633 char buffer[10];
634 int r, code;
635 code = XLookupKeysym(&event.xkey, 0);
636 if (code == XK_Left) {
637 view_roty += 5.0;
638 }
639 else if (code == XK_Right) {
640 view_roty -= 5.0;
641 }
642 else if (code == XK_Up) {
643 view_rotx += 5.0;
644 }
645 else if (code == XK_Down) {
646 view_rotx -= 5.0;
647 }
648 else {
649 r = XLookupString(&event.xkey, buffer, sizeof(buffer),
650 NULL, NULL);
651 if (buffer[0] == 27) {
652 /* escape */
653 return;
654 }
655 }
656 }
657 }
658 }
659
660 {
661 static int frames = 0;
662 static double tRot0 = -1.0, tRate0 = -1.0;
663 double dt, t = current_time();
664 if (tRot0 < 0.0)
665 tRot0 = t;
666 dt = t - tRot0;
667 tRot0 = t;
668
669 /* advance rotation for next frame */
670 angle += 70.0 * dt; /* 70 degrees per second */
671 if (angle > 3600.0)
672 angle -= 3600.0;
673
674 switch (surface_type) {
675 case GEARS_WINDOW:
676 draw();
677 eglSwapBuffers(eman->dpy, eman->win);
678 break;
679
680 case GEARS_PBUFFER:
681 draw();
682 if (!eglCopyBuffers(eman->dpy, eman->pbuf, eman->xpix))
683 break;
684 copy_gears(eman, w, h, window_w, window_h);
685 break;
686
687 case GEARS_PBUFFER_TEXTURE:
688 eglMakeCurrent(eman->dpy, eman->pbuf, eman->pbuf, eman->ctx);
689 draw();
690 texture_gears(eman, surface_type);
691 break;
692
693 case GEARS_PIXMAP:
694 draw();
695 copy_gears(eman, w, h, window_w, window_h);
696 break;
697
698 case GEARS_PIXMAP_TEXTURE:
699 eglMakeCurrent(eman->dpy, eman->pix, eman->pix, eman->ctx);
700 draw();
701 texture_gears(eman, surface_type);
702 break;
703
704 case GEARS_RENDERBUFFER:
705 glBindFramebuffer(GL_FRAMEBUFFER_EXT, eman->fbo);
706 draw();
707 glBindFramebuffer(GL_FRAMEBUFFER_EXT, 0);
708 texture_gears(eman, surface_type);
709 break;
710 }
711
712 frames++;
713
714 if (tRate0 < 0.0)
715 tRate0 = t;
716 if (t - tRate0 >= 5.0) {
717 GLfloat seconds = t - tRate0;
718 GLfloat fps = frames / seconds;
719 printf("%d frames in %3.1f seconds = %6.3f FPS\n", frames, seconds,
720 fps);
721 tRate0 = t;
722 frames = 0;
723 }
724 }
725 }
726 }
727
728
729 static void
730 usage(void)
731 {
732 printf("Usage:\n");
733 printf(" -display <displayname> set the display to run on\n");
734 printf(" -fullscreen run in fullscreen mode\n");
735 printf(" -info display OpenGL renderer info\n");
736 printf(" -pixmap use pixmap surface\n");
737 printf(" -pixmap-texture use pixmap surface and texture using EGLImage\n");
738 printf(" -pbuffer use pbuffer surface and eglCopyBuffers\n");
739 printf(" -pbuffer-texture use pbuffer surface and eglBindTexImage\n");
740 printf(" -renderbuffer renderbuffer as EGLImage and bind as texture from\n");
741 }
742
743 static const char *names[] = {
744 "window",
745 "pixmap",
746 "pixmap_texture",
747 "pbuffer",
748 "pbuffer_texture",
749 "renderbuffer"
750 };
751
752 int
753 main(int argc, char *argv[])
754 {
755 const int winWidth = 300, winHeight = 300;
756 Display *x_dpy;
757 char *dpyName = NULL;
758 struct egl_manager *eman;
759 EGLint attribs[] = {
760 EGL_SURFACE_TYPE, EGL_WINDOW_BIT, /* may be changed later */
761 EGL_RED_SIZE, 1,
762 EGL_GREEN_SIZE, 1,
763 EGL_BLUE_SIZE, 1,
764 EGL_DEPTH_SIZE, 1,
765 EGL_RENDERABLE_TYPE, EGL_OPENGL_BIT,
766 EGL_NONE
767 };
768 char win_title[] = "xeglgears (window/pixmap/pbuffer)";
769 EGLint surface_type = GEARS_WINDOW;
770 GLboolean printInfo = GL_FALSE;
771 GLboolean fullscreen = GL_FALSE;
772 EGLBoolean ret;
773 GLuint texture, color_rb, depth_rb;
774 int i;
775
776 for (i = 1; i < argc; i++) {
777 if (strcmp(argv[i], "-display") == 0) {
778 dpyName = argv[i+1];
779 i++;
780 }
781 else if (strcmp(argv[i], "-info") == 0) {
782 printInfo = GL_TRUE;
783 }
784 else if (strcmp(argv[i], "-fullscreen") == 0) {
785 fullscreen = GL_TRUE;
786 }
787 else if (strcmp(argv[i], "-pixmap") == 0) {
788 surface_type = GEARS_PIXMAP;
789 attribs[1] = EGL_PIXMAP_BIT;
790 }
791 else if (strcmp(argv[i], "-pixmap-texture") == 0) {
792 surface_type = GEARS_PIXMAP_TEXTURE;
793 attribs[1] = EGL_PIXMAP_BIT;
794 }
795 else if (strcmp(argv[i], "-pbuffer") == 0) {
796 surface_type = GEARS_PBUFFER;
797 attribs[1] = EGL_PBUFFER_BIT;
798 }
799 else if (strcmp(argv[i], "-pbuffer-texture") == 0) {
800 surface_type = GEARS_PBUFFER_TEXTURE;
801 attribs[1] = EGL_PBUFFER_BIT;
802 }
803 else if (strcmp(argv[i], "-renderbuffer") == 0) {
804 surface_type = GEARS_RENDERBUFFER;
805 }
806 else {
807 usage();
808 return -1;
809 }
810 }
811
812 x_dpy = XOpenDisplay(dpyName);
813 if (!x_dpy) {
814 printf("Error: couldn't open display %s\n",
815 dpyName ? dpyName : getenv("DISPLAY"));
816 return -1;
817 }
818
819 eglBindAPI(EGL_OPENGL_API);
820
821 eman = egl_manager_new(x_dpy, attribs, printInfo);
822 if (!eman) {
823 XCloseDisplay(x_dpy);
824 return -1;
825 }
826
827 snprintf(win_title, sizeof(win_title),
828 "xeglgears (%s)", names[surface_type]);
829
830 ret = egl_manager_create_window(eman, win_title, winWidth, winHeight,
831 EGL_TRUE, fullscreen, NULL);
832 if (!ret)
833 return -1;
834
835 /* create surface(s) */
836 switch (surface_type) {
837 case GEARS_WINDOW:
838 if (ret)
839 ret = eglMakeCurrent(eman->dpy, eman->win, eman->win, eman->ctx);
840 break;
841 case GEARS_PIXMAP:
842 case GEARS_PIXMAP_TEXTURE:
843 ret = egl_manager_create_pixmap(eman, eman->xwin, EGL_TRUE, NULL);
844 if (surface_type == GEARS_PIXMAP_TEXTURE)
845 eman->image = eglCreateImageKHR (eman->dpy, eman->ctx,
846 EGL_NATIVE_PIXMAP_KHR,
847 (EGLClientBuffer) eman->xpix, NULL);
848 if (ret)
849 ret = eglMakeCurrent(eman->dpy, eman->pix, eman->pix, eman->ctx);
850 break;
851 case GEARS_PBUFFER:
852 case GEARS_PBUFFER_TEXTURE:
853 {
854 EGLint pbuf_attribs[] = {
855 EGL_WIDTH, winWidth,
856 EGL_HEIGHT, winHeight,
857 EGL_TEXTURE_FORMAT, EGL_TEXTURE_RGB,
858 EGL_TEXTURE_TARGET, EGL_TEXTURE_2D,
859 EGL_NONE
860 };
861 ret = (egl_manager_create_pixmap(eman, eman->xwin,
862 EGL_TRUE, NULL) &&
863 egl_manager_create_pbuffer(eman, pbuf_attribs));
864 if (ret)
865 ret = eglMakeCurrent(eman->dpy, eman->pbuf, eman->pbuf, eman->ctx);
866 }
867 break;
868
869
870 case GEARS_RENDERBUFFER:
871 ret = eglMakeCurrent(eman->dpy, eman->win, eman->win, eman->ctx);
872 if (ret == EGL_FALSE)
873 printf("failed to make context current\n");
874
875 glGenFramebuffers(1, &eman->fbo);
876 glBindFramebuffer(GL_FRAMEBUFFER_EXT, eman->fbo);
877
878 glGenRenderbuffers(1, &color_rb);
879 glBindRenderbuffer(GL_RENDERBUFFER_EXT, color_rb);
880 glRenderbufferStorage(GL_RENDERBUFFER_EXT, GL_RGBA, winWidth, winHeight);
881 glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT,
882 GL_COLOR_ATTACHMENT0_EXT,
883 GL_RENDERBUFFER_EXT,
884 color_rb);
885
886 eman->image = eglCreateImageKHR(eman->dpy, eman->ctx,
887 EGL_GL_RENDERBUFFER_KHR,
888 (EGLClientBuffer) color_rb, NULL);
889
890 glGenRenderbuffers(1, &depth_rb);
891 glBindRenderbuffer(GL_RENDERBUFFER_EXT, depth_rb);
892 glRenderbufferStorage(GL_RENDERBUFFER_EXT,
893 GL_DEPTH_COMPONENT, winWidth, winHeight);
894 glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT,
895 GL_DEPTH_ATTACHMENT_EXT,
896 GL_RENDERBUFFER_EXT,
897 depth_rb);
898
899 if (glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT) != GL_FRAMEBUFFER_COMPLETE) {
900 printf("framebuffer not complete\n");
901 exit(1);
902 }
903
904 break;
905
906 default:
907 ret = EGL_FALSE;
908 break;
909 }
910
911 switch (surface_type) {
912 case GEARS_PIXMAP_TEXTURE:
913 case GEARS_RENDERBUFFER:
914 glGenTextures(1, &texture);
915 glBindTexture(GL_TEXTURE_2D, texture);
916 glEGLImageTargetTexture2DOES(GL_TEXTURE_2D, eman->image);
917 break;
918 case GEARS_PBUFFER_TEXTURE:
919 glGenTextures(1, &texture);
920 glBindTexture(GL_TEXTURE_2D, texture);
921 break;
922 }
923
924 if (!ret) {
925 egl_manager_destroy(eman);
926 XCloseDisplay(x_dpy);
927 return -1;
928 }
929
930 if (printInfo) {
931 printf("GL_RENDERER = %s\n", (char *) glGetString(GL_RENDERER));
932 printf("GL_VERSION = %s\n", (char *) glGetString(GL_VERSION));
933 printf("GL_VENDOR = %s\n", (char *) glGetString(GL_VENDOR));
934 }
935
936 init();
937
938 /* Set initial projection/viewing transformation.
939 * We can't be sure we'll get a ConfigureNotify event when the window
940 * first appears.
941 */
942 reshape(winWidth, winHeight);
943
944 event_loop(eman, surface_type, winWidth, winHeight);
945
946 glDeleteLists(gear1, 1);
947 glDeleteLists(gear2, 1);
948 glDeleteLists(gear3, 1);
949
950 egl_manager_destroy(eman);
951 XCloseDisplay(x_dpy);
952
953 return 0;
954 }