Subversion Repositories Games.Carmageddon

Rev

Blame | Last modification | View Log | Download | RSS feed

  1. #include <glad/glad.h>
  2.  
  3. // this needs to be included after glad.h
  4. #include <SDL.h>
  5. #include <SDL_opengl.h>
  6.  
  7. #include "../renderers/gl/gl_renderer.h"
  8. #include "harness/config.h"
  9. #include "harness/hooks.h"
  10. #include "harness/trace.h"
  11. #include "sdl2_scancode_to_dinput.h"
  12.  
  13. #include "globvars.h"
  14. #include "grafdata.h"
  15. #include "pd/sys.h"
  16.  
  17. SDL_Window* window;
  18. SDL_GLContext context;
  19. uint8_t directinput_key_state[SDL_NUM_SCANCODES];
  20. int render_width, render_height;
  21. int window_width, window_height;
  22. int vp_x, vp_y, vp_width, vp_height;
  23.  
  24. static const int scalefactor = 2; // Pierre-Marie Baty -- scale factor addition
  25.  
  26. struct {
  27.     float x;
  28.     float y;
  29. } sdl_window_scale;
  30.  
  31. static void update_viewport(void) {
  32.     const float target_aspect_ratio = (float)render_width / render_height;
  33.     const float aspect_ratio = (float)window_width / window_height;
  34.  
  35.     vp_width = window_width;
  36.     vp_height = window_height;
  37.     if (aspect_ratio != target_aspect_ratio) {
  38.         if (aspect_ratio > target_aspect_ratio) {
  39.             vp_width = window_height * target_aspect_ratio + .5f;
  40.         } else {
  41.             vp_height = window_width / target_aspect_ratio + .5f;
  42.         }
  43.     }
  44.     vp_x = (window_width - vp_width) / 2;
  45.     vp_y = (window_height - vp_height) / 2;
  46.     GLRenderer_SetViewport(vp_x, vp_y, vp_width, vp_height);
  47. }
  48.  
  49. static void* create_window_and_renderer(char* title, int x, int y, int width, int height) {
  50.  
  51.     window_width = width;
  52.     window_height = height;
  53.     render_width = width;
  54.     render_height = height;
  55.  
  56.     if (SDL_Init(SDL_INIT_VIDEO) != 0) {
  57.         LOG_PANIC("SDL_INIT_VIDEO error: %s", SDL_GetError());
  58.     }
  59.  
  60.     if (SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_CORE) != 0) {
  61.         LOG_PANIC("Failed to set SDL_GL_CONTEXT_PROFILE_MASK attribute. %s", SDL_GetError());
  62.     };
  63.     SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 3);
  64.     SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 1);
  65.  
  66.     SDL_GL_SetSwapInterval(1);
  67.  
  68.     window = SDL_CreateWindow(title,
  69.         SDL_WINDOWPOS_CENTERED,
  70.         SDL_WINDOWPOS_CENTERED,
  71.         scalefactor * width, scalefactor * height, // Pierre-Marie Baty -- scale factor addition
  72.         SDL_WINDOW_OPENGL | SDL_WINDOW_RESIZABLE);
  73.  
  74.     if (window == NULL) {
  75.         LOG_PANIC("Failed to create window. %s", SDL_GetError());
  76.     }
  77.  
  78.     sdl_window_scale.x = ((float)render_width) / (scalefactor * width); // Pierre-Marie Baty -- scale factor addition
  79.     sdl_window_scale.y = ((float)render_height) / (scalefactor * height); // Pierre-Marie Baty -- scale factor addition
  80.  
  81.     if (harness_game_config.start_full_screen) {
  82.         SDL_SetWindowFullscreen(window, SDL_WINDOW_FULLSCREEN_DESKTOP);
  83.     }
  84.  
  85.     context = SDL_GL_CreateContext(window);
  86.     if (!context) {
  87.         LOG_PANIC("Failed to call SDL_GL_CreateContext. %s", SDL_GetError());
  88.     }
  89.  
  90.     // Load GL extensions using glad
  91.     if (!gladLoadGLLoader((GLADloadproc)SDL_GL_GetProcAddress)) {
  92.         LOG_PANIC("Failed to initialize the OpenGL context with GLAD.");
  93.         exit(1);
  94.     }
  95.  
  96.     GLRenderer_Init(render_width, render_height);
  97.     update_viewport();
  98.  
  99.     return window;
  100. }
  101.  
  102. static int set_window_pos(void* hWnd, int x, int y, int nWidth, int nHeight) {
  103.     // SDL_SetWindowPosition(hWnd, x, y);
  104. //    if (nWidth == 320 && nHeight == 200) {
  105.         nWidth = scalefactor * nWidth; // Pierre-Marie Baty -- scale factor addition
  106.         nHeight = scalefactor * nHeight - 1; // Pierre-Marie Baty -- scale factor addition. FIXME: find out why the minus one is necessary.
  107. //    }
  108.     SDL_SetWindowSize(hWnd, nWidth, nHeight);
  109.     return 0;
  110. }
  111.  
  112. static void destroy_window(void* hWnd) {
  113.     SDL_GL_DeleteContext(context);
  114.     SDL_DestroyWindow(window);
  115.     SDL_Quit();
  116.     window = NULL;
  117. }
  118.  
  119. // Checks whether the `flag_check` is the only modifier applied.
  120. // e.g. is_only_modifier(event.key.keysym.mod, KMOD_ALT) returns true when only the ALT key was pressed
  121. static int is_only_key_modifier(int modifier_flags, int flag_check) {
  122.     return (modifier_flags & flag_check) && (modifier_flags & (KMOD_CTRL | KMOD_SHIFT | KMOD_ALT | KMOD_GUI)) == (modifier_flags & flag_check);
  123. }
  124.  
  125. static int get_and_handle_message(MSG_* msg) {
  126.     SDL_Event event;
  127.     int dinput_key;
  128.  
  129.     while (SDL_PollEvent(&event)) {
  130.         switch (event.type) {
  131.         case SDL_KEYDOWN:
  132.         case SDL_KEYUP:
  133.             if (event.key.keysym.sym == SDLK_RETURN) {
  134.                 if (event.key.type == SDL_KEYDOWN) {
  135.                     if ((event.key.keysym.mod & (KMOD_CTRL | KMOD_SHIFT | KMOD_ALT | KMOD_GUI))) {
  136.                         // Ignore keydown of RETURN when used together with some modifier
  137.                         return 0;
  138.                     }
  139.                 } else if (event.key.type == SDL_KEYUP) {
  140.                     if (is_only_key_modifier(event.key.keysym.mod, KMOD_ALT)) {
  141.                         SDL_SetWindowFullscreen(window, (SDL_GetWindowFlags(window) & SDL_WINDOW_FULLSCREEN_DESKTOP) ? 0 : SDL_WINDOW_FULLSCREEN_DESKTOP);
  142.                     }
  143.                 }
  144.             }
  145.  
  146.             // Map incoming SDL scancode to DirectInput DIK_* key code.
  147.             // https://github.com/DanielGibson/Snippets/blob/master/sdl2_scancode_to_dinput.h
  148.             dinput_key = sdlScanCodeToDirectInputKeyNum[event.key.keysym.scancode];
  149.             if (dinput_key == 0) {
  150.                 LOG_WARN("unexpected scan code %s (%d)", SDL_GetScancodeName(event.key.keysym.scancode), event.key.keysym.scancode);
  151.                 return 0;
  152.             }
  153.             // DInput expects high bit to be set if key is down
  154.             // https://learn.microsoft.com/en-us/previous-versions/windows/desktop/ee418261(v=vs.85)
  155.             directinput_key_state[dinput_key] = (event.type == SDL_KEYDOWN ? 0x80 : 0);
  156.             break;
  157.  
  158.         case SDL_WINDOWEVENT:
  159.             switch (event.window.event) {
  160.             case SDL_WINDOWEVENT_SIZE_CHANGED:
  161.                 SDL_GetWindowSize(window, &window_width, &window_height);
  162.                 update_viewport();
  163.                 sdl_window_scale.x = (float)render_width / vp_width;
  164.                 sdl_window_scale.y = (float)render_height / vp_height;
  165.                 break;
  166.             }
  167.             break;
  168.  
  169.         case SDL_QUIT:
  170.             msg->message = WM_QUIT;
  171.             return 1;
  172.         }
  173.     }
  174.     return 0;
  175. }
  176.  
  177. static void swap_window(void) {
  178.     SDL_GL_SwapWindow(window);
  179. }
  180.  
  181. static void get_keyboard_state(unsigned int count, uint8_t* buffer) {
  182.     memcpy(buffer, directinput_key_state, count);
  183. }
  184.  
  185. static int get_mouse_buttons(int* pButton1, int* pButton2) {
  186.     int state = SDL_GetMouseState(NULL, NULL);
  187.     *pButton1 = state & SDL_BUTTON_LMASK;
  188.     *pButton2 = state & SDL_BUTTON_RMASK;
  189.     return 0;
  190. }
  191.  
  192. static int get_mouse_position(int* pX, int* pY) {
  193.     SDL_GetMouseState(pX, pY);
  194.  
  195.     if (*pX < vp_x) {
  196.         *pX = vp_x;
  197.     } else if (*pX >= vp_x + vp_width) {
  198.         *pX = vp_x + vp_width - 1;
  199.     }
  200.     if (*pY < vp_y) {
  201.         *pY = vp_y;
  202.     } else if (*pY >= vp_y + vp_height) {
  203.         *pY = vp_y + vp_height - 1;
  204.     }
  205.     *pX -= vp_x;
  206.     *pY -= vp_y;
  207.     *pX *= sdl_window_scale.x;
  208.     *pY *= sdl_window_scale.y;
  209.  
  210. #if defined(DETHRACE_FIX_BUGS)
  211.     // In hires mode (640x480), the menus are still rendered at (320x240),
  212.     // so prescale the cursor coordinates accordingly.
  213.     *pX *= gGraf_specs[gGraf_data_index].phys_width;
  214.     *pX /= gGraf_specs[gReal_graf_data_index].phys_width;
  215.     *pY *= gGraf_specs[gGraf_data_index].phys_height;
  216.     *pY /= gGraf_specs[gReal_graf_data_index].phys_height;
  217. #endif
  218.     return 0;
  219. }
  220.  
  221. static void set_palette(PALETTEENTRY_* pal) {
  222.     GLRenderer_SetPalette((uint8_t*)pal);
  223. }
  224.  
  225. int show_error_message(void* window, char* text, char* caption) {
  226.     fprintf(stderr, "%s", text);
  227.     SDL_ShowSimpleMessageBox(SDL_MESSAGEBOX_ERROR, caption, text, window);
  228.     return 0;
  229. }
  230.  
  231. void Harness_Platform_Init(tHarness_platform* platform) {
  232.     platform->ProcessWindowMessages = get_and_handle_message;
  233.     platform->Sleep = SDL_Delay;
  234.     platform->GetTicks = SDL_GetTicks;
  235.     platform->CreateWindowAndRenderer = create_window_and_renderer;
  236.     platform->ShowCursor = SDL_ShowCursor;
  237.     platform->SetWindowPos = set_window_pos;
  238.     platform->SwapWindow = swap_window;
  239.     platform->DestroyWindow = destroy_window;
  240.     platform->GetKeyboardState = get_keyboard_state;
  241.     platform->GetMousePosition = get_mouse_position;
  242.     platform->GetMouseButtons = get_mouse_buttons;
  243.     platform->DestroyWindow = destroy_window;
  244.     platform->ShowErrorMessage = show_error_message;
  245.  
  246.     platform->Renderer_BufferModel = GLRenderer_BufferModel;
  247.     platform->Renderer_BufferMaterial = GLRenderer_BufferMaterial;
  248.     platform->Renderer_BufferTexture = GLRenderer_BufferTexture;
  249.     platform->Renderer_SetPalette = set_palette;
  250.     platform->Renderer_FullScreenQuad = GLRenderer_FullScreenQuad;
  251.     platform->Renderer_Model = GLRenderer_Model;
  252.     platform->Renderer_ClearBuffers = GLRenderer_ClearBuffers;
  253.     platform->Renderer_FlushBuffers = GLRenderer_FlushBuffers;
  254.     platform->Renderer_BeginScene = GLRenderer_BeginScene;
  255.     platform->Renderer_EndScene = GLRenderer_EndScene;
  256.     platform->Renderer_SetViewport = GLRenderer_SetViewport;
  257. }
  258.