957081e50027b9393c8622b5a6519d01bbce63b8
[mesa.git] / progs / egl / 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
349 static struct egl_manager *
350 egl_manager_new(EGLNativeDisplayType xdpy, const EGLint *attrib_list,
351 EGLBoolean verbose)
352 {
353 struct egl_manager *eman;
354 const char *ver;
355 EGLint num_conf;
356
357 eman = calloc(1, sizeof(*eman));
358 if (!eman)
359 return NULL;
360
361 eman->verbose = verbose;
362 eman->xdpy = xdpy;
363
364 eman->dpy = eglGetDisplay(eman->xdpy);
365 if (eman->dpy == EGL_NO_DISPLAY) {
366 printf("eglGetDisplay() failed\n");
367 free(eman);
368 return NULL;
369 }
370
371 if (!eglInitialize(eman->dpy, &eman->major, &eman->minor)) {
372 printf("eglInitialize() failed\n");
373 free(eman);
374 return NULL;
375 }
376
377 ver = eglQueryString(eman->dpy, EGL_VERSION);
378 printf("EGL_VERSION = %s\n", ver);
379
380 if (!eglChooseConfig(eman->dpy, attrib_list, &eman->conf, 1, &num_conf) ||
381 !num_conf) {
382 printf("eglChooseConfig() failed\n");
383 eglTerminate(eman->dpy);
384 free(eman);
385 return NULL;
386 }
387
388 eman->ctx = eglCreateContext(eman->dpy, eman->conf, EGL_NO_CONTEXT, NULL);
389 if (eman->ctx == EGL_NO_CONTEXT) {
390 printf("eglCreateContext() failed\n");
391 eglTerminate(eman->dpy);
392 free(eman);
393 return NULL;
394 }
395
396 return eman;
397 }
398
399 static EGLBoolean
400 egl_manager_create_window(struct egl_manager *eman, const char *name,
401 EGLint w, EGLint h, EGLBoolean need_surface,
402 EGLBoolean fullscreen, const EGLint *attrib_list)
403 {
404 XVisualInfo vinfo_template, *vinfo = NULL;
405 EGLint val, num_vinfo;
406 Window root;
407 XSetWindowAttributes attrs;
408 unsigned long mask;
409 EGLint x = 0, y = 0;
410
411 if (!eglGetConfigAttrib(eman->dpy, eman->conf,
412 EGL_NATIVE_VISUAL_ID, &val)) {
413 printf("eglGetConfigAttrib() failed\n");
414 return EGL_FALSE;
415 }
416 if (val) {
417 vinfo_template.visualid = (VisualID) val;
418 vinfo = XGetVisualInfo(eman->xdpy, VisualIDMask, &vinfo_template, &num_vinfo);
419 }
420 /* try harder if window surface is not needed */
421 if (!vinfo && !need_surface &&
422 eglGetConfigAttrib(eman->dpy, eman->conf, EGL_BUFFER_SIZE, &val)) {
423 if (val == 32)
424 val = 24;
425 vinfo_template.depth = val;
426 vinfo = XGetVisualInfo(eman->xdpy, VisualDepthMask, &vinfo_template, &num_vinfo);
427 }
428
429 if (!vinfo) {
430 printf("XGetVisualInfo() failed\n");
431 return EGL_FALSE;
432 }
433
434 root = DefaultRootWindow(eman->xdpy);
435 if (fullscreen) {
436 x = y = 0;
437 w = DisplayWidth(eman->xdpy, DefaultScreen(eman->xdpy));
438 h = DisplayHeight(eman->xdpy, DefaultScreen(eman->xdpy));
439 }
440
441 /* window attributes */
442 attrs.background_pixel = 0;
443 attrs.border_pixel = 0;
444 attrs.colormap = XCreateColormap(eman->xdpy, root, vinfo->visual, AllocNone);
445 attrs.event_mask = StructureNotifyMask | ExposureMask | KeyPressMask;
446 attrs.override_redirect = fullscreen;
447 mask = CWBackPixel | CWBorderPixel | CWColormap | CWEventMask | CWOverrideRedirect;
448
449 eman->xwin = XCreateWindow(eman->xdpy, root, x, y, w, h,
450 0, vinfo->depth, InputOutput,
451 vinfo->visual, mask, &attrs);
452 XFree(vinfo);
453
454 /* set hints and properties */
455 {
456 XSizeHints sizehints;
457 sizehints.x = x;
458 sizehints.y = y;
459 sizehints.width = w;
460 sizehints.height = h;
461 sizehints.flags = USSize | USPosition;
462 XSetNormalHints(eman->xdpy, eman->xwin, &sizehints);
463 XSetStandardProperties(eman->xdpy, eman->xwin, name, name,
464 None, (char **)NULL, 0, &sizehints);
465 }
466
467 if (need_surface) {
468 eman->win = eglCreateWindowSurface(eman->dpy, eman->conf,
469 eman->xwin, attrib_list);
470 if (eman->win == EGL_NO_SURFACE) {
471 printf("eglCreateWindowSurface() failed\n");
472 XDestroyWindow(eman->xdpy, eman->xwin);
473 eman->xwin = None;
474 return EGL_FALSE;
475 }
476 }
477
478 XMapWindow(eman->xdpy, eman->xwin);
479
480 return EGL_TRUE;
481 }
482
483 static EGLBoolean
484 egl_manager_create_pixmap(struct egl_manager *eman, EGLNativeWindowType xwin,
485 EGLBoolean need_surface, const EGLint *attrib_list)
486 {
487 XWindowAttributes attrs;
488
489 if (!XGetWindowAttributes(eman->xdpy, xwin, &attrs)) {
490 printf("XGetWindowAttributes() failed\n");
491 return EGL_FALSE;
492 }
493
494 eman->xpix = XCreatePixmap(eman->xdpy, xwin,
495 attrs.width, attrs.height, attrs.depth);
496
497 if (need_surface) {
498 eman->pix = eglCreatePixmapSurface(eman->dpy, eman->conf,
499 eman->xpix, attrib_list);
500 if (eman->pix == EGL_NO_SURFACE) {
501 printf("eglCreatePixmapSurface() failed\n");
502 XFreePixmap(eman->xdpy, eman->xpix);
503 eman->xpix = None;
504 return EGL_FALSE;
505 }
506 }
507
508 return EGL_TRUE;
509 }
510
511 static EGLBoolean
512 egl_manager_create_pbuffer(struct egl_manager *eman, const EGLint *attrib_list)
513 {
514 eman->pbuf = eglCreatePbufferSurface(eman->dpy, eman->conf, attrib_list);
515 if (eman->pbuf == EGL_NO_SURFACE) {
516 printf("eglCreatePbufferSurface() failed\n");
517 return EGL_FALSE;
518 }
519
520 return EGL_TRUE;
521 }
522
523 static void
524 egl_manager_destroy(struct egl_manager *eman)
525 {
526 eglMakeCurrent(eman->dpy, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
527 eglTerminate(eman->dpy);
528
529 if (eman->xwin != None)
530 XDestroyWindow(eman->xdpy, eman->xwin);
531 if (eman->xpix != None)
532 XFreePixmap(eman->xdpy, eman->xpix);
533
534 free(eman);
535 }
536
537 enum {
538 GEARS_WINDOW,
539 GEARS_PIXMAP,
540 GEARS_PIXMAP_TEXTURE,
541 GEARS_PBUFFER,
542 GEARS_PBUFFER_TEXTURE
543 };
544
545 static void
546 texture_gears(struct egl_manager *eman, int surface_type)
547 {
548 static const GLint verts[12] =
549 { -5, -6, -10, 5, -6, -10, -5, 4, 10, 5, 4, 10 };
550 static const GLint tex_coords[8] = { 0, 0, 1, 0, 0, 1, 1, 1 };
551
552 eglMakeCurrent(eman->dpy, eman->win, eman->win, eman->ctx);
553
554 glClearColor(0, 0, 0, 0);
555 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
556
557 glEnable(GL_TEXTURE_2D);
558 glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
559 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_R, GL_REPEAT);
560 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
561 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
562
563 glEnableClientState(GL_VERTEX_ARRAY);
564 glEnableClientState(GL_TEXTURE_COORD_ARRAY);
565 glVertexPointer(3, GL_INT, 0, verts);
566 glTexCoordPointer(2, GL_INT, 0, tex_coords);
567
568 if (surface_type == GEARS_PBUFFER_TEXTURE)
569 eglBindTexImage(eman->dpy, eman->pbuf, EGL_BACK_BUFFER);
570
571 glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
572
573 glDisableClientState(GL_VERTEX_ARRAY);
574 glDisableClientState(GL_COLOR_ARRAY);
575 glDisable(GL_TEXTURE_2D);
576
577 if (surface_type == GEARS_PBUFFER_TEXTURE)
578 eglReleaseTexImage(eman->dpy, eman->pbuf, EGL_BACK_BUFFER);
579
580 eglSwapBuffers(eman->dpy, eman->win);
581 }
582
583 static void
584 event_loop(struct egl_manager *eman, EGLint surface_type, EGLint w, EGLint h)
585 {
586 GC gc = XCreateGC(eman->xdpy, eman->xwin, 0, NULL);
587 EGLint orig_w = w, orig_h = h;
588
589 if (surface_type == EGL_PBUFFER_BIT)
590 printf("there will be no screen update if "
591 "eglCopyBuffers() is not implemented\n");
592
593 while (1) {
594 while (XPending(eman->xdpy) > 0) {
595 XEvent event;
596 XNextEvent(eman->xdpy, &event);
597 switch (event.type) {
598 case Expose:
599 /* we'll redraw below */
600 break;
601 case ConfigureNotify:
602 w = event.xconfigure.width;
603 h = event.xconfigure.height;
604 if (surface_type == EGL_WINDOW_BIT)
605 reshape(w, h);
606 break;
607 case KeyPress:
608 {
609 char buffer[10];
610 int r, code;
611 code = XLookupKeysym(&event.xkey, 0);
612 if (code == XK_Left) {
613 view_roty += 5.0;
614 }
615 else if (code == XK_Right) {
616 view_roty -= 5.0;
617 }
618 else if (code == XK_Up) {
619 view_rotx += 5.0;
620 }
621 else if (code == XK_Down) {
622 view_rotx -= 5.0;
623 }
624 else {
625 r = XLookupString(&event.xkey, buffer, sizeof(buffer),
626 NULL, NULL);
627 if (buffer[0] == 27) {
628 /* escape */
629 return;
630 }
631 }
632 }
633 }
634 }
635
636 {
637 static int frames = 0;
638 static double tRot0 = -1.0, tRate0 = -1.0;
639 double dt, t = current_time();
640 int x, y;
641 if (tRot0 < 0.0)
642 tRot0 = t;
643 dt = t - tRot0;
644 tRot0 = t;
645
646 /* advance rotation for next frame */
647 angle += 70.0 * dt; /* 70 degrees per second */
648 if (angle > 3600.0)
649 angle -= 3600.0;
650
651 switch (surface_type) {
652 case GEARS_PBUFFER:
653 case GEARS_PBUFFER_TEXTURE:
654 eglMakeCurrent(eman->dpy, eman->pbuf, eman->pbuf, eman->ctx);
655 break;
656
657 case GEARS_PIXMAP:
658 case GEARS_PIXMAP_TEXTURE:
659 eglMakeCurrent(eman->dpy, eman->pix, eman->pix, eman->ctx);
660 break;
661 }
662
663 draw();
664 switch (surface_type) {
665 case GEARS_WINDOW:
666 eglSwapBuffers(eman->dpy, eman->win);
667 break;
668 case GEARS_PBUFFER_TEXTURE:
669 case GEARS_PIXMAP_TEXTURE:
670 texture_gears(eman, surface_type);
671 break;
672 case GEARS_PBUFFER:
673 if (!eglCopyBuffers(eman->dpy, eman->pbuf, eman->xpix))
674 break;
675 eglWaitClient();
676 /* fall through */
677 case GEARS_PIXMAP:
678 eglWaitClient();
679 for (x = 0; x < w; x += orig_w) {
680 for (y = 0; y < h; y += orig_h) {
681 XCopyArea(eman->xdpy, eman->xpix, eman->xwin, gc,
682 0, 0, orig_w, orig_h, x, y);
683 }
684 }
685 break;
686 }
687
688 frames++;
689
690 if (tRate0 < 0.0)
691 tRate0 = t;
692 if (t - tRate0 >= 5.0) {
693 GLfloat seconds = t - tRate0;
694 GLfloat fps = frames / seconds;
695 printf("%d frames in %3.1f seconds = %6.3f FPS\n", frames, seconds,
696 fps);
697 tRate0 = t;
698 frames = 0;
699 }
700 }
701 }
702
703 XFreeGC(eman->xdpy, gc);
704 }
705
706
707 static void
708 usage(void)
709 {
710 printf("Usage:\n");
711 printf(" -display <displayname> set the display to run on\n");
712 printf(" -fullscreen run in fullscreen mode\n");
713 printf(" -info display OpenGL renderer info\n");
714 printf(" -pixmap use pixmap surface\n");
715 printf(" -pbuffer-copy use pbuffer surface and eglCopyBuffers\n");
716 printf(" -pbuffer-texture use pbuffer surface and eglBindTexImage\n");
717 }
718
719 static const char *names[] = {
720 "window", "pixmap", "pixmap_texture", "pbuffer", "pbuffer_texture"
721 };
722
723 int
724 main(int argc, char *argv[])
725 {
726 const int winWidth = 300, winHeight = 300;
727 Display *x_dpy;
728 char *dpyName = NULL;
729 struct egl_manager *eman;
730 EGLint attribs[] = {
731 EGL_SURFACE_TYPE, EGL_WINDOW_BIT, /* may be changed later */
732 EGL_RED_SIZE, 1,
733 EGL_GREEN_SIZE, 1,
734 EGL_BLUE_SIZE, 1,
735 EGL_DEPTH_SIZE, 1,
736 EGL_RENDERABLE_TYPE, EGL_OPENGL_BIT,
737 EGL_NONE
738 };
739 char win_title[] = "xeglgears (window/pixmap/pbuffer)";
740 EGLint surface_type = GEARS_WINDOW;
741 GLboolean printInfo = GL_FALSE;
742 GLboolean fullscreen = GL_FALSE;
743 EGLBoolean ret;
744 GLuint texture;
745 int i;
746
747 for (i = 1; i < argc; i++) {
748 if (strcmp(argv[i], "-display") == 0) {
749 dpyName = argv[i+1];
750 i++;
751 }
752 else if (strcmp(argv[i], "-info") == 0) {
753 printInfo = GL_TRUE;
754 }
755 else if (strcmp(argv[i], "-fullscreen") == 0) {
756 fullscreen = GL_TRUE;
757 }
758 else if (strcmp(argv[i], "-pixmap") == 0) {
759 surface_type = GEARS_PIXMAP;
760 attribs[1] = EGL_PIXMAP_BIT;
761 }
762 else if (strcmp(argv[i], "-pixmap-texture") == 0) {
763 surface_type = GEARS_PIXMAP_TEXTURE;
764 attribs[1] = EGL_PIXMAP_BIT;
765 }
766 else if (strcmp(argv[i], "-pbuffer") == 0) {
767 surface_type = GEARS_PBUFFER;
768 attribs[1] = EGL_PBUFFER_BIT;
769 }
770 else if (strcmp(argv[i], "-pbuffer-texture") == 0) {
771 surface_type = GEARS_PBUFFER_TEXTURE;
772 attribs[1] = EGL_PBUFFER_BIT;
773 }
774 else {
775 usage();
776 return -1;
777 }
778 }
779
780 x_dpy = XOpenDisplay(dpyName);
781 if (!x_dpy) {
782 printf("Error: couldn't open display %s\n",
783 dpyName ? dpyName : getenv("DISPLAY"));
784 return -1;
785 }
786
787 eglBindAPI(EGL_OPENGL_API);
788
789 eman = egl_manager_new(x_dpy, attribs, printInfo);
790 if (!eman) {
791 XCloseDisplay(x_dpy);
792 return -1;
793 }
794
795 snprintf(win_title, sizeof(win_title),
796 "xeglgears (%s)", names[surface_type]);
797
798 /* create surface(s) */
799 switch (surface_type) {
800 case GEARS_WINDOW:
801 ret = egl_manager_create_window(eman, win_title, winWidth, winHeight,
802 EGL_TRUE, fullscreen, NULL);
803 if (ret)
804 ret = eglMakeCurrent(eman->dpy, eman->win, eman->win, eman->ctx);
805 break;
806 case GEARS_PIXMAP:
807 case GEARS_PIXMAP_TEXTURE:
808 ret = (egl_manager_create_window(eman, win_title, winWidth, winHeight,
809 EGL_TRUE, fullscreen, NULL) &&
810 egl_manager_create_pixmap(eman, eman->xwin,
811 EGL_TRUE, NULL));
812 if (surface_type == GEARS_PIXMAP_TEXTURE)
813 eman->image = eglCreateImageKHR (eman->dpy, eman->ctx,
814 EGL_NATIVE_PIXMAP_KHR,
815 (EGLClientBuffer) eman->xpix, NULL);
816 if (ret)
817 ret = eglMakeCurrent(eman->dpy, eman->pix, eman->pix, eman->ctx);
818 break;
819 case GEARS_PBUFFER:
820 case GEARS_PBUFFER_TEXTURE:
821 {
822 EGLint pbuf_attribs[] = {
823 EGL_WIDTH, winWidth,
824 EGL_HEIGHT, winHeight,
825 EGL_TEXTURE_FORMAT, EGL_TEXTURE_RGB,
826 EGL_TEXTURE_TARGET, EGL_TEXTURE_2D,
827 EGL_NONE
828 };
829 ret = (egl_manager_create_window(eman, win_title, winWidth, winHeight,
830 EGL_TRUE, fullscreen, NULL) &&
831 egl_manager_create_pixmap(eman, eman->xwin,
832 EGL_TRUE, NULL) &&
833 egl_manager_create_pbuffer(eman, pbuf_attribs));
834 if (ret)
835 ret = eglMakeCurrent(eman->dpy, eman->pbuf, eman->pbuf, eman->ctx);
836 }
837 break;
838 default:
839 ret = EGL_FALSE;
840 break;
841 }
842
843 switch (surface_type) {
844 case GEARS_PIXMAP_TEXTURE:
845 glGenTextures(1, &texture);
846 glBindTexture(GL_TEXTURE_2D, texture);
847 glEGLImageTargetTexture2DOES(GL_TEXTURE_2D, eman->image);
848 break;
849 case GEARS_PBUFFER_TEXTURE:
850 glGenTextures(1, &texture);
851 glBindTexture(GL_TEXTURE_2D, texture);
852 break;
853 }
854
855 if (!ret) {
856 egl_manager_destroy(eman);
857 XCloseDisplay(x_dpy);
858 return -1;
859 }
860
861 if (printInfo) {
862 printf("GL_RENDERER = %s\n", (char *) glGetString(GL_RENDERER));
863 printf("GL_VERSION = %s\n", (char *) glGetString(GL_VERSION));
864 printf("GL_VENDOR = %s\n", (char *) glGetString(GL_VENDOR));
865 }
866
867 init();
868
869 /* Set initial projection/viewing transformation.
870 * We can't be sure we'll get a ConfigureNotify event when the window
871 * first appears.
872 */
873 reshape(winWidth, winHeight);
874
875 event_loop(eman, surface_type, winWidth, winHeight);
876
877 glDeleteLists(gear1, 1);
878 glDeleteLists(gear2, 1);
879 glDeleteLists(gear3, 1);
880
881 egl_manager_destroy(eman);
882 XCloseDisplay(x_dpy);
883
884 return 0;
885 }