kick
|
00001 // 00002 // PlatformBinding.cpp 00003 // KickCPP 00004 // 00005 // Created by morten on 8/10/13. 00006 // Copyright (c) 2013 Morten Nobel-Joergensen. All rights reserved. 00007 // 00008 00009 00010 #include "kick/context/sdl2_context.h" 00011 #include "kick/core/mouse_input.h" 00012 #include "kick/core/key_input.h" 00013 #include "kick/core/engine.h" 00014 #ifndef EMSCRIPTEN 00015 #ifdef __APPLE__ 00016 #include <SDL2_image/SDL_image.h> 00017 #else 00018 #include <SDL2_image/SDL_image.h> 00019 #endif 00020 #endif 00021 00022 using namespace std; 00023 using namespace glm; 00024 00025 namespace kick { 00026 00027 00028 SDL2Context::SDL2Context(){ 00029 /* 00030 char *base_path = SDL_GetBasePath(); 00031 if (base_path) { 00032 basePath = string{base_path}; 00033 SDL_free(base_path); 00034 } else { 00035 basePath = "./"; 00036 } 00037 */ 00038 #ifndef EMSCRIPTEN 00039 SDL_version compiled; 00040 SDL_version linked; 00041 00042 SDL_VERSION(&compiled); 00043 SDL_GetVersion(&linked); 00044 if (compiled.major != linked.major || 00045 compiled.minor != linked.minor || 00046 compiled.patch != linked.patch ){ 00047 printf("Compiled against SDL version %d.%d.%d ...\n", compiled.major, compiled.minor, compiled.patch); 00048 printf("Compiled linked against SDL version %d.%d.%d.\n", linked.major, linked.minor, linked.patch); 00049 } else { 00050 printf("SDL version: %d.%d.%d\n", compiled.major, compiled.minor, compiled.patch); 00051 } 00052 #endif 00053 00054 basePath = "./"; 00055 } 00056 00057 SDL2Context::~SDL2Context(){ 00058 if (glContext){ 00059 SDL_GL_DeleteContext(glContext); 00060 } 00061 #ifndef EMSCRIPTEN 00062 if (window){ 00063 SDL_DestroyWindow(window); 00064 } 00065 #endif 00066 SDL_Quit(); 00067 00068 } 00069 00070 bool SDL2Context::init(int &argc, char **argv){ 00071 #ifndef EMSCRIPTEN 00072 SDL_SetMainReady(); 00073 #endif 00074 bool res = SDL_Init(SDL_INIT_EVERYTHING) >= 0; 00075 00076 #ifndef EMSCRIPTEN 00077 if (SDL_IsScreenSaverEnabled()){ 00078 SDL_DisableScreenSaver(); 00079 } 00080 #endif 00081 00082 return res; 00083 } 00084 00085 bool SDL2Context::showWindow(const WindowConfig& config){ 00086 const char *windowName = config.name.c_str(); 00087 int width = config.width; 00088 int height = config.height; 00089 int depthSize = config.depthBufferSize; 00090 00091 00092 if (depthSize>0){ 00093 /* Turn on double buffering with a 24bit Z buffer. 00094 * You may need to change this to 16 or 32 for your system */ 00095 SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1); 00096 SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, depthSize); 00097 } 00098 00099 00100 #ifdef EMSCRIPTEN 00101 SDL_Surface *screen = SDL_SetVideoMode(width, height, 32, SDL_OPENGL); 00102 window = nullptr; 00103 #else 00104 /* Request opengl 3.2 context. 00105 * SDL doesn't have the ability to choose which profile at this time of writing, 00106 * but it should default to the core profile */ 00107 00108 #ifdef KICK_CONTEXT_ES2 00109 SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 3); 00110 SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 2); 00111 SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_ES); 00112 #else 00113 if (config.multisamples>1) { 00114 SDL_GL_SetAttribute(SDL_GL_MULTISAMPLEBUFFERS, 1); 00115 SDL_GL_SetAttribute(SDL_GL_MULTISAMPLESAMPLES, config.multisamples); 00116 } 00117 SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 3); 00118 SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 2); 00119 00120 SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK,SDL_GL_CONTEXT_PROFILE_CORE); 00121 #endif 00122 00123 /* Create our window centered at 512x512 resolution */ 00124 window = SDL_CreateWindow(windowName, SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, 00125 width, height, SDL_WINDOW_OPENGL | SDL_WINDOW_SHOWN | SDL_WINDOW_RESIZABLE); 00126 00127 if (!window) 00128 return false; 00129 00130 #ifndef EMSCRIPTEN 00131 SDL_Surface * iconSurface = IMG_Load("assets/ui/icon.png"); 00132 if (iconSurface){ 00133 // The icon is attached to the window pointer 00134 SDL_SetWindowIcon(window, iconSurface); 00135 SDL_FreeSurface(iconSurface); 00136 } 00137 #endif 00138 00139 glContext = SDL_GL_CreateContext(window); 00140 00141 #ifdef _WIN32 00142 //Initialize GLEW 00143 glewExperimental = GL_TRUE; 00144 GLenum glewError = glewInit(); 00145 if (glewError != GLEW_OK) 00146 { 00147 printf("Error initializing GLEW! %s\n", glewGetErrorString(glewError)); 00148 } 00149 #endif 00150 00151 if (!glContext) 00152 return false; 00153 00154 int w,h; 00155 SDL_GL_GetDrawableSize(window, &w, &h); 00156 contextSurfaceDim = glm::ivec2(w, h); 00157 00158 #endif 00159 return true; 00160 } 00161 00162 void SDL2Context::swapBuffer(){ 00163 SDL_GL_SwapWindow(window); 00164 } 00165 00166 void SDL2Context::step(){ 00167 Engine::update(); 00168 Engine::render(); 00169 } 00170 00171 bool SDL2Context::tick(){ 00172 #ifdef EMSCRIPTEN 00173 // ugly hack - checks size each frame (since no events is fired) 00174 int w, h; 00175 SDL_GetWindowSize(window, &w, &h); 00176 if (contextSurfaceDim.x != w || contextSurfaceDim.y != h){ 00177 contextSurfaceDim.x = w; 00178 contextSurfaceDim.y = h; 00179 contextSurfaceSize.notifyListeners(contextSurfaceDim); 00180 } 00181 #endif 00182 bool quit = false; 00183 SDL_Event event; 00184 Engine::startFrame(); 00185 while(SDL_PollEvent(&event)) 00186 { 00187 switch (event.type) { 00188 case SDL_QUIT: 00189 quit = 1; 00190 break; 00191 case SDL_WINDOWEVENT: 00192 if (event.window.event == SDL_WINDOWEVENT_SIZE_CHANGED || event.window.event == SDL_WINDOWEVENT_RESIZED ){ 00193 if (contextSurfaceDim.x != event.window.data1 || contextSurfaceDim.y != event.window.data2){ 00194 contextSurfaceDim.x = event.window.data1; 00195 contextSurfaceDim.y = event.window.data2; 00196 contextSurfaceSize.notifyListeners(contextSurfaceDim); 00197 } 00198 } 00199 break; 00200 #ifndef EMSCRIPTEN 00201 case SDL_APP_TERMINATING: 00205 break; 00206 case SDL_APP_LOWMEMORY: 00210 break; 00211 case SDL_APP_WILLENTERBACKGROUND: 00215 break; 00216 case SDL_APP_DIDENTERBACKGROUND: 00220 break; 00221 case SDL_APP_WILLENTERFOREGROUND: 00225 break; 00226 case SDL_APP_DIDENTERFOREGROUND: 00230 break; 00231 case SDL_SYSWMEVENT: 00232 break; 00233 #endif 00234 case SDL_KEYDOWN: 00235 handleKey(event.key, true); 00236 break; 00237 case SDL_KEYUP: 00238 handleKey(event.key, false); 00239 break; 00240 case SDL_TEXTEDITING: 00241 break; 00242 case SDL_TEXTINPUT: 00243 break; 00244 case SDL_MOUSEMOTION: 00245 handleMouseMotion(event.motion); 00246 break; 00247 case SDL_MOUSEBUTTONDOWN: 00248 handleMouseButton(event.button, true); 00249 break; 00250 case SDL_MOUSEBUTTONUP: 00251 handleMouseButton(event.button, false); 00252 break; 00253 case SDL_MOUSEWHEEL: 00254 handleMouseWheel(event.wheel); 00255 break; 00256 case SDL_FINGERDOWN: /* Touch events */ 00257 handleTouch(event.tfinger); 00258 break; 00259 case SDL_FINGERUP: 00260 handleTouch(event.tfinger); 00261 break; 00262 case SDL_FINGERMOTION: 00263 handleTouch(event.tfinger); 00264 break; 00265 #ifndef EMSCRIPTEN 00266 case SDL_JOYAXISMOTION: 00267 break; 00268 case SDL_JOYBALLMOTION: 00269 break; 00270 case SDL_JOYHATMOTION: 00271 break; 00272 case SDL_JOYBUTTONDOWN: 00273 break; 00274 case SDL_JOYBUTTONUP: 00275 break; 00276 case SDL_JOYDEVICEADDED: 00277 break; 00278 case SDL_JOYDEVICEREMOVED: 00279 break; 00280 case SDL_CONTROLLERAXISMOTION: 00281 break; 00282 case SDL_CONTROLLERBUTTONDOWN: 00283 break; 00284 case SDL_CONTROLLERBUTTONUP: 00285 break; 00286 case SDL_CONTROLLERDEVICEADDED: 00287 break; 00288 case SDL_CONTROLLERDEVICEREMOVED: 00289 break; 00290 case SDL_CONTROLLERDEVICEREMAPPED: 00291 break; 00292 case SDL_DOLLARGESTURE: /* Gesture events */ 00293 break; 00294 case SDL_DOLLARRECORD: 00295 break; 00296 case SDL_MULTIGESTURE: 00297 break; 00298 case SDL_CLIPBOARDUPDATE: 00299 break; 00300 case SDL_DROPFILE: 00301 break; 00302 00303 #endif 00304 default: 00305 // unhandled 00306 cout << "Unhandled event "<< event.type << endl; 00307 break; 00308 } 00309 } 00310 step(); 00311 return quit; 00312 } 00313 00314 #ifdef EMSCRIPTEN 00315 void kick_emscripten_tick(){ 00316 SDL2Context *c = (SDL2Context*)Engine::context(); 00317 c->tick(); 00318 } 00319 #endif 00320 00321 void SDL2Context::mainLoop(){ 00322 #ifdef EMSCRIPTEN 00323 int fps = 0; // 0 is RequestAnimFrame 00324 int simulate_infinite_loop = 1; 00325 emscripten_set_main_loop(kick_emscripten_tick, fps, simulate_infinite_loop); 00326 #else 00327 /* An SDL_Event */ 00328 bool quit = false; 00329 nextTime = SDL_GetTicks() + tickInterval; 00330 while (!quit) { 00331 quit = tick(); 00332 SDL_Delay(timeLeft()); 00333 nextTime += tickInterval; 00334 } 00335 #endif 00336 } 00337 00338 Uint32 SDL2Context::timeLeft(){ 00339 Uint32 now; 00340 00341 now = SDL_GetTicks(); 00342 if(nextTime <= now) 00343 return 0; 00344 else 00345 return nextTime - now; 00346 } 00347 00348 std::string SDL2Context::getBasePath(){ 00349 return basePath; 00350 } 00351 00352 void SDL2Context::handleKey(SDL_KeyboardEvent event, bool keyDown){ 00353 Key key = static_cast<Key>(event.keysym.sym); 00354 if (keyDown){ 00355 if (event.repeat){ 00356 return; 00357 } 00358 KeyInput::pressBegin(key); 00359 } else { 00360 KeyInput::pressEnd(key); 00361 } 00362 } 00363 void SDL2Context::handleMouseMotion(SDL_MouseMotionEvent event){ 00364 MouseInput::setPosition(ivec2(event.x,event.y)); 00365 MouseInput::setPositionDelta(ivec2(event.xrel,event.yrel)); 00366 } 00367 00368 void SDL2Context::handleMouseButton(SDL_MouseButtonEvent event, bool buttonDown){ 00369 if (buttonDown){ 00370 MouseInput::buttonPressStarted(event.button-1); 00371 } else { 00372 MouseInput::buttonPressEnded(event.button-1); 00373 } 00374 #ifndef EMSCRIPTEN 00375 MouseInput::setClicks(event.clicks); 00376 #endif 00377 } 00378 00379 void SDL2Context::handleMouseWheel(SDL_MouseWheelEvent event){ 00380 MouseInput::setMouseWheelDelta(ivec2(event.x, event.y)); 00381 } 00382 00383 bool SDL2Context::isFullscreen() { 00384 return ((SDL_GetWindowFlags(window)&(SDL_WINDOW_FULLSCREEN|SDL_WINDOW_FULLSCREEN_DESKTOP)) != 0); 00385 } 00386 00387 void SDL2Context::setFullscreen(bool fullscreen) { 00388 #ifndef EMSCRIPTEN 00389 if (isFullscreen() != fullscreen){ 00390 Uint32 flags = (SDL_GetWindowFlags(window) ^ SDL_WINDOW_FULLSCREEN_DESKTOP); 00391 if (SDL_SetWindowFullscreen(window, flags) < 0) // NOTE: this takes FLAGS as the second param, NOT true/false! 00392 { 00393 std::cout << "Toggling fullscreen mode failed: " << SDL_GetError() << std::endl; 00394 return; 00395 } 00396 } 00397 #endif 00398 } 00399 00400 void SDL2Context::setWindowTitle(std::string title) { 00401 #ifndef EMSCRIPTEN 00402 SDL_SetWindowTitle(window, title.c_str()); 00403 #endif 00404 } 00405 00406 std::string SDL2Context::getWindowTitle() { 00407 #ifndef EMSCRIPTEN 00408 string title{SDL_GetWindowTitle(window)}; 00409 return title; 00410 #else 00411 return ""; 00412 #endif 00413 } 00414 00415 void SDL2Context::handleTouch(SDL_TouchFingerEvent event) { 00416 ivec2 pos{(int)round(contextSurfaceDim.x * event.x), (int)round(contextSurfaceDim.y * event.y)}; 00417 switch (event.type){ 00418 case SDL_FINGERDOWN: 00419 TouchInput::setTouchStarted(event.fingerId, pos, event.pressure); 00420 break; 00421 case SDL_FINGERMOTION: 00422 TouchInput::setTouchMoved(event.fingerId, pos, event.pressure); 00423 break; 00424 case SDL_FINGERUP: 00425 TouchInput::setTouchEnded(event.fingerId, pos); 00426 break; 00427 default: 00428 cout << "Unknown event type "<<event.type<<endl; 00429 } 00430 } 00431 00432 }