bindtex.c revision 32001f49
1/*
2 * Simple demo for eglBindTexImage.  Based on xegl_tri.c by
3 *
4 * Copyright (C) 2008  Brian Paul   All Rights Reserved.
5 *
6 * Permission is hereby granted, free of charge, to any person obtaining a
7 * copy of this software and associated documentation files (the "Software"),
8 * to deal in the Software without restriction, including without limitation
9 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
10 * and/or sell copies of the Software, and to permit persons to whom the
11 * Software is furnished to do so, subject to the following conditions:
12 *
13 * The above copyright notice and this permission notice shall be included
14 * in all copies or substantial portions of the Software.
15 *
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
17 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
19 * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
20 * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
21 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
22 */
23
24/*
25 * The spec says that eglBindTexImage supports only OpenGL ES context, but this
26 * demo uses OpenGL context.  Keep in mind that this is non-standard.
27 */
28
29#include <math.h>
30#include <stdlib.h>
31#include <stdio.h>
32#include <string.h>
33#include <X11/Xlib.h>
34#include <X11/Xutil.h>
35#include <X11/keysym.h>
36#include <GLES/gl.h>
37#include <EGL/egl.h>
38
39static EGLDisplay dpy;
40static EGLContext ctx_win, ctx_pbuf;
41static EGLSurface surf_win, surf_pbuf;
42static GLuint tex_pbuf;
43
44static GLfloat view_rotx = 0.0, view_roty = 0.0, view_rotz = 0.0;
45static GLboolean blend = GL_TRUE;
46static GLuint color_flow;
47
48static void
49make_pbuffer(int width, int height)
50{
51   static const EGLint config_attribs[] = {
52      EGL_RED_SIZE, 8,
53      EGL_GREEN_SIZE, 8,
54      EGL_BLUE_SIZE, 8,
55      EGL_BIND_TO_TEXTURE_RGB, EGL_TRUE,
56      EGL_NONE
57   };
58   EGLint pbuf_attribs[] = {
59      EGL_WIDTH, width,
60      EGL_HEIGHT, height,
61      EGL_TEXTURE_FORMAT, EGL_TEXTURE_RGB,
62      EGL_TEXTURE_TARGET, EGL_TEXTURE_2D,
63      EGL_NONE
64   };
65   EGLConfig config;
66   EGLint num_configs;
67
68   if (!eglChooseConfig(dpy, config_attribs, &config, 1, &num_configs) ||
69       !num_configs) {
70      printf("Error: couldn't get an EGL visual config for pbuffer\n");
71      exit(1);
72   }
73
74   ctx_pbuf = eglCreateContext(dpy, config, EGL_NO_CONTEXT, NULL );
75   surf_pbuf = eglCreatePbufferSurface(dpy, config, pbuf_attribs);
76   if (surf_pbuf == EGL_NO_SURFACE) {
77      printf("failed to allocate pbuffer\n");
78      exit(1);
79   }
80}
81
82static void
83use_pbuffer(void)
84{
85   static int initialized;
86
87   eglMakeCurrent(dpy, surf_pbuf, surf_pbuf, ctx_pbuf);
88   if (!initialized) {
89      EGLint width, height;
90      GLfloat ar;
91
92      initialized = 1;
93
94      eglQuerySurface(dpy, surf_pbuf, EGL_WIDTH, &width);
95      eglQuerySurface(dpy, surf_pbuf, EGL_WIDTH, &height);
96      ar = (GLfloat) width / (GLfloat) height;
97
98      glViewport(0, 0, (GLint) width, (GLint) height);
99
100      glMatrixMode(GL_PROJECTION);
101      glLoadIdentity();
102      glFrustumf(-ar, ar, -1, 1, 1.0, 10.0);
103
104      glMatrixMode(GL_MODELVIEW);
105      glLoadIdentity();
106
107      /* y-inverted */
108      glScalef(1.0, -1.0, 1.0);
109
110      glTranslatef(0.0, 0.0, -5.0);
111
112      glClearColor(0.2, 0.2, 0.2, 0.0);
113
114      glGenTextures(1, &tex_pbuf);
115   }
116}
117
118static void
119make_window(Display *x_dpy, const char *name,
120            int x, int y, int width, int height,
121            Window *winRet)
122{
123   static const EGLint attribs[] = {
124      EGL_RED_SIZE, 8,
125      EGL_GREEN_SIZE, 8,
126      EGL_BLUE_SIZE, 8,
127      EGL_ALPHA_SIZE, 8,
128      EGL_DEPTH_SIZE, 8,
129      EGL_NONE
130   };
131
132   int scrnum;
133   XSetWindowAttributes attr;
134   unsigned long mask;
135   Window root;
136   Window win;
137   XVisualInfo *visInfo, visTemplate;
138   int num_visuals;
139   EGLConfig config;
140   EGLint num_configs, vid;
141
142   scrnum = DefaultScreen( x_dpy );
143   root = RootWindow( x_dpy, scrnum );
144
145   if (!eglChooseConfig(dpy, attribs, &config, 1, &num_configs) ||
146       !num_configs) {
147      printf("Error: couldn't get an EGL visual config\n");
148      exit(1);
149   }
150
151   if (!eglGetConfigAttrib(dpy, config, EGL_NATIVE_VISUAL_ID, &vid)) {
152      printf("Error: eglGetConfigAttrib() failed\n");
153      exit(1);
154   }
155
156   /* The X window visual must match the EGL config */
157   visTemplate.visualid = vid;
158   visInfo = XGetVisualInfo(x_dpy, VisualIDMask, &visTemplate, &num_visuals);
159   if (!visInfo) {
160      printf("Error: couldn't get X visual\n");
161      exit(1);
162   }
163
164   /* window attributes */
165   attr.background_pixel = 0;
166   attr.border_pixel = 0;
167   attr.colormap = XCreateColormap( x_dpy, root, visInfo->visual, AllocNone);
168   attr.event_mask = StructureNotifyMask | ExposureMask | KeyPressMask;
169   attr.override_redirect = 0;
170   mask = CWBackPixel | CWBorderPixel | CWColormap | CWEventMask | CWOverrideRedirect;
171
172   win = XCreateWindow( x_dpy, root, 0, 0, width, height,
173		        0, visInfo->depth, InputOutput,
174		        visInfo->visual, mask, &attr );
175
176   /* set hints and properties */
177   {
178      XSizeHints sizehints;
179      sizehints.x = x;
180      sizehints.y = y;
181      sizehints.width  = width;
182      sizehints.height = height;
183      sizehints.flags = USSize | USPosition;
184      XSetNormalHints(x_dpy, win, &sizehints);
185      XSetStandardProperties(x_dpy, win, name, name,
186                              None, (char **)NULL, 0, &sizehints);
187   }
188
189   ctx_win = eglCreateContext(dpy, config, EGL_NO_CONTEXT, NULL );
190   if (!ctx_win) {
191      printf("Error: eglCreateContext failed\n");
192      exit(1);
193   }
194
195   surf_win = eglCreateWindowSurface(dpy, config, win, NULL);
196
197   XFree(visInfo);
198
199   *winRet = win;
200}
201
202static void
203use_window(void)
204{
205   static int initialized;
206
207   eglMakeCurrent(dpy, surf_win, surf_win, ctx_win);
208   if (!initialized) {
209      initialized = 1;
210      glEnable(GL_TEXTURE_2D);
211      glBindTexture(GL_TEXTURE_2D, tex_pbuf);
212      glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
213
214      glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
215   }
216}
217
218static void
219draw_triangle(void)
220{
221   static const GLfloat verts[3][2] = {
222      { -3, -3 },
223      {  3, -3 },
224      {  0,  3 }
225   };
226   GLfloat colors[3][4] = {
227      { 1, 0, 0, 1 },
228      { 0, 1, 0, 1 },
229      { 0, 0, 1, 1 }
230   };
231   GLint i;
232
233   /* flow the color */
234   for (i = 0; i < 3; i++) {
235      GLint first = (i + color_flow / 256) % 3;
236      GLint second = (first + 1) % 3;
237      GLint third = (second + 1) % 3;
238      GLfloat c = (color_flow % 256) / 256.0f;
239
240      c = c * c * c;
241      colors[i][first] = 1.0f - c;
242      colors[i][second] = c;
243      colors[i][third] = 0.0f;
244   }
245
246   glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
247
248   glVertexPointer(2, GL_FLOAT, 0, verts);
249   glColorPointer(4, GL_FLOAT, 0, colors);
250   glEnableClientState(GL_VERTEX_ARRAY);
251   glEnableClientState(GL_COLOR_ARRAY);
252
253   glDrawArrays(GL_TRIANGLES, 0, 3);
254
255   glDisableClientState(GL_VERTEX_ARRAY);
256   glDisableClientState(GL_COLOR_ARRAY);
257}
258
259static void
260draw_textured_cube(void)
261{
262   static const GLfloat verts[][2] = {
263      { -4, -4 },
264      {  4, -4 },
265      {  4,  4 },
266      { -4,  4 }
267   };
268   static const GLfloat colors[][4] = {
269      { 1, 1, 1, 0.5 },
270      { 1, 1, 1, 0.5 },
271      { 1, 1, 1, 0.5 },
272      { 1, 1, 1, 0.5 }
273   };
274   static const GLfloat texs[][2] = {
275      { 0, 0 },
276      { 1, 0 },
277      { 1, 1 },
278      { 0, 1 }
279   };
280   static const GLfloat xforms[6][4] = {
281      {   0, 0, 1, 0 },
282      {  90, 0, 1, 0 },
283      { 180, 0, 1, 0 },
284      { 270, 0, 1, 0 },
285      {  90, 1, 0, 0 },
286      { -90, 1, 0, 0 }
287   };
288   GLint i;
289
290   glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
291
292   if (blend) {
293      glDisable(GL_DEPTH_TEST);
294      glEnable(GL_BLEND);
295   } else {
296      glEnable(GL_DEPTH_TEST);
297      glDisable(GL_BLEND);
298   }
299
300   glVertexPointer(2, GL_FLOAT, 0, verts);
301   glColorPointer(4, GL_FLOAT, 0, colors);
302   glTexCoordPointer(2, GL_FLOAT, 0, texs);
303
304   glEnableClientState(GL_VERTEX_ARRAY);
305   glEnableClientState(GL_COLOR_ARRAY);
306   glEnableClientState(GL_TEXTURE_COORD_ARRAY);
307
308   for (i = 0; i < 6; i++) {
309      glPushMatrix();
310      glRotatef(xforms[i][0], xforms[i][1], xforms[i][2], xforms[i][3]);
311      glTranslatef(0, 0, 4.1);
312      glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
313      glPopMatrix();
314   }
315
316   glDisableClientState(GL_VERTEX_ARRAY);
317   glDisableClientState(GL_COLOR_ARRAY);
318   glDisableClientState(GL_TEXTURE_COORD_ARRAY);
319}
320
321static void
322draw(void)
323{
324   use_pbuffer();
325   draw_triangle();
326
327   use_window();
328
329   eglBindTexImage(dpy, surf_pbuf, EGL_BACK_BUFFER);
330
331   glPushMatrix();
332   glRotatef(view_rotx, 1, 0, 0);
333   glRotatef(view_roty, 0, 1, 0);
334   glRotatef(view_rotz, 0, 0, 1);
335
336   draw_textured_cube();
337
338   glPopMatrix();
339
340   eglReleaseTexImage(dpy, surf_pbuf, EGL_BACK_BUFFER);
341}
342
343/* new window size or exposure */
344static void
345reshape(int width, int height)
346{
347   GLfloat ar = (GLfloat) width / (GLfloat) height;
348
349   use_window();
350
351   glViewport(0, 0, (GLint) width, (GLint) height);
352
353   glMatrixMode(GL_PROJECTION);
354   glLoadIdentity();
355   glFrustumf(-ar, ar, -1, 1, 5.0, 60.0);
356
357   glMatrixMode(GL_MODELVIEW);
358   glLoadIdentity();
359   glTranslatef(0.0, 0.0, -40.0);
360}
361
362static void
363event_loop(Display *x_dpy, Window win)
364{
365   while (1) {
366      int redraw = 1;
367
368      if (XPending(x_dpy) > 0) {
369         XEvent event;
370         XNextEvent(x_dpy, &event);
371
372         switch (event.type) {
373         case Expose:
374            redraw = 1;
375            break;
376         case ConfigureNotify:
377            reshape(event.xconfigure.width, event.xconfigure.height);
378            break;
379         case KeyPress:
380            {
381               char buffer[10];
382               int r, code;
383               code = XLookupKeysym(&event.xkey, 0);
384               if (code == XK_Left) {
385                  view_roty += 5.0;
386               }
387               else if (code == XK_Right) {
388                  view_roty -= 5.0;
389               }
390               else if (code == XK_Up) {
391                  view_rotx += 5.0;
392               }
393               else if (code == XK_Down) {
394                  view_rotx -= 5.0;
395               }
396               else if (code == XK_b) {
397                  blend = !blend;
398               }
399               else {
400                  r = XLookupString(&event.xkey, buffer, sizeof(buffer),
401                        NULL, NULL);
402                  if (buffer[0] == 27) {
403                     /* escape */
404                     return;
405                  }
406               }
407            }
408            redraw = 1;
409            break;
410         default:
411            ; /*no-op*/
412         }
413      }
414
415      if (redraw) {
416         view_rotx += 1.0;
417         view_roty += 2.0;
418         view_rotz += 1.5;
419         color_flow += 20;
420         draw();
421         eglSwapBuffers(dpy, surf_win);
422      }
423   }
424}
425
426int
427main(int argc, char *argv[])
428{
429   const int winWidth = 300, winHeight = 300;
430   Display *x_dpy;
431   Window win;
432   char *dpyName = NULL;
433   EGLint egl_major, egl_minor;
434   const char *s;
435
436   x_dpy = XOpenDisplay(dpyName);
437   if (!x_dpy) {
438      printf("Error: couldn't open display %s\n",
439	     dpyName ? dpyName : getenv("DISPLAY"));
440      return -1;
441   }
442
443   dpy = eglGetDisplay(x_dpy);
444   if (!dpy) {
445      printf("Error: eglGetDisplay() failed\n");
446      return -1;
447   }
448
449   if (!eglInitialize(dpy, &egl_major, &egl_minor)) {
450      printf("Error: eglInitialize() failed\n");
451      return -1;
452   }
453
454   s = eglQueryString(dpy, EGL_VERSION);
455   printf("EGL_VERSION = %s\n", s);
456
457   make_window(x_dpy, "color flow", 0, 0, winWidth, winHeight, &win);
458   make_pbuffer(winWidth, winHeight);
459
460   XMapWindow(x_dpy, win);
461
462   reshape(winWidth, winHeight);
463   event_loop(x_dpy, win);
464
465   glDeleteTextures(1, &tex_pbuf);
466
467   eglMakeCurrent(dpy, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
468   eglTerminate(dpy);
469
470   XDestroyWindow(x_dpy, win);
471   XCloseDisplay(x_dpy);
472
473   return 0;
474}
475