Example #1
0
/*
 * Add controller mappings from the specified file
 */
void S2D_AddControllerMappingsFromFile(const char *path) {
  if (!S2D_FileExists(path)) {
    S2D_Log(S2D_WARN, "Controller mappings file not found: %s", path);
    return;
  }

  int mappings_added = SDL_GameControllerAddMappingsFromFile(path);
  if (mappings_added == -1) {
    S2D_Error("SDL_GameControllerAddMappingsFromFile", SDL_GetError());
  } else {
    S2D_Log(S2D_INFO, "Added %i controller mapping(s)", mappings_added);
  }
}
Example #2
0
/*
 * Open controllers and joysticks
 */
void S2D_OpenControllers() {

  char guid_str[33];

  // Enumerate joysticks
  for (int device_index = 0; device_index < SDL_NumJoysticks(); ++device_index) {

    // Check if joystick supports SDL's game controller interface (a mapping is available)
    if (SDL_IsGameController(device_index)) {
      SDL_GameController *controller = SDL_GameControllerOpen(device_index);
      SDL_JoystickID intance_id = SDL_JoystickInstanceID(SDL_GameControllerGetJoystick(controller));

      SDL_JoystickGetGUIDString(
        SDL_JoystickGetGUID(SDL_GameControllerGetJoystick(controller)),
        guid_str, 33
      );

      if (intance_id > last_intance_id) {
        if (controller) {
          S2D_Log(S2D_INFO, "Controller #%i: %s\n      GUID: %s", intance_id, SDL_GameControllerName(controller), guid_str);
        } else {
          S2D_Log(S2D_ERROR, "Could not open controller #%i: %s", intance_id, SDL_GetError());
        }
        last_intance_id = intance_id;
      }

    // Controller interface not supported, try to open as joystick
    } else {
      SDL_Joystick *joy = SDL_JoystickOpen(device_index);
      SDL_JoystickID intance_id = SDL_JoystickInstanceID(joy);

      if (!joy) {
        S2D_Log(S2D_ERROR, "Could not open controller");
      } else if(intance_id > last_intance_id) {
        SDL_JoystickGetGUIDString(
          SDL_JoystickGetGUID(joy),
          guid_str, 33
        );
        S2D_Log(S2D_INFO,
          "Controller #%i: %s\n      GUID: %s\n      Axes: %d\n      Buttons: %d\n      Balls: %d",
          intance_id, SDL_JoystickName(joy), guid_str, SDL_JoystickNumAxes(joy),
          SDL_JoystickNumButtons(joy), SDL_JoystickNumBalls(joy)
        );
        S2D_Log(S2D_WARN, "Controller #%i does not have a mapping available", intance_id);
        last_intance_id = intance_id;
      }
    }
  }
}
Example #3
0
/*
 * Add controller mapping from string
 */
void S2D_AddControllerMapping(const char *map) {
  int result = SDL_GameControllerAddMapping(map);

  char guid[33];
  strncpy(guid, map, 32);

  switch (result) {
    case 1:
      S2D_Log(S2D_INFO, "Mapping added for GUID: %s", guid);
      break;
    case 0:
      S2D_Log(S2D_INFO, "Mapping updated for GUID: %s", guid);
      break;
    case -1:
      S2D_Error("SDL_GameControllerAddMapping", SDL_GetError());
      break;
  }
}
Example #4
0
/*
 * Print info about the current OpenGL context
 */
void S2D_GL_PrintContextInfo(S2D_Window *window) {
  S2D_Log(S2D_INFO,
    "OpenGL Context\n"
    "      GL_VENDOR: %s\n"
    "      GL_RENDERER: %s\n"
    "      GL_VERSION: %s\n"
    "      GL_SHADING_LANGUAGE_VERSION: %s",
    window->S2D_GL_VENDOR,
    window->S2D_GL_RENDERER,
    window->S2D_GL_VERSION,
    window->S2D_GL_SHADING_LANGUAGE_VERSION
  );
}
Example #5
0
/*
 * Create text
 */
Text *S2D_CreateText(const char *font, const char *msg, int size) {
  
  #if GLES
    S2D_Log("S2D_DrawText not yet implemented!", S2D_WARN);
  #endif
  
  Text *txt;

  txt = (Text *)malloc(sizeof(Text));
  if(!txt) {
    S2D_Error("S2D_CreateText", "Out of memory!");
    return NULL;
  }
  
  // `msg` cannot be an empty string; if so, return
  if (strlen(msg) == 0) {
    S2D_Error("S2D_CreateText", "Text message cannot be empty!");
    return NULL;
  } else {
    txt->msg = msg;
  }
  
  txt->x = 0;
  txt->y = 0;
  txt->color.r = 1.0;
  txt->color.g = 1.0;
  txt->color.b = 1.0;
  txt->color.a = 1.0;
  txt->texture_id = 0;
  
  txt->font = TTF_OpenFont(font, size);
  if (!txt->font) {
    S2D_Error("TTF_OpenFont", TTF_GetError());
    free(txt);
    return NULL;
  }
  
  // Save the width and height of the text
  TTF_SizeText(txt->font, txt->msg, &txt->w, &txt->h);
  
  SDL_Surface *surface;
  SDL_Color color = { 255, 255, 255 };
  surface = TTF_RenderText_Blended(txt->font, txt->msg, color);
  
  S2D_GL_SetUpTexture(&txt->texture_id, GL_RGBA, txt->w, txt->h, surface->pixels, GL_NEAREST);
  
  // Free the surface data, no longer needed
  SDL_FreeSurface(surface);
  
  return txt;
}
Example #6
0
/*
 * Close the window, clean up SDL
 */
int S2D_Close(Window *window) {
  
  S2D_Log("Closing S2D", S2D_INFO);
  
  // SDL
  IMG_Quit();
  Mix_CloseAudio();
  Mix_Quit();
  TTF_Quit();
  SDL_GL_DeleteContext(window->glcontext);
  SDL_DestroyWindow(window->sdl);
  SDL_Quit();
  
  return 0;
}
Example #7
0
/*
 * Create an image
 */
Image *S2D_CreateImage(const char *path) {
  if(!path)
      return NULL;
  // TODO: Implement images in GLES
  #if GLES
    S2D_Log("S2D_DrawImage not yet implemented!", S2D_INFO);
  #endif
  
  Image *img;
  SDL_Surface *surface;
  
  // Load image from file as SDL_Surface
  surface = IMG_Load(path);
  if (!surface) {
    S2D_Error("IMG_Load", IMG_GetError());
    return NULL;
  }

  img = (Image *)malloc(sizeof(Image));
  if(!img) {
    S2D_Error("IMG_Load", "Out of memory!");
    SDL_FreeSurface(surface);
    return NULL;
  }

  // Initialize values
  img->x = 0;
  img->y = 0;
  img->w = surface->w;
  img->h = surface->h;
  img->texture_id = 0;
  
  // Detect image mode
  // TODO: BMP is in BGR...?
  int format = GL_RGB;
  if(surface->format->BytesPerPixel == 4) {
    format = GL_RGBA;
  }
  
  S2D_GL_SetUpTexture(&img->texture_id, format, img->w, img->h, surface->pixels, GL_NEAREST);
  
  // Free the surface data, no longer needed
  SDL_FreeSurface(surface);
  
  return img;
}
Example #8
0
/*
 * Show the window
 */
int S2D_Show(Window *window) {
  
  // Setting up variables
  int mouse_x, mouse_y;  // Mouse positions
  const Uint8 *key_state;
  Uint32 frames = 0;       // Total frames since start
  Uint32 start_ms = SDL_GetTicks();  // Elapsed time since start
  Uint32 begin_ms = start_ms;  // Time at beginning of loop
  Uint32 end_ms;    // Time at end of loop
  Uint32 elapsed_ms;  // Total elapsed time
  Uint32 loop_ms;   // Elapsed time of loop
  int delay_ms;     // Amount of delay to achieve desired frame rate
  double fps;       // The actual frame rate
  
  // Enable VSync
  if (window->vsync) {
    if (!SDL_SetHint(SDL_HINT_RENDER_VSYNC, "1")) {
      S2D_Log("VSync cannot be enabled", S2D_WARN);
    }
  }
  
  // Detect Controllers and Joysticks //////////////////////////////////////////
  
  if (SDL_NumJoysticks() > 0) {
    sprintf(S2D_msg, "Joysticks detected: %i", SDL_NumJoysticks());
    S2D_Log(S2D_msg, S2D_INFO);
  }
  
  // Variables for controllers and joysticks
  SDL_GameController *controller = NULL;
  SDL_Joystick *joy = NULL;
  
  // Enumerate joysticks
  for (int i = 0; i < SDL_NumJoysticks(); ++i) {
    
    // Check to see if joystick supports SDL's game controller interface
    if (SDL_IsGameController(i)) {
      controller = SDL_GameControllerOpen(i);
      if (controller) {
        sprintf(S2D_msg, "Found a valid controller, named: %s\n",
                 SDL_GameControllerName(controller));
        S2D_Log(S2D_msg, S2D_INFO);
        break;  // Break after first available controller
      } else {
        sprintf(S2D_msg, "Could not open game controller %i: %s\n", i, SDL_GetError());
        S2D_Log(S2D_msg, S2D_ERROR);
      }
    
    // Controller interface not supported, try to open as joystick
    } else {
      sprintf(S2D_msg, "Joystick %i is not supported by the game controller interface", i);
      S2D_Log(S2D_msg, S2D_WARN);
      joy = SDL_JoystickOpen(i);
      
      // Joystick is valid
      if (joy) {
        sprintf(S2D_msg,
          "Opened Joystick %i\n"
          "Name: %s\n"
          "Axes: %d\n"
          "Buttons: %d\n"
          "Balls: %d\n",
          i, SDL_JoystickName(joy), SDL_JoystickNumAxes(joy),
          SDL_JoystickNumButtons(joy), SDL_JoystickNumBalls(joy)
        );
        S2D_Log(S2D_msg, S2D_INFO);
        
      // Joystick not valid
      } else {
        sprintf(S2D_msg, "Could not open Joystick %i", i);
        S2D_Log(S2D_msg, S2D_ERROR);
      }
      
      break;  // Break after first available joystick
    }
  }
  
  // Main Event Loop ///////////////////////////////////////////////////////////
  
  bool quit = false;
  while (!quit) {
    
    // Clear Frame /////////////////////////////////////////////////////////////
    
    S2D_GL_Clear(window->background);
    
    // Set FPS /////////////////////////////////////////////////////////////////
    
    frames++;
    end_ms = SDL_GetTicks();
    
    elapsed_ms = end_ms - start_ms;
    fps = frames / (elapsed_ms / 1000.0);
    
    loop_ms = end_ms - begin_ms;
    delay_ms = (1000 / window->fps_cap) - loop_ms;
    
    if (delay_ms < 0) delay_ms = 0;
    
    // Note: `loop_ms + delay_ms` should equal `1000 / fps_cap`
    
    SDL_Delay(delay_ms);
    begin_ms = SDL_GetTicks();
    
    // Handle Input ////////////////////////////////////////////////////////////
    
    SDL_Event e;
    while (SDL_PollEvent(&e)) {
      switch (e.type) {
        
        case SDL_KEYDOWN:
          if (window->on_key)
            window->on_key(SDL_GetScancodeName(e.key.keysym.scancode));
          break;
        
        case SDL_MOUSEBUTTONDOWN:
          if (window->on_mouse)
            window->on_mouse(e.button.x, e.button.y);
          break;
        
        case SDL_JOYAXISMOTION:
          if (window->on_controller)
            window->on_controller(true, e.jaxis.axis, e.jaxis.value, false, 0);
          break;
        
        case SDL_JOYBUTTONDOWN:
          if (window->on_controller)
            window->on_controller(false, 0, 0, true, e.jbutton.button);
          break;
        
        case SDL_WINDOWEVENT:
          switch (e.window.event) {
            case SDL_WINDOWEVENT_RESIZED:
              S2D_GL_SetView(e.window.data1, e.window.data2, window->width, window->height);
              break;
          }
          break;
        
        case SDL_QUIT:
          quit = true;
          break;
      }
    }
    
    // Detect keys held down
    int num_keys;
    key_state = SDL_GetKeyboardState(&num_keys);
    
    for (int i = 0; i < num_keys; i++) {
      if (window->on_key_down) {
        if (key_state[i] == 1) {
          window->on_key_down(SDL_GetScancodeName(i));
        }
      }
    }
    
    // Store the mouse position
    SDL_GetMouseState(&mouse_x, &mouse_y);
    
    // Update Window State /////////////////////////////////////////////////////
    
    // Store new values in the window
    window->mouse.x      = mouse_x;
    window->mouse.y      = mouse_y;
    window->mouse.real_x = mouse_x;
    window->mouse.real_y = mouse_y;
    window->frames       = frames;
    window->elapsed_ms   = elapsed_ms;
    window->loop_ms      = loop_ms;
    window->delay_ms     = delay_ms;
    window->fps          = fps;
    
    // scale the mouse position, if necessary
    if (window->s_width != window->width) {
      window->mouse.x = (int)((double)window->mouse.real_x *
        ((double)window->s_width / (double)window->width) + 0.5);
    }
    
    if (window->s_height != window->height) {
      window->mouse.y = (int)((double)window->mouse.real_y *
        ((double)window->s_height / (double)window->height) + 0.5);
    }
    
    // Call update and render callbacks
    if (window->update) window->update();
    if (window->render) window->render();
    
    // Draw Frame //////////////////////////////////////////////////////////////
    SDL_GL_SwapWindow(window->sdl);
  }
  
  return 0;
}
Example #9
0
/*
 * Logs Simple 2D errors to the console, with caller and message body
 */
void S2D_Error(const char *caller, const char *msg) {
  sprintf(S2D_msg, "(%s) %s", caller, msg);
  S2D_Log(S2D_msg, S2D_ERROR);
}
Example #10
0
/*
 * Create a window
 */
Window* S2D_CreateWindow(const char *title, int width, int height,
                         Update update, Render render, int flags) {
  
  // Allocate window and set default values
  Window *window = (Window*)malloc(sizeof(Window));
  window->title = title;
  window->width = width;
  window->height = height;
  window->fps_cap = 60;
  window->vsync = true;
  window->update = update;
  window->render = render;
  window->on_key = NULL;
  window->on_key_down = NULL;
  window->on_mouse = NULL;
  window->on_controller = NULL;
  window->background.r = 0.0;
  window->background.g = 0.0;
  window->background.b = 0.0;
  window->background.a = 1.0;
  
  // SDL Initialization ////////////////////////////////////////////////////////
  
  // Initialize SDL
  if (SDL_Init(SDL_INIT_EVERYTHING) != 0) S2D_Error("SDL_Init", SDL_GetError());
  
  // Initialize SDL_ttf
  if (TTF_Init() != 0) {
    S2D_Error("TTF_Init", TTF_GetError());
    free(window);
    return NULL;
  }
  
  // Initialize SDL_mixer
  int mix_flags = MIX_INIT_FLAC|MIX_INIT_OGG|MIX_INIT_MP3;
  int mix_initted = Mix_Init(mix_flags);
  if ((mix_initted&mix_flags) != mix_flags) {
    S2D_Error("Mix_Init", Mix_GetError());
  }
  
  int audio_rate = 44100;
  Uint16 audio_format = AUDIO_S16SYS;
  int audio_channels = 2;
  int audio_buffers = 4096;
  
  if (Mix_OpenAudio(audio_rate, MIX_DEFAULT_FORMAT, audio_channels, audio_buffers) != 0) {
    S2D_Error("Mix_OpenAudio", Mix_GetError());
    free(window);
    return NULL;
  }
  
  // Create SDL window
  window->sdl = SDL_CreateWindow(
    window->title,                                   // title
    SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED,  // window position
    window->width, window->height,                   // window size
    SDL_WINDOW_OPENGL | flags                        // flags
  );
  
  if (!window->sdl) S2D_Error("SDL_CreateWindow", SDL_GetError());
  
  // Window created by SDL might not actually be the requested size.
  // If not, retrieve and set the actual window size.
  window->s_width = window->width;
  window->s_height = window->height;
  SDL_GetWindowSize(window->sdl, &window->width, &window->height);
  
  if ((window->width != window->s_width) ||
    (window->height != window->s_height)) {
    
    sprintf(S2D_msg,
      "Resolution %dx%d unsupported by driver, scaling to %dx%d",
      window->s_width, window->s_height, window->width, window->height);
    S2D_Log(S2D_msg, S2D_WARN);
  }
  
  // Init OpenGL / GLES ////////////////////////////////////////////////////////
  
  // Specify the OpenGL Context
  #if !GLES
    if (FORCE_GL2) {
      // Use legacy OpenGL 2.1
      SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 2);
      SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 1);
    } else {
      // Request an OpenGL 3.3 forward-compatible core profile
      SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_CORE);
      SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 3);
      SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 3);
    }
  #endif
  
  // Create and store the OpenGL context
  if (FORCE_GL2) {
    window->glcontext = NULL;
  } else {
    // Ask SDL to create an OpenGL context
    window->glcontext = SDL_GL_CreateContext(window->sdl);
  }
  
  // Check if a valid OpenGL context was created
  if (window->glcontext) {
    // Valid context found
    
    #if GLES
      // Initialize OpenGL ES 2.0
      gles_init(window->width, window->height, window->s_width, window->s_height);
      
    #else
      // Initialize OpenGL 3.3+
      gl3_init(window->width, window->height);
    #endif
    
  } else {
    // Context could not be created
    
    #if GLES
      S2D_Error("GLES / SDL_GL_CreateContext", SDL_GetError());
      
    #else
      // Try to fallback using an OpenGL 2.1 context
      SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 2);
      SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 1);
      
      // Try creating the context again
      window->glcontext = SDL_GL_CreateContext(window->sdl);
      
      // Check if this context was created
      if (window->glcontext) {
        // Valid context found
        S2D_GL2 = true;
        gl2_init(window->width, window->height);
        
      } else {
        // Could not create any OpenGL contexts, hard failure
        S2D_Error("GL2 / SDL_GL_CreateContext", SDL_GetError());
        S2D_Log("An OpenGL context could not be created", S2D_ERROR);
        free(window);
        return NULL;
      }
    #endif
  }
  
  // Store the context and print it if diagnostics is enabled
  S2D_GL_StoreContextInfo(window);
  if (diagnostics) S2D_GL_PrintContextInfo(window);
  
  return window;
}
Example #11
0
/*
 * Initialize OpenGL
 */
int S2D_GL_Init(S2D_Window *window) {

  // Specify OpenGL contexts and set attributes
  #if GLES
    SDL_GL_SetAttribute(SDL_GL_RED_SIZE,   8);
    SDL_GL_SetAttribute(SDL_GL_GREEN_SIZE, 8);
    SDL_GL_SetAttribute(SDL_GL_BLUE_SIZE,  8);
    SDL_GL_SetAttribute(SDL_GL_ALPHA_SIZE, 8);
  #else
    // Use legacy OpenGL 2.1
    if (FORCE_GL2) {
      SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 2);
      SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 1);
    // Request an OpenGL 3.3 forward-compatible core profile
    } else {
      SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_CORE);
      SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 3);
      SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 3);
    }
  #endif

  // Create and store the OpenGL context
  if (FORCE_GL2) {
    window->glcontext = NULL;
  } else {
    // Ask SDL to create an OpenGL context
    window->glcontext = SDL_GL_CreateContext(window->sdl);
  }

  // Check if a valid OpenGL context was created
  if (window->glcontext) {
    // Valid context found

    // Initialize OpenGL ES 2.0
    #if GLES
      S2D_GLES_Init();
      S2D_GL_SetViewport(window);

    // Initialize OpenGL 3.3+
    #else
      // Initialize GLEW on Windows
      #if WINDOWS
        GLenum err = glewInit();
        if (GLEW_OK != err) S2D_Error("GLEW", glewGetErrorString(err));
      #endif
      S2D_GL3_Init();
      S2D_GL_SetViewport(window);
    #endif

  // Context could not be created
  } else {

    #if GLES
      S2D_Error("GLES / SDL_GL_CreateContext", SDL_GetError());

    #else
      // Try to fallback using an OpenGL 2.1 context
      SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 2);
      SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 1);

      // Try creating the context again
      window->glcontext = SDL_GL_CreateContext(window->sdl);

      // Check if this context was created
      if (window->glcontext) {
        // Valid context found
        S2D_GL2 = true;
        S2D_GL2_Init();
        S2D_GL_SetViewport(window);

      // Could not create any OpenGL contexts, hard failure
      } else {
        S2D_Error("GL2 / SDL_GL_CreateContext", SDL_GetError());
        S2D_Log(S2D_ERROR, "An OpenGL context could not be created");
        return -1;
      }
    #endif
  }

  // Store the context and print it if diagnostics is enabled
  S2D_GL_StoreContextInfo(window);
  if (S2D_diagnostics) S2D_GL_PrintContextInfo(window);

  return 0;
}
Example #12
0
/*
 * Prints current GL error
 */
void S2D_GL_PrintError(char *error) {
  S2D_Log(S2D_ERROR, "%s (%d)", error, glGetError());
}