Subversion Repositories Games.Carmageddon

Rev

Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
1 pmbaty 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
}