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 eglDestroySurface(_eglut->dpy, win->surface); 81 82 _eglutNativeFiniWindow(win); 83 84 eglDestroyContext(_eglut->dpy, win->context); 85} 86 87static EGLConfig 88_eglutChooseConfig(void) 89{ 90 EGLConfig config; 91 EGLint config_attribs[32]; 92 EGLint renderable_type, num_configs, i; 93 94 i = 0; 95 config_attribs[i++] = EGL_RED_SIZE; 96 config_attribs[i++] = 1; 97 config_attribs[i++] = EGL_GREEN_SIZE; 98 config_attribs[i++] = 1; 99 config_attribs[i++] = EGL_BLUE_SIZE; 100 config_attribs[i++] = 1; 101 config_attribs[i++] = EGL_DEPTH_SIZE; 102 config_attribs[i++] = 1; 103 104 config_attribs[i++] = EGL_SURFACE_TYPE; 105 config_attribs[i++] = _eglut->surface_type; 106 107 config_attribs[i++] = EGL_RENDERABLE_TYPE; 108 renderable_type = 0x0; 109 if (_eglut->api_mask & EGLUT_OPENGL_BIT) 110 renderable_type |= EGL_OPENGL_BIT; 111 if (_eglut->api_mask & EGLUT_OPENGL_ES1_BIT) 112 renderable_type |= EGL_OPENGL_ES_BIT; 113 if (_eglut->api_mask & EGLUT_OPENGL_ES2_BIT) 114 renderable_type |= EGL_OPENGL_ES2_BIT; 115 if (_eglut->api_mask & EGLUT_OPENVG_BIT) 116 renderable_type |= EGL_OPENVG_BIT; 117 config_attribs[i++] = renderable_type; 118 119 config_attribs[i] = EGL_NONE; 120 121 if (!eglChooseConfig(_eglut->dpy, 122 config_attribs, &config, 1, &num_configs) || !num_configs) 123 _eglutFatal("failed to choose a config"); 124 125 return config; 126} 127 128static struct eglut_window * 129_eglutCreateWindow(const char *title, int x, int y, int w, int h) 130{ 131 struct eglut_window *win; 132 EGLint context_attribs[4]; 133 EGLint api, i; 134 135 win = calloc(1, sizeof(*win)); 136 if (!win) 137 _eglutFatal("failed to allocate window"); 138 139 win->config = _eglutChooseConfig(); 140 141 i = 0; 142 context_attribs[i] = EGL_NONE; 143 144 /* multiple APIs? */ 145 146 api = EGL_OPENGL_ES_API; 147 if (_eglut->api_mask & EGLUT_OPENGL_BIT) { 148 api = EGL_OPENGL_API; 149 } 150 else if (_eglut->api_mask & EGLUT_OPENVG_BIT) { 151 api = EGL_OPENVG_API; 152 } 153 else if (_eglut->api_mask & EGLUT_OPENGL_ES2_BIT) { 154 context_attribs[i++] = EGL_CONTEXT_CLIENT_VERSION; 155 context_attribs[i++] = 2; 156 } 157 158 context_attribs[i] = EGL_NONE; 159 160 eglBindAPI(api); 161 win->context = eglCreateContext(_eglut->dpy, 162 win->config, EGL_NO_CONTEXT, context_attribs); 163 if (!win->context) 164 _eglutFatal("failed to create context"); 165 166 _eglutNativeInitWindow(win, title, x, y, w, h); 167 switch (_eglut->surface_type) { 168 case EGL_WINDOW_BIT: 169 win->surface = eglCreateWindowSurface(_eglut->dpy, 170 win->config, win->native.u.window, NULL); 171 break; 172 case EGL_PIXMAP_BIT: 173 win->surface = eglCreatePixmapSurface(_eglut->dpy, 174 win->config, win->native.u.pixmap, NULL); 175 break; 176 case EGL_PBUFFER_BIT: 177 win->surface = win->native.u.surface; 178 break; 179 default: 180 break; 181 } 182 if (win->surface == EGL_NO_SURFACE) 183 _eglutFatal("failed to create surface"); 184 185 return win; 186} 187 188void 189eglutInitAPIMask(int mask) 190{ 191 _eglut->api_mask = mask; 192} 193 194void 195eglutInitWindowSize(int width, int height) 196{ 197 _eglut->window_width = width; 198 _eglut->window_height = height; 199} 200 201void 202eglutInit(int argc, char **argv) 203{ 204 int i; 205 206 for (i = 1; i < argc; i++) { 207 if (strcmp(argv[i], "-display") == 0) 208 _eglut->display_name = argv[++i]; 209 else if (strcmp(argv[i], "-info") == 0) { 210 _eglut->verbose = 1; 211 } 212 } 213 214 _eglutNativeInitDisplay(); 215 _eglut->dpy = eglGetDisplay(_eglut->native_dpy); 216 217 if (!eglInitialize(_eglut->dpy, &_eglut->major, &_eglut->minor)) 218 _eglutFatal("failed to initialize EGL display"); 219 220 _eglut->init_time = _eglutNow(); 221 222 printf("EGL_VERSION = %s\n", eglQueryString(_eglut->dpy, EGL_VERSION)); 223 if (_eglut->verbose) { 224 printf("EGL_VENDOR = %s\n", eglQueryString(_eglut->dpy, EGL_VENDOR)); 225 printf("EGL_EXTENSIONS = %s\n", 226 eglQueryString(_eglut->dpy, EGL_EXTENSIONS)); 227 printf("EGL_CLIENT_APIS = %s\n", 228 eglQueryString(_eglut->dpy, EGL_CLIENT_APIS)); 229 } 230} 231 232int 233eglutGet(int state) 234{ 235 int val; 236 237 switch (state) { 238 case EGLUT_ELAPSED_TIME: 239 val = _eglutNow() - _eglut->init_time; 240 break; 241 default: 242 val = -1; 243 break; 244 } 245 246 return val; 247} 248 249void 250eglutIdleFunc(EGLUTidleCB func) 251{ 252 _eglut->idle_cb = func; 253} 254 255void 256eglutPostRedisplay(void) 257{ 258 _eglut->redisplay = 1; 259} 260 261void 262eglutMainLoop(void) 263{ 264 struct eglut_window *win = _eglut->current; 265 266 if (!win) 267 _eglutFatal("no window is created\n"); 268 269 if (win->reshape_cb) 270 win->reshape_cb(win->native.width, win->native.height); 271 272 _eglutNativeEventLoop(); 273} 274 275static void 276_eglutFini(void) 277{ 278 eglTerminate(_eglut->dpy); 279 _eglutNativeFiniDisplay(); 280} 281 282void 283eglutDestroyWindow(int win) 284{ 285 struct eglut_window *window = _eglut->current; 286 287 if (window->index != win) 288 return; 289 290 eglMakeCurrent(_eglut->dpy, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT); 291 292 _eglutDestroyWindow(_eglut->current); 293} 294 295static void 296_eglutDefaultKeyboard(unsigned char key) 297{ 298 if (key == 27) { 299 if (_eglut->current) 300 eglutDestroyWindow(_eglut->current->index); 301 _eglutFini(); 302 303 exit(0); 304 } 305} 306 307int 308eglutCreateWindow(const char *title) 309{ 310 struct eglut_window *win; 311 312 win = _eglutCreateWindow(title, 0, 0, 313 _eglut->window_width, _eglut->window_height); 314 315 win->index = _eglut->num_windows++; 316 win->reshape_cb = NULL; 317 win->display_cb = NULL; 318 win->keyboard_cb = _eglutDefaultKeyboard; 319 win->special_cb = NULL; 320 321 if (!eglMakeCurrent(_eglut->dpy, win->surface, win->surface, win->context)) 322 _eglutFatal("failed to make window current"); 323 _eglut->current = win; 324 325 return win->index; 326} 327 328int 329eglutGetWindowWidth(void) 330{ 331 struct eglut_window *win = _eglut->current; 332 return win->native.width; 333} 334 335int 336eglutGetWindowHeight(void) 337{ 338 struct eglut_window *win = _eglut->current; 339 return win->native.height; 340} 341 342void 343eglutDisplayFunc(EGLUTdisplayCB func) 344{ 345 struct eglut_window *win = _eglut->current; 346 win->display_cb = func; 347 348} 349 350void 351eglutReshapeFunc(EGLUTreshapeCB func) 352{ 353 struct eglut_window *win = _eglut->current; 354 win->reshape_cb = func; 355} 356 357void 358eglutKeyboardFunc(EGLUTkeyboardCB func) 359{ 360 struct eglut_window *win = _eglut->current; 361 win->keyboard_cb = func; 362} 363 364void 365eglutSpecialFunc(EGLUTspecialCB func) 366{ 367 struct eglut_window *win = _eglut->current; 368 win->special_cb = func; 369} 370