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