132001f49Smrg/*
232001f49Smrg * Copyright (C) 2008  Brian Paul   All Rights Reserved.
332001f49Smrg *
432001f49Smrg * Permission is hereby granted, free of charge, to any person obtaining a
532001f49Smrg * copy of this software and associated documentation files (the "Software"),
632001f49Smrg * to deal in the Software without restriction, including without limitation
732001f49Smrg * the rights to use, copy, modify, merge, publish, distribute, sublicense,
832001f49Smrg * and/or sell copies of the Software, and to permit persons to whom the
932001f49Smrg * Software is furnished to do so, subject to the following conditions:
1032001f49Smrg *
1132001f49Smrg * The above copyright notice and this permission notice shall be included
1232001f49Smrg * in all copies or substantial portions of the Software.
1332001f49Smrg *
1432001f49Smrg * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
1532001f49Smrg * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
1632001f49Smrg * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
1732001f49Smrg * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
1832001f49Smrg * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
1932001f49Smrg * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
2032001f49Smrg */
2132001f49Smrg
2232001f49Smrg/*
2332001f49Smrg * Test drawing to two windows.
2432001f49Smrg * Brian Paul
2532001f49Smrg * August 2008
2632001f49Smrg */
2732001f49Smrg
2832001f49Smrg
2932001f49Smrg#include <assert.h>
3032001f49Smrg#include <math.h>
3132001f49Smrg#include <stdlib.h>
3232001f49Smrg#include <stdio.h>
3332001f49Smrg#include <string.h>
3432001f49Smrg#include <X11/Xlib.h>
3532001f49Smrg#include <X11/Xutil.h>
3632001f49Smrg#include <X11/keysym.h>
3732001f49Smrg#include <GLES/gl.h>
3832001f49Smrg#include <GLES/glext.h>
3932001f49Smrg#include <EGL/egl.h>
4032001f49Smrg
4132001f49Smrg
4232001f49Smrgstatic int WinWidth[2] = {150, 300}, WinHeight[2] = {150, 300};
4332001f49Smrg
4432001f49Smrg
4532001f49Smrgstatic GLfloat view_rotx = 0.0, view_roty = 0.0, view_rotz = 0.0;
4632001f49Smrg
4732001f49Smrg
4832001f49Smrg/* new window size or exposure */
4932001f49Smrgstatic void
5032001f49Smrgreshape(int width, int height)
5132001f49Smrg{
5232001f49Smrg   GLfloat ar = (GLfloat) width / (GLfloat) height;
5332001f49Smrg
5432001f49Smrg   glViewport(0, 0, (GLint) width, (GLint) height);
5532001f49Smrg
5632001f49Smrg   glMatrixMode(GL_PROJECTION);
5732001f49Smrg   glLoadIdentity();
5832001f49Smrg#ifdef GL_VERSION_ES_CM_1_0
5932001f49Smrg   glFrustumf(-ar, ar, -1, 1, 5.0, 60.0);
6032001f49Smrg#else
6132001f49Smrg   glFrustum(-ar, ar, -1, 1, 5.0, 60.0);
6232001f49Smrg#endif
6332001f49Smrg
6432001f49Smrg   glMatrixMode(GL_MODELVIEW);
6532001f49Smrg   glLoadIdentity();
6632001f49Smrg   glTranslatef(0.0, 0.0, -10.0);
6732001f49Smrg}
6832001f49Smrg
6932001f49Smrg
7032001f49Smrgstatic void
7132001f49Smrgdraw(int win)
7232001f49Smrg{
7332001f49Smrg   static const GLfloat verts[3][2] = {
7432001f49Smrg      { -1, -1 },
7532001f49Smrg      {  1, -1 },
7632001f49Smrg      {  0,  1 }
7732001f49Smrg   };
7832001f49Smrg   static const GLfloat colors[3][4] = {
7932001f49Smrg      { 1, 0, 0, 1 },
8032001f49Smrg      { 0, 1, 0, 1 },
8132001f49Smrg      { 0, 0, 1, 1 }
8232001f49Smrg   };
8332001f49Smrg
8432001f49Smrg   assert(win == 0 || win == 1);
8532001f49Smrg
8632001f49Smrg   reshape(WinWidth[win], WinHeight[win]);
8732001f49Smrg
8832001f49Smrg   glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
8932001f49Smrg
9032001f49Smrg   glPushMatrix();
9132001f49Smrg   glRotatef(view_rotx, 1, 0, 0);
9232001f49Smrg   glRotatef(view_roty, 0, 1, 0);
9332001f49Smrg   glRotatef(view_rotz, 0, 0, 1);
9432001f49Smrg
9532001f49Smrg   /* draw triangle */
9632001f49Smrg   {
9732001f49Smrg      glVertexPointer(2, GL_FLOAT, 0, verts);
9832001f49Smrg      glColorPointer(4, GL_FLOAT, 0, colors);
9932001f49Smrg
10032001f49Smrg      glEnableClientState(GL_VERTEX_ARRAY);
10132001f49Smrg      glEnableClientState(GL_COLOR_ARRAY);
10232001f49Smrg
10332001f49Smrg      glDrawArrays(GL_TRIANGLES, 0, 3);
10432001f49Smrg
10532001f49Smrg      glDisableClientState(GL_VERTEX_ARRAY);
10632001f49Smrg      glDisableClientState(GL_COLOR_ARRAY);
10732001f49Smrg   }
10832001f49Smrg
10932001f49Smrg   glPopMatrix();
11032001f49Smrg}
11132001f49Smrg
11232001f49Smrg
11332001f49Smrgstatic void
11432001f49Smrginit(void)
11532001f49Smrg{
11632001f49Smrg   glClearColor(0.4, 0.4, 0.4, 0.0);
11732001f49Smrg}
11832001f49Smrg
11932001f49Smrg
12032001f49Smrg/*
12132001f49Smrg * Create an RGB, double-buffered X window.
12232001f49Smrg * Return the window and context handles.
12332001f49Smrg */
12432001f49Smrgstatic void
12532001f49Smrgmake_x_window(Display *x_dpy, EGLDisplay egl_dpy,
12632001f49Smrg              const char *name,
12732001f49Smrg              int x, int y, int width, int height,
12832001f49Smrg              Window *winRet,
12932001f49Smrg              EGLContext *ctxRet,
13032001f49Smrg              EGLSurface *surfRet)
13132001f49Smrg{
13232001f49Smrg   static const EGLint attribs[] = {
13332001f49Smrg      EGL_RED_SIZE, 1,
13432001f49Smrg      EGL_GREEN_SIZE, 1,
13532001f49Smrg      EGL_BLUE_SIZE, 1,
13632001f49Smrg      EGL_DEPTH_SIZE, 1,
13732001f49Smrg      EGL_NONE
13832001f49Smrg   };
13932001f49Smrg
14032001f49Smrg   int scrnum;
14132001f49Smrg   XSetWindowAttributes attr;
14232001f49Smrg   unsigned long mask;
14332001f49Smrg   Window root;
14432001f49Smrg   Window win;
14532001f49Smrg   XVisualInfo *visInfo, visTemplate;
14632001f49Smrg   int num_visuals;
14732001f49Smrg   EGLContext ctx;
14832001f49Smrg   EGLConfig config;
14932001f49Smrg   EGLint num_configs;
15032001f49Smrg   EGLint vid;
15132001f49Smrg
15232001f49Smrg   scrnum = DefaultScreen( x_dpy );
15332001f49Smrg   root = RootWindow( x_dpy, scrnum );
15432001f49Smrg
15532001f49Smrg   if (!eglChooseConfig( egl_dpy, attribs, &config, 1, &num_configs)) {
15632001f49Smrg      printf("Error: couldn't get an EGL visual config\n");
15732001f49Smrg      exit(1);
15832001f49Smrg   }
15932001f49Smrg
16032001f49Smrg   assert(config);
16132001f49Smrg   assert(num_configs > 0);
16232001f49Smrg
16332001f49Smrg   if (!eglGetConfigAttrib(egl_dpy, config, EGL_NATIVE_VISUAL_ID, &vid)) {
16432001f49Smrg      printf("Error: eglGetConfigAttrib() failed\n");
16532001f49Smrg      exit(1);
16632001f49Smrg   }
16732001f49Smrg
16832001f49Smrg   /* The X window visual must match the EGL config */
16932001f49Smrg   visTemplate.visualid = vid;
17032001f49Smrg   visInfo = XGetVisualInfo(x_dpy, VisualIDMask, &visTemplate, &num_visuals);
17132001f49Smrg   if (!visInfo) {
17232001f49Smrg      printf("Error: couldn't get X visual\n");
17332001f49Smrg      exit(1);
17432001f49Smrg   }
17532001f49Smrg
17632001f49Smrg   /* window attributes */
17732001f49Smrg   attr.background_pixel = 0;
17832001f49Smrg   attr.border_pixel = 0;
17932001f49Smrg   attr.colormap = XCreateColormap( x_dpy, root, visInfo->visual, AllocNone);
18032001f49Smrg   attr.event_mask = StructureNotifyMask | ExposureMask | KeyPressMask;
18132001f49Smrg   mask = CWBackPixel | CWBorderPixel | CWColormap | CWEventMask;
18232001f49Smrg
18332001f49Smrg   win = XCreateWindow( x_dpy, root, x, y, width, height,
18432001f49Smrg		        0, visInfo->depth, InputOutput,
18532001f49Smrg		        visInfo->visual, mask, &attr );
18632001f49Smrg
18732001f49Smrg   /* set hints and properties */
18832001f49Smrg   {
18932001f49Smrg      XSizeHints sizehints;
19032001f49Smrg      sizehints.x = x;
19132001f49Smrg      sizehints.y = y;
19232001f49Smrg      sizehints.width  = width;
19332001f49Smrg      sizehints.height = height;
19432001f49Smrg      sizehints.flags = USSize | USPosition;
19532001f49Smrg      XSetNormalHints(x_dpy, win, &sizehints);
19632001f49Smrg      XSetStandardProperties(x_dpy, win, name, name,
19732001f49Smrg                              None, (char **)NULL, 0, &sizehints);
19832001f49Smrg   }
19932001f49Smrg
20032001f49Smrg#if USE_FULL_GL
20132001f49Smrg   eglBindAPI(EGL_OPENGL_API);
20232001f49Smrg#else
20332001f49Smrg   eglBindAPI(EGL_OPENGL_ES_API);
20432001f49Smrg#endif
20532001f49Smrg
20632001f49Smrg   if (ctxRet) {
20732001f49Smrg      ctx = eglCreateContext(egl_dpy, config, EGL_NO_CONTEXT, NULL );
20832001f49Smrg      if (!ctx) {
20932001f49Smrg         printf("Error: eglCreateContext failed\n");
21032001f49Smrg         exit(1);
21132001f49Smrg      }
21232001f49Smrg      *ctxRet = ctx;
21332001f49Smrg   }
21432001f49Smrg
21532001f49Smrg   *surfRet = eglCreateWindowSurface(egl_dpy, config, win, NULL);
21632001f49Smrg
21732001f49Smrg   if (!*surfRet) {
21832001f49Smrg      printf("Error: eglCreateWindowSurface failed\n");
21932001f49Smrg      exit(1);
22032001f49Smrg   }
22132001f49Smrg
22232001f49Smrg   XFree(visInfo);
22332001f49Smrg
22432001f49Smrg   *winRet = win;
22532001f49Smrg}
22632001f49Smrg
22732001f49Smrg
22832001f49Smrgstatic void
22932001f49Smrgevent_loop(Display *dpy, Window win1, Window win2,
23032001f49Smrg           EGLDisplay egl_dpy, EGLSurface egl_surf1, EGLSurface egl_surf2,
23132001f49Smrg           EGLContext egl_ctx)
23232001f49Smrg{
23332001f49Smrg   while (1) {
23432001f49Smrg      int redraw = 0;
23532001f49Smrg      int win;
23632001f49Smrg      XEvent event;
23732001f49Smrg
23832001f49Smrg      XNextEvent(dpy, &event);
23932001f49Smrg
24032001f49Smrg      switch (event.type) {
24132001f49Smrg      case Expose:
24232001f49Smrg         redraw = 1;
24332001f49Smrg         break;
24432001f49Smrg      case ConfigureNotify:
24532001f49Smrg         if (event.xconfigure.window == win1)
24632001f49Smrg            win = 0;
24732001f49Smrg         else
24832001f49Smrg            win = 1;
24932001f49Smrg         WinWidth[win] = event.xconfigure.width;
25032001f49Smrg         WinHeight[win] = event.xconfigure.height;
25132001f49Smrg         break;
25232001f49Smrg      case KeyPress:
25332001f49Smrg         {
25432001f49Smrg            char buffer[10];
25532001f49Smrg            int r, code;
25632001f49Smrg            code = XLookupKeysym(&event.xkey, 0);
25732001f49Smrg            if (code == XK_Left) {
25832001f49Smrg               view_roty += 5.0;
25932001f49Smrg            }
26032001f49Smrg            else if (code == XK_Right) {
26132001f49Smrg               view_roty -= 5.0;
26232001f49Smrg            }
26332001f49Smrg            else if (code == XK_Up) {
26432001f49Smrg               view_rotx += 5.0;
26532001f49Smrg            }
26632001f49Smrg            else if (code == XK_Down) {
26732001f49Smrg               view_rotx -= 5.0;
26832001f49Smrg            }
26932001f49Smrg            else {
27032001f49Smrg               r = XLookupString(&event.xkey, buffer, sizeof(buffer),
27132001f49Smrg                                 NULL, NULL);
27232001f49Smrg               if (buffer[0] == 27) {
27332001f49Smrg                  /* escape */
27432001f49Smrg                  return;
27532001f49Smrg               }
27632001f49Smrg            }
27732001f49Smrg         }
27832001f49Smrg         redraw = 1;
27932001f49Smrg         break;
28032001f49Smrg      default:
28132001f49Smrg         ; /*no-op*/
28232001f49Smrg      }
28332001f49Smrg
28432001f49Smrg      if (redraw) {
28532001f49Smrg         /* win 1 */
28632001f49Smrg         if (!eglMakeCurrent(egl_dpy, egl_surf1, egl_surf1, egl_ctx)) {
28732001f49Smrg            printf("Error: eglMakeCurrent(1) failed\n");
28832001f49Smrg            return;
28932001f49Smrg         }
29032001f49Smrg         draw(0);
29132001f49Smrg         eglSwapBuffers(egl_dpy, egl_surf1);
29232001f49Smrg
29332001f49Smrg         /* win 2 */
29432001f49Smrg         if (!eglMakeCurrent(egl_dpy, egl_surf2, egl_surf2, egl_ctx)) {
29532001f49Smrg            printf("Error: eglMakeCurrent(2) failed\n");
29632001f49Smrg            return;
29732001f49Smrg         }
29832001f49Smrg         draw(1);
29932001f49Smrg         eglSwapBuffers(egl_dpy, egl_surf2);
30032001f49Smrg      }
30132001f49Smrg   }
30232001f49Smrg}
30332001f49Smrg
30432001f49Smrg
30532001f49Smrgstatic void
30632001f49Smrgusage(void)
30732001f49Smrg{
30832001f49Smrg   printf("Usage:\n");
30932001f49Smrg   printf("  -display <displayname>  set the display to run on\n");
31032001f49Smrg   printf("  -info                   display OpenGL renderer info\n");
31132001f49Smrg}
31232001f49Smrg
31332001f49Smrg
31432001f49Smrgint
31532001f49Smrgmain(int argc, char *argv[])
31632001f49Smrg{
31732001f49Smrg   Display *x_dpy;
31832001f49Smrg   Window win1, win2;
31932001f49Smrg   EGLSurface egl_surf1, egl_surf2;
32032001f49Smrg   EGLContext egl_ctx;
32132001f49Smrg   EGLDisplay egl_dpy;
32232001f49Smrg   char *dpyName = NULL;
32332001f49Smrg   GLboolean printInfo = GL_FALSE;
32432001f49Smrg   EGLint egl_major, egl_minor;
32532001f49Smrg   int i;
32632001f49Smrg   const char *s;
32732001f49Smrg
32832001f49Smrg   static struct {
32932001f49Smrg      char *name;
33032001f49Smrg      GLenum value;
33132001f49Smrg      enum {GetString, GetInteger} type;
33232001f49Smrg   } info_items[] = {
33332001f49Smrg      {"GL_RENDERER", GL_RENDERER, GetString},
33432001f49Smrg      {"GL_VERSION", GL_VERSION, GetString},
33532001f49Smrg      {"GL_VENDOR", GL_VENDOR, GetString},
33632001f49Smrg      {"GL_EXTENSIONS", GL_EXTENSIONS, GetString},
33732001f49Smrg      {"GL_MAX_PALETTE_MATRICES_OES", GL_MAX_PALETTE_MATRICES_OES, GetInteger},
33832001f49Smrg      {"GL_MAX_VERTEX_UNITS_OES", GL_MAX_VERTEX_UNITS_OES, GetInteger},
33932001f49Smrg   };
34032001f49Smrg
34132001f49Smrg   for (i = 1; i < argc; i++) {
34232001f49Smrg      if (strcmp(argv[i], "-display") == 0) {
34332001f49Smrg         dpyName = argv[i+1];
34432001f49Smrg         i++;
34532001f49Smrg      }
34632001f49Smrg      else if (strcmp(argv[i], "-info") == 0) {
34732001f49Smrg         printInfo = GL_TRUE;
34832001f49Smrg      }
34932001f49Smrg      else {
35032001f49Smrg         usage();
35132001f49Smrg         return -1;
35232001f49Smrg      }
35332001f49Smrg   }
35432001f49Smrg
35532001f49Smrg   x_dpy = XOpenDisplay(dpyName);
35632001f49Smrg   if (!x_dpy) {
35732001f49Smrg      printf("Error: couldn't open display %s\n",
35832001f49Smrg	     dpyName ? dpyName : getenv("DISPLAY"));
35932001f49Smrg      return -1;
36032001f49Smrg   }
36132001f49Smrg
36232001f49Smrg   egl_dpy = eglGetDisplay(x_dpy);
36332001f49Smrg   if (!egl_dpy) {
36432001f49Smrg      printf("Error: eglGetDisplay() failed\n");
36532001f49Smrg      return -1;
36632001f49Smrg   }
36732001f49Smrg
36832001f49Smrg   if (!eglInitialize(egl_dpy, &egl_major, &egl_minor)) {
36932001f49Smrg      printf("Error: eglInitialize() failed\n");
37032001f49Smrg      return -1;
37132001f49Smrg   }
37232001f49Smrg
37332001f49Smrg   s = eglQueryString(egl_dpy, EGL_VERSION);
37432001f49Smrg   printf("EGL_VERSION = %s\n", s);
37532001f49Smrg
37632001f49Smrg   s = eglQueryString(egl_dpy, EGL_VENDOR);
37732001f49Smrg   printf("EGL_VENDOR = %s\n", s);
37832001f49Smrg
37932001f49Smrg   s = eglQueryString(egl_dpy, EGL_EXTENSIONS);
38032001f49Smrg   printf("EGL_EXTENSIONS = %s\n", s);
38132001f49Smrg
38232001f49Smrg   s = eglQueryString(egl_dpy, EGL_CLIENT_APIS);
38332001f49Smrg   printf("EGL_CLIENT_APIS = %s\n", s);
38432001f49Smrg
38532001f49Smrg   make_x_window(x_dpy, egl_dpy,
38632001f49Smrg                 "xegl_two_win #1", 0, 0, WinWidth[0], WinHeight[0],
38732001f49Smrg                 &win1, &egl_ctx, &egl_surf1);
38832001f49Smrg
38932001f49Smrg   make_x_window(x_dpy, egl_dpy,
39032001f49Smrg                 "xegl_two_win #2", WinWidth[0] + 50, 0,
39132001f49Smrg                 WinWidth[1], WinHeight[1],
39232001f49Smrg                 &win2, NULL, &egl_surf2);
39332001f49Smrg
39432001f49Smrg   XMapWindow(x_dpy, win1);
39532001f49Smrg
39632001f49Smrg   XMapWindow(x_dpy, win2);
39732001f49Smrg
39832001f49Smrg   if (!eglMakeCurrent(egl_dpy, egl_surf1, egl_surf1, egl_ctx)) {
39932001f49Smrg      printf("Error: eglMakeCurrent() failed\n");
40032001f49Smrg      return -1;
40132001f49Smrg   }
40232001f49Smrg
40332001f49Smrg   if (printInfo) {
40432001f49Smrg      for (i = 0; i < sizeof(info_items)/sizeof(info_items[0]); i++) {
40532001f49Smrg         switch (info_items[i].type) {
40632001f49Smrg            case GetString:
40732001f49Smrg               printf("%s = %s\n", info_items[i].name, (char *)glGetString(info_items[i].value));
40832001f49Smrg               break;
40932001f49Smrg            case GetInteger: {
41032001f49Smrg               GLint rv = -1;
41132001f49Smrg               glGetIntegerv(info_items[i].value, &rv);
41232001f49Smrg               printf("%s = %d\n", info_items[i].name, rv);
41332001f49Smrg               break;
41432001f49Smrg            }
41532001f49Smrg         }
41632001f49Smrg      }
41732001f49Smrg   };
41832001f49Smrg
41932001f49Smrg   init();
42032001f49Smrg
42132001f49Smrg   event_loop(x_dpy, win1, win2, egl_dpy, egl_surf1, egl_surf2, egl_ctx);
42232001f49Smrg
42332001f49Smrg   eglDestroyContext(egl_dpy, egl_ctx);
42432001f49Smrg   eglDestroySurface(egl_dpy, egl_surf1);
42532001f49Smrg   eglDestroySurface(egl_dpy, egl_surf2);
42632001f49Smrg   eglTerminate(egl_dpy);
42732001f49Smrg
42832001f49Smrg   XDestroyWindow(x_dpy, win1);
42932001f49Smrg   XDestroyWindow(x_dpy, win2);
43032001f49Smrg   XCloseDisplay(x_dpy);
43132001f49Smrg
43232001f49Smrg   return 0;
43332001f49Smrg}
434