You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 

301 line
7.5 KiB

  1. //
  2. // Lol Engine
  3. //
  4. // Copyright: (c) 2010-2011 Sam Hocevar <sam@hocevar.net>
  5. // This program is free software; you can redistribute it and/or
  6. // modify it under the terms of the Do What The Fuck You Want To
  7. // Public License, Version 2, as published by Sam Hocevar. See
  8. // http://sam.zoy.org/projects/COPYING.WTFPL for more details.
  9. //
  10. #if defined HAVE_CONFIG_H
  11. # include "config.h"
  12. #endif
  13. #if defined USE_EGL && !defined __ANDROID__
  14. # if defined HAVE_BCM_HOST_H
  15. # include <bcm_host.h>
  16. # else
  17. # include <X11/Xlib.h>
  18. # include <X11/Xatom.h>
  19. # include <X11/Xutil.h>
  20. # endif
  21. # include <EGL/egl.h>
  22. # include <EGL/eglext.h>
  23. #endif
  24. #if defined USE_SDL
  25. # if defined HAVE_SDL_SDL_H
  26. # include <SDL/SDL.h>
  27. # else
  28. # include <SDL.h>
  29. # endif
  30. #endif
  31. #include "core.h"
  32. #include "lolgl.h"
  33. #include "eglapp.h"
  34. #if defined USE_SDL
  35. # include "platform/sdl/sdlinput.h"
  36. #endif
  37. namespace lol
  38. {
  39. /*
  40. * EGL App implementation class
  41. */
  42. class EglAppData
  43. {
  44. friend class EglApp;
  45. private:
  46. #if defined USE_EGL && !defined __ANDROID__
  47. EGLDisplay egl_dpy;
  48. EGLContext egl_ctx;
  49. EGLSurface egl_surf;
  50. uvec2 screen_size;
  51. # if defined HAVE_BCM_HOST_H
  52. EGL_DISPMANX_WINDOW_T nativewindow;
  53. # else
  54. Display *dpy;
  55. Window win;
  56. # endif
  57. #endif
  58. };
  59. /*
  60. * Public EglApp class
  61. */
  62. EglApp::EglApp(char const *title, ivec2 res, float fps) :
  63. data(new EglAppData())
  64. {
  65. #if defined USE_EGL && !defined __ANDROID__
  66. # if defined HAVE_BCM_HOST_H
  67. bcm_host_init();
  68. data->egl_dpy = eglGetDisplay(EGL_DEFAULT_DISPLAY);
  69. # else
  70. data->dpy = XOpenDisplay(NULL);
  71. if (data->dpy == NULL)
  72. {
  73. Log::Error("cannot connect to X server\n");
  74. exit(EXIT_FAILURE);
  75. }
  76. Window root = DefaultRootWindow(data->dpy);
  77. XSetWindowAttributes swa;
  78. swa.event_mask = ExposureMask | PointerMotionMask | KeyPressMask;
  79. data->win = XCreateWindow(data->dpy, root, 0, 0, res.x, res.y, 0,
  80. CopyFromParent, InputOutput,
  81. CopyFromParent, CWEventMask, &swa);
  82. XSetWindowAttributes xattr;
  83. xattr.override_redirect = False;
  84. XChangeWindowAttributes(data->dpy, data->win, CWOverrideRedirect, &xattr);
  85. XWMHints hints;
  86. hints.flags = InputHint;
  87. hints.input = True;
  88. XSetWMHints(data->dpy, data->win, &hints);
  89. XMapWindow(data->dpy, data->win);
  90. XStoreName(data->dpy, data->win, title);
  91. data->egl_dpy = eglGetDisplay((EGLNativeDisplayType)data->dpy);
  92. # endif
  93. if (data->egl_dpy == EGL_NO_DISPLAY)
  94. {
  95. Log::Error("cannot get EGL display\n");
  96. exit(EXIT_FAILURE);
  97. }
  98. if (!eglInitialize(data->egl_dpy, NULL, NULL))
  99. {
  100. Log::Error("cannot initialize EGL\n");
  101. exit(EXIT_FAILURE);
  102. }
  103. EGLint attr[] =
  104. {
  105. EGL_BUFFER_SIZE, 16,
  106. EGL_DEPTH_SIZE, 16,
  107. EGL_RED_SIZE, 4,
  108. EGL_GREEN_SIZE, 4,
  109. EGL_BLUE_SIZE, 4,
  110. EGL_ALPHA_SIZE, 4,
  111. #if defined HAVE_GLES_2X
  112. EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT,
  113. #endif
  114. EGL_NONE
  115. };
  116. EGLConfig ecfg;
  117. EGLint num_config;
  118. if (!eglChooseConfig(data->egl_dpy, attr, &ecfg, 1, &num_config))
  119. {
  120. Log::Error("cannot choose EGL config (%i)\n", eglGetError());
  121. exit(EXIT_FAILURE);
  122. }
  123. if (num_config != 1)
  124. {
  125. Log::Error("cannot choose between %i EGL configs\n", num_config);
  126. exit(EXIT_FAILURE);
  127. }
  128. if (!eglBindAPI(EGL_OPENGL_ES_API))
  129. {
  130. Log::Error("cannot bind OpenGL ES API (%i)\n", eglGetError());
  131. exit(EXIT_FAILURE);
  132. }
  133. # if defined HAVE_BCM_HOST_H
  134. DISPMANX_ELEMENT_HANDLE_T dispman_element;
  135. DISPMANX_DISPLAY_HANDLE_T dispman_display;
  136. DISPMANX_UPDATE_HANDLE_T dispman_update;
  137. VC_RECT_T dst_rect;
  138. VC_RECT_T src_rect;
  139. graphics_get_display_size(0 /* LCD */, &data->screen_size.x, &data->screen_size.y);
  140. dst_rect.x = 0;
  141. dst_rect.y = 0;
  142. dst_rect.width = data->screen_size.x;
  143. dst_rect.height = data->screen_size.y;
  144. src_rect.x = 0;
  145. src_rect.y = 0;
  146. src_rect.width = data->screen_size.x << 16;
  147. src_rect.height = data->screen_size.y << 16;
  148. dispman_display = vc_dispmanx_display_open(0 /* LCD */);
  149. dispman_update = vc_dispmanx_update_start(0);
  150. dispman_element = vc_dispmanx_element_add(dispman_update, dispman_display,
  151. 0/*layer*/, &dst_rect, 0/*src*/, &src_rect, DISPMANX_PROTECTION_NONE,
  152. 0 /*alpha*/, 0/*clamp*/, (DISPMANX_TRANSFORM_T)0/*transform*/);
  153. data->nativewindow.element = dispman_element;
  154. data->nativewindow.width = data->screen_size.x;
  155. data->nativewindow.height = data->screen_size.y;
  156. vc_dispmanx_update_submit_sync(dispman_update);
  157. data->egl_surf = eglCreateWindowSurface(data->egl_dpy, ecfg,
  158. &data->nativewindow, NULL);
  159. # else
  160. data->egl_surf = eglCreateWindowSurface(data->egl_dpy, ecfg,
  161. (EGLNativeWindowType)data->win,
  162. NULL);
  163. # endif
  164. if (data->egl_surf == EGL_NO_SURFACE)
  165. {
  166. switch (eglGetError())
  167. {
  168. case EGL_BAD_DISPLAY:
  169. Log::Error("missing EGL display connection\n");
  170. break;
  171. case EGL_NOT_INITIALIZED:
  172. Log::Error("EGL display not initialized\n");
  173. break;
  174. case EGL_BAD_CONFIG:
  175. Log::Error("invalid EGL configuration\n");
  176. break;
  177. case EGL_BAD_NATIVE_WINDOW:
  178. Log::Error("invalid EGL native window\n");
  179. break;
  180. case EGL_BAD_ATTRIBUTE:
  181. Log::Error("invalid EGL window attribute\n");
  182. break;
  183. case EGL_BAD_ALLOC:
  184. Log::Error("cannot allocate EGL surface\n");
  185. break;
  186. case EGL_BAD_MATCH:
  187. Log::Error("unsupported EGL window\n");
  188. break;
  189. default:
  190. Log::Error("cannot create EGL surface (%i)\n", eglGetError());
  191. break;
  192. }
  193. exit(EXIT_FAILURE);
  194. }
  195. EGLint ctxattr[] =
  196. {
  197. #if defined HAVE_GLES_2X
  198. EGL_CONTEXT_CLIENT_VERSION, 2,
  199. #endif
  200. EGL_NONE
  201. };
  202. data->egl_ctx = eglCreateContext(data->egl_dpy, ecfg,
  203. EGL_NO_CONTEXT, ctxattr);
  204. if (data->egl_ctx == EGL_NO_CONTEXT)
  205. {
  206. Log::Error("cannot create EGL context (%i)\n", eglGetError());
  207. exit(EXIT_FAILURE);
  208. }
  209. eglMakeCurrent(data->egl_dpy, data->egl_surf,
  210. data->egl_surf, data->egl_ctx);
  211. # if !defined HAVE_BCM_HOST_H
  212. XWindowAttributes gwa;
  213. XGetWindowAttributes(data->dpy, data->win, &gwa);
  214. data->screen_size = ivec2(gwa.width, gwa.height);
  215. # endif
  216. # if defined USE_SDL
  217. new SdlInput();
  218. # endif
  219. /* Initialise everything */
  220. Ticker::Setup(fps);
  221. Video::Setup((ivec2)data->screen_size);
  222. Audio::Setup(2);
  223. #endif
  224. }
  225. void EglApp::ShowPointer(bool show)
  226. {
  227. /* FIXME: unimplemented (do we have a mouse pointer anyway? */
  228. (void)show;
  229. }
  230. void EglApp::Run()
  231. {
  232. while (!Ticker::Finished())
  233. {
  234. /* Tick the renderer, show the frame and clamp to desired framerate. */
  235. Ticker::TickDraw();
  236. #if defined USE_EGL && !defined __ANDROID__
  237. eglSwapBuffers(data->egl_dpy, data->egl_surf);
  238. #endif
  239. }
  240. }
  241. EglApp::~EglApp()
  242. {
  243. #if defined USE_EGL && !defined __ANDROID__
  244. eglDestroyContext(data->egl_dpy, data->egl_ctx);
  245. eglDestroySurface(data->egl_dpy, data->egl_surf);
  246. eglTerminate(data->egl_dpy);
  247. # if defined HAVE_BCM_HOST_H
  248. /* FIXME */
  249. # else
  250. XDestroyWindow(data->dpy, data->win);
  251. XCloseDisplay(data->dpy);
  252. # endif
  253. #endif
  254. delete data;
  255. }
  256. } /* namespace lol */