eglut.c revision 32001f49
1/*
2 * Copyright (C) 2010 LunarG Inc.
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 OR
15 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
17 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
19 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
20 * DEALINGS IN THE SOFTWARE.
21 *
22 * Authors:
23 *    Chia-I Wu <olv@lunarg.com>
24 */
25
26#include <stdio.h>
27#include <stdlib.h>
28#include <string.h>
29#include <stdarg.h>
30#include <sys/time.h>
31
32#include "EGL/egl.h"
33#include "EGL/eglext.h"
34
35#include "eglutint.h"
36
37static struct eglut_state _eglut_state = {
38   .api_mask = EGLUT_OPENGL_ES1_BIT,
39   .window_width = 300,
40   .window_height = 300,
41   .verbose = 0,
42   .num_windows = 0,
43};
44
45struct eglut_state *_eglut = &_eglut_state;
46
47void
48_eglutFatal(char *format, ...)
49{
50  va_list args;
51
52  va_start(args, format);
53
54  fprintf(stderr, "EGLUT: ");
55  vfprintf(stderr, format, args);
56  va_end(args);
57  putc('\n', stderr);
58
59  exit(1);
60}
61
62/* return current time (in milliseconds) */
63int
64_eglutNow(void)
65{
66   struct timeval tv;
67#ifdef __VMS
68   (void) gettimeofday(&tv, NULL );
69#else
70   struct timezone tz;
71   (void) gettimeofday(&tv, &tz);
72#endif
73   return tv.tv_sec * 1000 + tv.tv_usec / 1000;
74}
75
76static void
77_eglutDestroyWindow(struct eglut_window *win)
78{
79   if (_eglut->surface_type != EGL_PBUFFER_BIT &&
80       _eglut->surface_type != EGL_SCREEN_BIT_MESA)
81      eglDestroySurface(_eglut->dpy, win->surface);
82
83   _eglutNativeFiniWindow(win);
84
85   eglDestroyContext(_eglut->dpy, win->context);
86}
87
88static EGLConfig
89_eglutChooseConfig(void)
90{
91   EGLConfig config;
92   EGLint config_attribs[32];
93   EGLint renderable_type, num_configs, i;
94
95   i = 0;
96   config_attribs[i++] = EGL_RED_SIZE;
97   config_attribs[i++] = 1;
98   config_attribs[i++] = EGL_GREEN_SIZE;
99   config_attribs[i++] = 1;
100   config_attribs[i++] = EGL_BLUE_SIZE;
101   config_attribs[i++] = 1;
102   config_attribs[i++] = EGL_DEPTH_SIZE;
103   config_attribs[i++] = 1;
104
105   config_attribs[i++] = EGL_SURFACE_TYPE;
106   config_attribs[i++] = _eglut->surface_type;
107
108   config_attribs[i++] = EGL_RENDERABLE_TYPE;
109   renderable_type = 0x0;
110   if (_eglut->api_mask & EGLUT_OPENGL_BIT)
111      renderable_type |= EGL_OPENGL_BIT;
112   if (_eglut->api_mask & EGLUT_OPENGL_ES1_BIT)
113      renderable_type |= EGL_OPENGL_ES_BIT;
114   if (_eglut->api_mask & EGLUT_OPENGL_ES2_BIT)
115      renderable_type |= EGL_OPENGL_ES2_BIT;
116   if (_eglut->api_mask & EGLUT_OPENVG_BIT)
117      renderable_type |= EGL_OPENVG_BIT;
118   config_attribs[i++] = renderable_type;
119
120   config_attribs[i] = EGL_NONE;
121
122   if (!eglChooseConfig(_eglut->dpy,
123            config_attribs, &config, 1, &num_configs) || !num_configs)
124      _eglutFatal("failed to choose a config");
125
126   return config;
127}
128
129static struct eglut_window *
130_eglutCreateWindow(const char *title, int x, int y, int w, int h)
131{
132   struct eglut_window *win;
133   EGLint context_attribs[4];
134   EGLint api, i;
135
136   win = calloc(1, sizeof(*win));
137   if (!win)
138      _eglutFatal("failed to allocate window");
139
140   win->config = _eglutChooseConfig();
141
142   i = 0;
143   context_attribs[i] = EGL_NONE;
144
145   /* multiple APIs? */
146
147   api = EGL_OPENGL_ES_API;
148   if (_eglut->api_mask & EGLUT_OPENGL_BIT) {
149      api = EGL_OPENGL_API;
150   }
151   else if (_eglut->api_mask & EGLUT_OPENVG_BIT) {
152      api = EGL_OPENVG_API;
153   }
154   else if (_eglut->api_mask & EGLUT_OPENGL_ES2_BIT) {
155      context_attribs[i++] = EGL_CONTEXT_CLIENT_VERSION;
156      context_attribs[i++] = 2;
157   }
158
159   context_attribs[i] = EGL_NONE;
160
161   eglBindAPI(api);
162   win->context = eglCreateContext(_eglut->dpy,
163         win->config, EGL_NO_CONTEXT, context_attribs);
164   if (!win->context)
165      _eglutFatal("failed to create context");
166
167   _eglutNativeInitWindow(win, title, x, y, w, h);
168   switch (_eglut->surface_type) {
169   case EGL_WINDOW_BIT:
170      win->surface = eglCreateWindowSurface(_eglut->dpy,
171            win->config, win->native.u.window, NULL);
172      break;
173   case EGL_PIXMAP_BIT:
174      win->surface = eglCreatePixmapSurface(_eglut->dpy,
175            win->config, win->native.u.pixmap, NULL);
176      break;
177   case EGL_PBUFFER_BIT:
178   case EGL_SCREEN_BIT_MESA:
179      win->surface = win->native.u.surface;
180      break;
181   default:
182      break;
183   }
184   if (win->surface == EGL_NO_SURFACE)
185      _eglutFatal("failed to create surface");
186
187   return win;
188}
189
190void
191eglutInitAPIMask(int mask)
192{
193   _eglut->api_mask = mask;
194}
195
196void
197eglutInitWindowSize(int width, int height)
198{
199   _eglut->window_width = width;
200   _eglut->window_height = height;
201}
202
203void
204eglutInit(int argc, char **argv)
205{
206   int i;
207
208   for (i = 1; i < argc; i++) {
209      if (strcmp(argv[i], "-display") == 0)
210         _eglut->display_name = argv[++i];
211      else if (strcmp(argv[i], "-info") == 0) {
212         _eglut->verbose = 1;
213      }
214   }
215
216   _eglutNativeInitDisplay();
217   _eglut->dpy = eglGetDisplay(_eglut->native_dpy);
218
219   if (!eglInitialize(_eglut->dpy, &_eglut->major, &_eglut->minor))
220      _eglutFatal("failed to initialize EGL display");
221
222   _eglut->init_time = _eglutNow();
223
224   printf("EGL_VERSION = %s\n", eglQueryString(_eglut->dpy, EGL_VERSION));
225   if (_eglut->verbose) {
226      printf("EGL_VENDOR = %s\n", eglQueryString(_eglut->dpy, EGL_VENDOR));
227      printf("EGL_EXTENSIONS = %s\n",
228            eglQueryString(_eglut->dpy, EGL_EXTENSIONS));
229      printf("EGL_CLIENT_APIS = %s\n",
230            eglQueryString(_eglut->dpy, EGL_CLIENT_APIS));
231   }
232}
233
234int
235eglutGet(int state)
236{
237   int val;
238
239   switch (state) {
240   case EGLUT_ELAPSED_TIME:
241      val = _eglutNow() - _eglut->init_time;
242      break;
243   default:
244      val = -1;
245      break;
246   }
247
248   return val;
249}
250
251void
252eglutIdleFunc(EGLUTidleCB func)
253{
254   _eglut->idle_cb = func;
255}
256
257void
258eglutPostRedisplay(void)
259{
260   _eglut->redisplay = 1;
261}
262
263void
264eglutMainLoop(void)
265{
266   struct eglut_window *win = _eglut->current;
267
268   if (!win)
269      _eglutFatal("no window is created\n");
270
271   if (win->reshape_cb)
272      win->reshape_cb(win->native.width, win->native.height);
273
274   _eglutNativeEventLoop();
275}
276
277static void
278_eglutFini(void)
279{
280   eglTerminate(_eglut->dpy);
281   _eglutNativeFiniDisplay();
282}
283
284void
285eglutDestroyWindow(int win)
286{
287   struct eglut_window *window = _eglut->current;
288
289   if (window->index != win)
290      return;
291
292   /* XXX it causes some bug in st/egl KMS backend */
293   if ( _eglut->surface_type != EGL_SCREEN_BIT_MESA)
294      eglMakeCurrent(_eglut->dpy, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
295
296   _eglutDestroyWindow(_eglut->current);
297}
298
299static void
300_eglutDefaultKeyboard(unsigned char key)
301{
302   if (key == 27) {
303      if (_eglut->current)
304         eglutDestroyWindow(_eglut->current->index);
305      _eglutFini();
306
307      exit(0);
308   }
309}
310
311int
312eglutCreateWindow(const char *title)
313{
314   struct eglut_window *win;
315
316   win = _eglutCreateWindow(title, 0, 0,
317         _eglut->window_width, _eglut->window_height);
318
319   win->index = _eglut->num_windows++;
320   win->reshape_cb = NULL;
321   win->display_cb = NULL;
322   win->keyboard_cb = _eglutDefaultKeyboard;
323   win->special_cb = NULL;
324
325   if (!eglMakeCurrent(_eglut->dpy, win->surface, win->surface, win->context))
326      _eglutFatal("failed to make window current");
327   _eglut->current = win;
328
329   return win->index;
330}
331
332int
333eglutGetWindowWidth(void)
334{
335   struct eglut_window *win = _eglut->current;
336   return win->native.width;
337}
338
339int
340eglutGetWindowHeight(void)
341{
342   struct eglut_window *win = _eglut->current;
343   return win->native.height;
344}
345
346void
347eglutDisplayFunc(EGLUTdisplayCB func)
348{
349   struct eglut_window *win = _eglut->current;
350   win->display_cb = func;
351
352}
353
354void
355eglutReshapeFunc(EGLUTreshapeCB func)
356{
357   struct eglut_window *win = _eglut->current;
358   win->reshape_cb = func;
359}
360
361void
362eglutKeyboardFunc(EGLUTkeyboardCB func)
363{
364   struct eglut_window *win = _eglut->current;
365   win->keyboard_cb = func;
366}
367
368void
369eglutSpecialFunc(EGLUTspecialCB func)
370{
371   struct eglut_window *win = _eglut->current;
372   win->special_cb = func;
373}
374