2 * Mesa 3-D graphics library
5 * Copyright (C) 2010 LunarG Inc.
7 * Permission is hereby granted, free of charge, to any person obtaining a
8 * copy of this software and associated documentation files (the "Software"),
9 * to deal in the Software without restriction, including without limitation
10 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
11 * and/or sell copies of the Software, and to permit persons to whom the
12 * Software is furnished to do so, subject to the following conditions:
14 * The above copyright notice and this permission notice shall be included
15 * in all copies or substantial portions of the Software.
17 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
18 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
20 * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
21 * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
22 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
25 * Chia-I Wu <olv@lunarg.com>
29 * This demo uses EGL_KHR_image_pixmap and GL_OES_EGL_image to demonstrate
30 * texture-from-pixmap.
37 #include <unistd.h> /* for usleep */
38 #include <sys/time.h> /* for gettimeofday */
40 #include <X11/Xutil.h>
41 #include <X11/keysym.h>
43 #include <GLES/glext.h>
45 #include <EGL/eglext.h>
52 unsigned int width
, height
, depth
;
64 PFNEGLCREATEIMAGEKHRPROC eglCreateImageKHR
;
65 PFNEGLDESTROYIMAGEKHRPROC eglDestroyImageKHR
;
66 PFNGLEGLIMAGETARGETTEXTURE2DOESPROC glEGLImageTargetTexture2DOES
;
74 unsigned long next_frame
; /* in ms */
91 const GLfloat verts
[4][2] = {
97 const GLfloat texcoords
[4][2] = {
103 const GLfloat faces
[6][4] = {
113 glClear(GL_COLOR_BUFFER_BIT
| GL_DEPTH_BUFFER_BIT
);
115 glVertexPointer(2, GL_FLOAT
, 0, verts
);
116 glTexCoordPointer(2, GL_FLOAT
, 0, texcoords
);
118 glEnableClientState(GL_VERTEX_ARRAY
);
119 glEnableClientState(GL_TEXTURE_COORD_ARRAY
);
121 for (i
= 0; i
< 6; i
++) {
123 glRotatef(faces
[i
][0], faces
[i
][1], faces
[i
][2], faces
[i
][3]);
124 glTranslatef(0, 0, 1.0);
125 glDrawArrays(GL_TRIANGLE_FAN
, 0, 4);
129 glDisableClientState(GL_VERTEX_ARRAY
);
130 glDisableClientState(GL_TEXTURE_COORD_ARRAY
);
134 gl_reshape(int width
, int height
)
136 GLfloat ar
= (GLfloat
) width
/ (GLfloat
) height
;
138 glViewport(0, 0, width
, height
);
140 glMatrixMode(GL_PROJECTION
);
142 glFrustumf(-ar
, ar
, -1, 1, 5.0, 60.0);
144 glMatrixMode(GL_MODELVIEW
);
146 glTranslatef(0.0, 0.0, -10.0);
150 app_redraw(struct app_data
*data
)
152 /* pixmap has changed */
153 if (data
->reshape
|| data
->paint
.active
) {
154 eglWaitNative(EGL_CORE_NATIVE_ENGINE
);
157 data
->glEGLImageTargetTexture2DOES(GL_TEXTURE_2D
,
158 (GLeglImageOES
) data
->img
);
162 XCopyArea(data
->xdpy
, data
->pix
, data
->canvas
, data
->fg
,
163 0, 0, data
->width
, data
->height
, 0, 0);
166 glRotatef(data
->animate
.view_rotx
, 1, 0, 0);
167 glRotatef(data
->animate
.view_roty
, 0, 1, 0);
168 glRotatef(data
->animate
.view_rotz
, 0, 0, 1);
172 eglSwapBuffers(data
->dpy
, data
->surf
);
176 app_reshape(struct app_data
*data
)
178 const EGLint img_attribs
[] = {
179 EGL_IMAGE_PRESERVED_KHR
, EGL_TRUE
,
183 XResizeWindow(data
->xdpy
, data
->cube
, data
->width
, data
->height
);
184 XMoveWindow(data
->xdpy
, data
->cube
, data
->width
, 0);
187 data
->eglDestroyImageKHR(data
->dpy
, data
->img
);
189 XFreePixmap(data
->xdpy
, data
->pix
);
191 data
->pix
= XCreatePixmap(data
->xdpy
, data
->canvas
, data
->width
, data
->height
, data
->depth
);
192 XFillRectangle(data
->xdpy
, data
->pix
, data
->bg
, 0, 0, data
->width
, data
->height
);
194 data
->img
= data
->eglCreateImageKHR(data
->dpy
, EGL_NO_CONTEXT
,
195 EGL_NATIVE_PIXMAP_KHR
, (EGLClientBuffer
) data
->pix
, img_attribs
);
197 gl_reshape(data
->width
, data
->height
);
201 app_toggle_animate(struct app_data
*data
)
203 data
->animate
.active
= !data
->animate
.active
;
205 if (data
->animate
.active
) {
208 gettimeofday(&tv
, NULL
);
209 data
->animate
.next_frame
= tv
.tv_sec
* 1000 + tv
.tv_usec
/ 1000;
214 app_next_event(struct app_data
*data
)
218 data
->reshape
= False
;
219 data
->redraw
= False
;
220 data
->paint
.active
= False
;
222 if (data
->animate
.active
) {
226 gettimeofday(&tv
, NULL
);
227 now
= tv
.tv_sec
* 1000 + tv
.tv_usec
/ 1000;
229 /* wait for next frame */
230 if (!XPending(data
->xdpy
) && now
< data
->animate
.next_frame
) {
231 usleep((data
->animate
.next_frame
- now
) * 1000);
232 gettimeofday(&tv
, NULL
);
233 now
= tv
.tv_sec
* 1000 + tv
.tv_usec
/ 1000;
236 while (now
>= data
->animate
.next_frame
) {
237 data
->animate
.view_rotx
+= 1.0;
238 data
->animate
.view_roty
+= 2.0;
239 data
->animate
.view_rotz
+= 1.5;
242 data
->animate
.next_frame
+= 1000 / 30;
245 /* check again in case there were events when sleeping */
246 if (!XPending(data
->xdpy
)) {
252 XNextEvent(data
->xdpy
, &event
);
254 switch (event
.type
) {
255 case ConfigureNotify
:
256 data
->width
= event
.xconfigure
.width
/ 2;
257 data
->height
= event
.xconfigure
.height
;
258 data
->reshape
= True
;
267 code
= XLookupKeysym(&event
.xkey
, 0);
270 app_toggle_animate(data
);
281 data
->paint
.x1
= data
->paint
.x2
= event
.xbutton
.x
;
282 data
->paint
.y1
= data
->paint
.y2
= event
.xbutton
.y
;
285 data
->paint
.active
= False
;
288 data
->paint
.x1
= data
->paint
.x2
;
289 data
->paint
.y1
= data
->paint
.y2
;
290 data
->paint
.x2
= event
.xmotion
.x
;
291 data
->paint
.y2
= event
.xmotion
.y
;
292 data
->paint
.active
= True
;
298 if (data
->paint
.active
|| data
->reshape
)
303 app_init_gl(struct app_data
*data
)
305 glClearColor(0.1, 0.1, 0.3, 0.0);
306 glColor4f(1.0, 1.0, 1.0, 1.0);
308 glGenTextures(1, &data
->texture
);
310 glBindTexture(GL_TEXTURE_2D
, data
->texture
);
311 glTexParameteri(GL_TEXTURE_2D
, GL_TEXTURE_MIN_FILTER
, GL_LINEAR
);
312 glTexParameteri(GL_TEXTURE_2D
, GL_TEXTURE_MAG_FILTER
, GL_LINEAR
);
314 glEnable(GL_TEXTURE_2D
);
315 glEnable(GL_DEPTH_TEST
);
319 app_init_exts(struct app_data
*data
)
323 exts
= eglQueryString(data
->dpy
, EGL_EXTENSIONS
);
324 data
->eglCreateImageKHR
=
325 (PFNEGLCREATEIMAGEKHRPROC
) eglGetProcAddress("eglCreateImageKHR");
326 data
->eglDestroyImageKHR
=
327 (PFNEGLDESTROYIMAGEKHRPROC
) eglGetProcAddress("eglDestroyImageKHR");
328 if (!exts
|| !strstr(exts
, "EGL_KHR_image_pixmap") ||
329 !data
->eglCreateImageKHR
|| !data
->eglDestroyImageKHR
) {
330 printf("EGL does not support EGL_KHR_image_pixmap\n");
334 exts
= (const char *) glGetString(GL_EXTENSIONS
);
335 exts
= "GL_OES_EGL_image"; /* XXX */
336 data
->glEGLImageTargetTexture2DOES
= (PFNGLEGLIMAGETARGETTEXTURE2DOESPROC
)
337 eglGetProcAddress("glEGLImageTargetTexture2DOES");
338 if (!exts
|| !strstr(exts
, "GL_OES_EGL_image") ||
339 !data
->glEGLImageTargetTexture2DOES
) {
340 printf("OpenGL ES does not support GL_OES_EGL_image\n");
348 app_run(struct app_data
*data
)
354 if (!eglMakeCurrent(data
->dpy
, data
->surf
, data
->surf
, data
->ctx
))
357 if (!app_init_exts(data
))
360 printf("Draw something on the left with the mouse!\n");
364 if (!XGetGeometry(data
->xdpy
, data
->canvas
, &root
, &x
, &y
,
365 &data
->width
, &data
->height
, &border
, &data
->depth
))
371 XMapWindow(data
->xdpy
, data
->canvas
);
372 XMapWindow(data
->xdpy
, data
->cube
);
374 app_toggle_animate(data
);
378 app_next_event(data
);
382 if (data
->paint
.active
) {
383 XDrawLine(data
->xdpy
, data
->pix
, data
->fg
,
384 data
->paint
.x1
, data
->paint
.y1
,
385 data
->paint
.x2
, data
->paint
.y2
);
392 eglMakeCurrent(data
->dpy
, EGL_NO_SURFACE
, EGL_NO_SURFACE
, EGL_NO_CONTEXT
);
396 make_x_window(struct app_data
*data
, const char *name
,
397 int x
, int y
, int width
, int height
)
399 static const EGLint attribs
[] = {
404 EGL_RENDERABLE_TYPE
, EGL_OPENGL_ES_BIT
,
407 static const EGLint ctx_attribs
[] = {
408 EGL_CONTEXT_CLIENT_VERSION
, 1,
412 XSetWindowAttributes attr
;
416 XVisualInfo
*visInfo
, visTemplate
;
422 scrnum
= DefaultScreen( data
->xdpy
);
423 root
= RootWindow( data
->xdpy
, scrnum
);
425 if (!eglChooseConfig( data
->dpy
, attribs
, &config
, 1, &num_configs
)) {
426 printf("Error: couldn't get an EGL visual config\n");
431 assert(num_configs
> 0);
433 if (!eglGetConfigAttrib(data
->dpy
, config
, EGL_NATIVE_VISUAL_ID
, &vid
)) {
434 printf("Error: eglGetConfigAttrib() failed\n");
438 /* The X window visual must match the EGL config */
439 visTemplate
.visualid
= vid
;
440 visInfo
= XGetVisualInfo(data
->xdpy
, VisualIDMask
, &visTemplate
, &num_visuals
);
442 printf("Error: couldn't get X visual\n");
446 /* window attributes */
447 attr
.background_pixel
= 0;
448 attr
.border_pixel
= 0;
449 attr
.colormap
= XCreateColormap( data
->xdpy
, root
, visInfo
->visual
, AllocNone
);
450 attr
.event_mask
= StructureNotifyMask
| ExposureMask
|
451 KeyPressMask
| ButtonPressMask
| ButtonMotionMask
;
452 mask
= CWBackPixel
| CWBorderPixel
| CWColormap
| CWEventMask
;
454 win
= XCreateWindow( data
->xdpy
, root
, 0, 0, width
* 2, height
,
455 0, visInfo
->depth
, InputOutput
,
456 visInfo
->visual
, mask
, &attr
);
458 /* set hints and properties */
460 XSizeHints sizehints
;
463 sizehints
.width
= width
;
464 sizehints
.height
= height
;
465 sizehints
.flags
= USSize
| USPosition
;
466 XSetNormalHints(data
->xdpy
, win
, &sizehints
);
467 XSetStandardProperties(data
->xdpy
, win
, name
, name
,
468 None
, (char **)NULL
, 0, &sizehints
);
473 attr
.event_mask
= 0x0;
474 win
= XCreateWindow( data
->xdpy
, win
, width
, 0, width
, height
,
475 0, visInfo
->depth
, InputOutput
,
476 visInfo
->visual
, mask
, &attr
);
479 eglBindAPI(EGL_OPENGL_ES_API
);
481 data
->ctx
= eglCreateContext(data
->dpy
, config
, EGL_NO_CONTEXT
, ctx_attribs
);
483 printf("Error: eglCreateContext failed\n");
487 data
->surf
= eglCreateWindowSurface(data
->dpy
, config
, data
->cube
, NULL
);
489 printf("Error: eglCreateWindowSurface failed\n");
495 return (data
->canvas
&& data
->cube
&& data
->ctx
&& data
->surf
);
499 app_fini(struct app_data
*data
)
502 data
->eglDestroyImageKHR(data
->dpy
, data
->img
);
504 XFreePixmap(data
->xdpy
, data
->pix
);
507 XFreeGC(data
->xdpy
, data
->fg
);
509 XFreeGC(data
->xdpy
, data
->bg
);
512 eglDestroySurface(data
->dpy
, data
->surf
);
514 eglDestroyContext(data
->dpy
, data
->ctx
);
517 XDestroyWindow(data
->xdpy
, data
->cube
);
519 XDestroyWindow(data
->xdpy
, data
->canvas
);
522 eglTerminate(data
->dpy
);
524 XCloseDisplay(data
->xdpy
);
528 app_init(struct app_data
*data
, int argc
, char **argv
)
532 memset(data
, 0, sizeof(*data
));
534 data
->xdpy
= XOpenDisplay(NULL
);
538 data
->dpy
= eglGetDisplay(data
->xdpy
);
539 if (!data
->dpy
|| !eglInitialize(data
->dpy
, NULL
, NULL
))
542 if (!make_x_window(data
, "EGLImage TFP", 0, 0, 300, 300))
545 gc_vals
.function
= GXcopy
;
546 gc_vals
.foreground
= WhitePixel(data
->xdpy
, DefaultScreen(data
->xdpy
));
547 gc_vals
.line_width
= 3;
548 gc_vals
.line_style
= LineSolid
;
549 gc_vals
.fill_style
= FillSolid
;
551 data
->fg
= XCreateGC(data
->xdpy
, data
->canvas
,
552 GCFunction
| GCForeground
| GCLineWidth
| GCLineStyle
| GCFillStyle
,
554 gc_vals
.foreground
= BlackPixel(data
->xdpy
, DefaultScreen(data
->xdpy
));
555 data
->bg
= XCreateGC(data
->xdpy
, data
->canvas
,
556 GCFunction
| GCForeground
| GCLineWidth
| GCLineStyle
| GCFillStyle
,
558 if (!data
->fg
|| !data
->bg
)
569 main(int argc
, char **argv
)
571 struct app_data data
;
573 if (app_init(&data
, argc
, argv
)) {