kick
/Users/morten/Programmering/cpp/kick/src/kick/context/sdl2_context.cpp
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 }
 All Classes Functions Variables