132001f49Smrg/*
232001f49Smrg * Copyright (C) 2010 LunarG Inc.
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 OR
1532001f49Smrg * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
1632001f49Smrg * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
1732001f49Smrg * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
1832001f49Smrg * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
1932001f49Smrg * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
2032001f49Smrg * DEALINGS IN THE SOFTWARE.
2132001f49Smrg *
2232001f49Smrg * Authors:
2332001f49Smrg *    Chia-I Wu <olv@lunarg.com>
2432001f49Smrg */
2532001f49Smrg
2632001f49Smrg#include <stdio.h>
2732001f49Smrg#include <stdlib.h>
2832001f49Smrg#include <string.h>
2932001f49Smrg#include <stdarg.h>
3032001f49Smrg#include <sys/time.h>
3132001f49Smrg
3232001f49Smrg#include "EGL/egl.h"
3332001f49Smrg#include "EGL/eglext.h"
3432001f49Smrg
3532001f49Smrg#include "eglutint.h"
3632001f49Smrg
3732001f49Smrgstatic struct eglut_state _eglut_state = {
3832001f49Smrg   .api_mask = EGLUT_OPENGL_ES1_BIT,
3932001f49Smrg   .window_width = 300,
4032001f49Smrg   .window_height = 300,
4132001f49Smrg   .verbose = 0,
4232001f49Smrg   .num_windows = 0,
4332001f49Smrg};
4432001f49Smrg
4532001f49Smrgstruct eglut_state *_eglut = &_eglut_state;
4632001f49Smrg
4732001f49Smrgvoid
4832001f49Smrg_eglutFatal(char *format, ...)
4932001f49Smrg{
5032001f49Smrg  va_list args;
5132001f49Smrg
5232001f49Smrg  va_start(args, format);
5332001f49Smrg
5432001f49Smrg  fprintf(stderr, "EGLUT: ");
5532001f49Smrg  vfprintf(stderr, format, args);
5632001f49Smrg  va_end(args);
5732001f49Smrg  putc('\n', stderr);
5832001f49Smrg
5932001f49Smrg  exit(1);
6032001f49Smrg}
6132001f49Smrg
6232001f49Smrg/* return current time (in milliseconds) */
6332001f49Smrgint
6432001f49Smrg_eglutNow(void)
6532001f49Smrg{
6632001f49Smrg   struct timeval tv;
6732001f49Smrg#ifdef __VMS
6832001f49Smrg   (void) gettimeofday(&tv, NULL );
6932001f49Smrg#else
7032001f49Smrg   struct timezone tz;
7132001f49Smrg   (void) gettimeofday(&tv, &tz);
7232001f49Smrg#endif
7332001f49Smrg   return tv.tv_sec * 1000 + tv.tv_usec / 1000;
7432001f49Smrg}
7532001f49Smrg
7632001f49Smrgstatic void
7732001f49Smrg_eglutDestroyWindow(struct eglut_window *win)
7832001f49Smrg{
797ec3b29aSmrg   if (_eglut->surface_type != EGL_PBUFFER_BIT)
8032001f49Smrg      eglDestroySurface(_eglut->dpy, win->surface);
8132001f49Smrg
8232001f49Smrg   _eglutNativeFiniWindow(win);
8332001f49Smrg
8432001f49Smrg   eglDestroyContext(_eglut->dpy, win->context);
8532001f49Smrg}
8632001f49Smrg
8732001f49Smrgstatic EGLConfig
8832001f49Smrg_eglutChooseConfig(void)
8932001f49Smrg{
9032001f49Smrg   EGLConfig config;
9132001f49Smrg   EGLint config_attribs[32];
9232001f49Smrg   EGLint renderable_type, num_configs, i;
9332001f49Smrg
9432001f49Smrg   i = 0;
9532001f49Smrg   config_attribs[i++] = EGL_RED_SIZE;
9632001f49Smrg   config_attribs[i++] = 1;
9732001f49Smrg   config_attribs[i++] = EGL_GREEN_SIZE;
9832001f49Smrg   config_attribs[i++] = 1;
9932001f49Smrg   config_attribs[i++] = EGL_BLUE_SIZE;
10032001f49Smrg   config_attribs[i++] = 1;
10132001f49Smrg   config_attribs[i++] = EGL_DEPTH_SIZE;
10232001f49Smrg   config_attribs[i++] = 1;
10332001f49Smrg
10432001f49Smrg   config_attribs[i++] = EGL_SURFACE_TYPE;
10532001f49Smrg   config_attribs[i++] = _eglut->surface_type;
10632001f49Smrg
10732001f49Smrg   config_attribs[i++] = EGL_RENDERABLE_TYPE;
10832001f49Smrg   renderable_type = 0x0;
10932001f49Smrg   if (_eglut->api_mask & EGLUT_OPENGL_BIT)
11032001f49Smrg      renderable_type |= EGL_OPENGL_BIT;
11132001f49Smrg   if (_eglut->api_mask & EGLUT_OPENGL_ES1_BIT)
11232001f49Smrg      renderable_type |= EGL_OPENGL_ES_BIT;
11332001f49Smrg   if (_eglut->api_mask & EGLUT_OPENGL_ES2_BIT)
11432001f49Smrg      renderable_type |= EGL_OPENGL_ES2_BIT;
11532001f49Smrg   if (_eglut->api_mask & EGLUT_OPENVG_BIT)
11632001f49Smrg      renderable_type |= EGL_OPENVG_BIT;
11732001f49Smrg   config_attribs[i++] = renderable_type;
11832001f49Smrg
11932001f49Smrg   config_attribs[i] = EGL_NONE;
12032001f49Smrg
12132001f49Smrg   if (!eglChooseConfig(_eglut->dpy,
12232001f49Smrg            config_attribs, &config, 1, &num_configs) || !num_configs)
12332001f49Smrg      _eglutFatal("failed to choose a config");
12432001f49Smrg
12532001f49Smrg   return config;
12632001f49Smrg}
12732001f49Smrg
12832001f49Smrgstatic struct eglut_window *
12932001f49Smrg_eglutCreateWindow(const char *title, int x, int y, int w, int h)
13032001f49Smrg{
13132001f49Smrg   struct eglut_window *win;
13232001f49Smrg   EGLint context_attribs[4];
13332001f49Smrg   EGLint api, i;
13432001f49Smrg
13532001f49Smrg   win = calloc(1, sizeof(*win));
13632001f49Smrg   if (!win)
13732001f49Smrg      _eglutFatal("failed to allocate window");
13832001f49Smrg
13932001f49Smrg   win->config = _eglutChooseConfig();
14032001f49Smrg
14132001f49Smrg   i = 0;
14232001f49Smrg   context_attribs[i] = EGL_NONE;
14332001f49Smrg
14432001f49Smrg   /* multiple APIs? */
14532001f49Smrg
14632001f49Smrg   api = EGL_OPENGL_ES_API;
14732001f49Smrg   if (_eglut->api_mask & EGLUT_OPENGL_BIT) {
14832001f49Smrg      api = EGL_OPENGL_API;
14932001f49Smrg   }
15032001f49Smrg   else if (_eglut->api_mask & EGLUT_OPENVG_BIT) {
15132001f49Smrg      api = EGL_OPENVG_API;
15232001f49Smrg   }
15332001f49Smrg   else if (_eglut->api_mask & EGLUT_OPENGL_ES2_BIT) {
15432001f49Smrg      context_attribs[i++] = EGL_CONTEXT_CLIENT_VERSION;
15532001f49Smrg      context_attribs[i++] = 2;
15632001f49Smrg   }
15732001f49Smrg
15832001f49Smrg   context_attribs[i] = EGL_NONE;
15932001f49Smrg
16032001f49Smrg   eglBindAPI(api);
16132001f49Smrg   win->context = eglCreateContext(_eglut->dpy,
16232001f49Smrg         win->config, EGL_NO_CONTEXT, context_attribs);
16332001f49Smrg   if (!win->context)
16432001f49Smrg      _eglutFatal("failed to create context");
16532001f49Smrg
16632001f49Smrg   _eglutNativeInitWindow(win, title, x, y, w, h);
16732001f49Smrg   switch (_eglut->surface_type) {
16832001f49Smrg   case EGL_WINDOW_BIT:
16932001f49Smrg      win->surface = eglCreateWindowSurface(_eglut->dpy,
17032001f49Smrg            win->config, win->native.u.window, NULL);
17132001f49Smrg      break;
17232001f49Smrg   case EGL_PIXMAP_BIT:
17332001f49Smrg      win->surface = eglCreatePixmapSurface(_eglut->dpy,
17432001f49Smrg            win->config, win->native.u.pixmap, NULL);
17532001f49Smrg      break;
17632001f49Smrg   case EGL_PBUFFER_BIT:
17732001f49Smrg      win->surface = win->native.u.surface;
17832001f49Smrg      break;
17932001f49Smrg   default:
18032001f49Smrg      break;
18132001f49Smrg   }
18232001f49Smrg   if (win->surface == EGL_NO_SURFACE)
18332001f49Smrg      _eglutFatal("failed to create surface");
18432001f49Smrg
18532001f49Smrg   return win;
18632001f49Smrg}
18732001f49Smrg
18832001f49Smrgvoid
18932001f49SmrgeglutInitAPIMask(int mask)
19032001f49Smrg{
19132001f49Smrg   _eglut->api_mask = mask;
19232001f49Smrg}
19332001f49Smrg
19432001f49Smrgvoid
19532001f49SmrgeglutInitWindowSize(int width, int height)
19632001f49Smrg{
19732001f49Smrg   _eglut->window_width = width;
19832001f49Smrg   _eglut->window_height = height;
19932001f49Smrg}
20032001f49Smrg
20132001f49Smrgvoid
20232001f49SmrgeglutInit(int argc, char **argv)
20332001f49Smrg{
20432001f49Smrg   int i;
20532001f49Smrg
20632001f49Smrg   for (i = 1; i < argc; i++) {
20732001f49Smrg      if (strcmp(argv[i], "-display") == 0)
20832001f49Smrg         _eglut->display_name = argv[++i];
20932001f49Smrg      else if (strcmp(argv[i], "-info") == 0) {
21032001f49Smrg         _eglut->verbose = 1;
21132001f49Smrg      }
21232001f49Smrg   }
21332001f49Smrg
21432001f49Smrg   _eglutNativeInitDisplay();
21532001f49Smrg   _eglut->dpy = eglGetDisplay(_eglut->native_dpy);
21632001f49Smrg
21732001f49Smrg   if (!eglInitialize(_eglut->dpy, &_eglut->major, &_eglut->minor))
21832001f49Smrg      _eglutFatal("failed to initialize EGL display");
21932001f49Smrg
22032001f49Smrg   _eglut->init_time = _eglutNow();
22132001f49Smrg
22232001f49Smrg   printf("EGL_VERSION = %s\n", eglQueryString(_eglut->dpy, EGL_VERSION));
22332001f49Smrg   if (_eglut->verbose) {
22432001f49Smrg      printf("EGL_VENDOR = %s\n", eglQueryString(_eglut->dpy, EGL_VENDOR));
22532001f49Smrg      printf("EGL_EXTENSIONS = %s\n",
22632001f49Smrg            eglQueryString(_eglut->dpy, EGL_EXTENSIONS));
22732001f49Smrg      printf("EGL_CLIENT_APIS = %s\n",
22832001f49Smrg            eglQueryString(_eglut->dpy, EGL_CLIENT_APIS));
22932001f49Smrg   }
23032001f49Smrg}
23132001f49Smrg
23232001f49Smrgint
23332001f49SmrgeglutGet(int state)
23432001f49Smrg{
23532001f49Smrg   int val;
23632001f49Smrg
23732001f49Smrg   switch (state) {
23832001f49Smrg   case EGLUT_ELAPSED_TIME:
23932001f49Smrg      val = _eglutNow() - _eglut->init_time;
24032001f49Smrg      break;
24132001f49Smrg   default:
24232001f49Smrg      val = -1;
24332001f49Smrg      break;
24432001f49Smrg   }
24532001f49Smrg
24632001f49Smrg   return val;
24732001f49Smrg}
24832001f49Smrg
24932001f49Smrgvoid
25032001f49SmrgeglutIdleFunc(EGLUTidleCB func)
25132001f49Smrg{
25232001f49Smrg   _eglut->idle_cb = func;
25332001f49Smrg}
25432001f49Smrg
25532001f49Smrgvoid
25632001f49SmrgeglutPostRedisplay(void)
25732001f49Smrg{
25832001f49Smrg   _eglut->redisplay = 1;
25932001f49Smrg}
26032001f49Smrg
26132001f49Smrgvoid
26232001f49SmrgeglutMainLoop(void)
26332001f49Smrg{
26432001f49Smrg   struct eglut_window *win = _eglut->current;
26532001f49Smrg
26632001f49Smrg   if (!win)
26732001f49Smrg      _eglutFatal("no window is created\n");
26832001f49Smrg
26932001f49Smrg   if (win->reshape_cb)
27032001f49Smrg      win->reshape_cb(win->native.width, win->native.height);
27132001f49Smrg
27232001f49Smrg   _eglutNativeEventLoop();
27332001f49Smrg}
27432001f49Smrg
27532001f49Smrgstatic void
27632001f49Smrg_eglutFini(void)
27732001f49Smrg{
27832001f49Smrg   eglTerminate(_eglut->dpy);
27932001f49Smrg   _eglutNativeFiniDisplay();
28032001f49Smrg}
28132001f49Smrg
28232001f49Smrgvoid
28332001f49SmrgeglutDestroyWindow(int win)
28432001f49Smrg{
28532001f49Smrg   struct eglut_window *window = _eglut->current;
28632001f49Smrg
28732001f49Smrg   if (window->index != win)
28832001f49Smrg      return;
28932001f49Smrg
2907ec3b29aSmrg   eglMakeCurrent(_eglut->dpy, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
29132001f49Smrg
29232001f49Smrg   _eglutDestroyWindow(_eglut->current);
29332001f49Smrg}
29432001f49Smrg
29532001f49Smrgstatic void
29632001f49Smrg_eglutDefaultKeyboard(unsigned char key)
29732001f49Smrg{
29832001f49Smrg   if (key == 27) {
29932001f49Smrg      if (_eglut->current)
30032001f49Smrg         eglutDestroyWindow(_eglut->current->index);
30132001f49Smrg      _eglutFini();
30232001f49Smrg
30332001f49Smrg      exit(0);
30432001f49Smrg   }
30532001f49Smrg}
30632001f49Smrg
30732001f49Smrgint
30832001f49SmrgeglutCreateWindow(const char *title)
30932001f49Smrg{
31032001f49Smrg   struct eglut_window *win;
31132001f49Smrg
31232001f49Smrg   win = _eglutCreateWindow(title, 0, 0,
31332001f49Smrg         _eglut->window_width, _eglut->window_height);
31432001f49Smrg
31532001f49Smrg   win->index = _eglut->num_windows++;
31632001f49Smrg   win->reshape_cb = NULL;
31732001f49Smrg   win->display_cb = NULL;
31832001f49Smrg   win->keyboard_cb = _eglutDefaultKeyboard;
31932001f49Smrg   win->special_cb = NULL;
32032001f49Smrg
32132001f49Smrg   if (!eglMakeCurrent(_eglut->dpy, win->surface, win->surface, win->context))
32232001f49Smrg      _eglutFatal("failed to make window current");
32332001f49Smrg   _eglut->current = win;
32432001f49Smrg
32532001f49Smrg   return win->index;
32632001f49Smrg}
32732001f49Smrg
32832001f49Smrgint
32932001f49SmrgeglutGetWindowWidth(void)
33032001f49Smrg{
33132001f49Smrg   struct eglut_window *win = _eglut->current;
33232001f49Smrg   return win->native.width;
33332001f49Smrg}
33432001f49Smrg
33532001f49Smrgint
33632001f49SmrgeglutGetWindowHeight(void)
33732001f49Smrg{
33832001f49Smrg   struct eglut_window *win = _eglut->current;
33932001f49Smrg   return win->native.height;
34032001f49Smrg}
34132001f49Smrg
34232001f49Smrgvoid
34332001f49SmrgeglutDisplayFunc(EGLUTdisplayCB func)
34432001f49Smrg{
34532001f49Smrg   struct eglut_window *win = _eglut->current;
34632001f49Smrg   win->display_cb = func;
34732001f49Smrg
34832001f49Smrg}
34932001f49Smrg
35032001f49Smrgvoid
35132001f49SmrgeglutReshapeFunc(EGLUTreshapeCB func)
35232001f49Smrg{
35332001f49Smrg   struct eglut_window *win = _eglut->current;
35432001f49Smrg   win->reshape_cb = func;
35532001f49Smrg}
35632001f49Smrg
35732001f49Smrgvoid
35832001f49SmrgeglutKeyboardFunc(EGLUTkeyboardCB func)
35932001f49Smrg{
36032001f49Smrg   struct eglut_window *win = _eglut->current;
36132001f49Smrg   win->keyboard_cb = func;
36232001f49Smrg}
36332001f49Smrg
36432001f49Smrgvoid
36532001f49SmrgeglutSpecialFunc(EGLUTspecialCB func)
36632001f49Smrg{
36732001f49Smrg   struct eglut_window *win = _eglut->current;
36832001f49Smrg   win->special_cb = func;
36932001f49Smrg}
370