Subversion Repositories Games.Carmageddon

Rev

Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
18 pmbaty 1
#include <SDL.h>
2
 
3
#include "harness.h"
4
#include "harness/config.h"
5
#include "harness/hooks.h"
6
#include "harness/trace.h"
7
#include "sdl2_scancode_to_dinput.h"
8
 
9
#include "globvars.h"
10
#include "grafdata.h"
11
#include "pd/sys.h"
12
 
13
SDL_Window* window;
14
SDL_Renderer* renderer;
15
SDL_Texture* screen_texture;
16
uint32_t converted_palette[256];
17
br_pixelmap* last_screen_src;
18
int render_width, render_height;
19
int window_width, window_height;
20
 
21
Uint32 last_frame_time;
22
 
23
uint8_t directinput_key_state[SDL_NUM_SCANCODES];
24
 
25
static void* create_window_and_renderer(char* title, int x, int y, int width, int height) {
26
    window_width = width;
27
    window_height = height;
28
    render_width = width;
29
    render_height = height;
30
 
31
    if (SDL_Init(SDL_INIT_VIDEO) != 0) {
32
        LOG_PANIC("SDL_INIT_VIDEO error: %s", SDL_GetError());
33
    }
34
 
35
    window = SDL_CreateWindow(title,
36
        SDL_WINDOWPOS_CENTERED,
37
        SDL_WINDOWPOS_CENTERED,
38
        width, height,
39
        SDL_WINDOW_RESIZABLE);
40
 
41
    if (window == NULL) {
42
        LOG_PANIC("Failed to create window: %s", SDL_GetError());
43
    }
44
 
45
    if (harness_game_config.start_full_screen) {
46
        SDL_SetWindowFullscreen(window, SDL_WINDOW_FULLSCREEN_DESKTOP);
47
    }
48
 
49
    renderer = SDL_CreateRenderer(window, -1, SDL_RENDERER_PRESENTVSYNC);
50
    if (renderer == NULL) {
51
        LOG_PANIC("Failed to create renderer: %s", SDL_GetError());
52
    }
53
    SDL_SetRenderDrawBlendMode(renderer, SDL_BLENDMODE_NONE);
54
    SDL_RenderSetLogicalSize(renderer, render_width, render_height);
55
 
56
    screen_texture = SDL_CreateTexture(renderer, SDL_PIXELFORMAT_ARGB8888, SDL_TEXTUREACCESS_STREAMING, width, height);
57
    if (screen_texture == NULL) {
58
        SDL_RendererInfo info;
59
        SDL_GetRendererInfo(renderer, &info);
60
        for (Uint32 i = 0; i < info.num_texture_formats; i++) {
61
            LOG_INFO("%s\n", SDL_GetPixelFormatName(info.texture_formats[i]));
62
        }
63
        LOG_PANIC("Failed to create screen_texture: %s", SDL_GetError());
64
    }
65
 
66
    return window;
67
}
68
 
69
static int set_window_pos(void* hWnd, int x, int y, int nWidth, int nHeight) {
70
    // SDL_SetWindowPosition(hWnd, x, y);
71
    if (nWidth == 320 && nHeight == 200) {
72
        nWidth = 640;
73
        nHeight = 400;
74
    }
75
    SDL_SetWindowSize(hWnd, nWidth, nHeight);
76
    return 0;
77
}
78
 
79
static void destroy_window(void* hWnd) {
80
    // SDL_GL_DeleteContext(context);
81
    SDL_DestroyWindow(window);
82
    SDL_Quit();
83
    window = NULL;
84
}
85
 
86
// Checks whether the `flag_check` is the only modifier applied.
87
// e.g. is_only_modifier(event.key.keysym.mod, KMOD_ALT) returns true when only the ALT key was pressed
88
static int is_only_key_modifier(int modifier_flags, int flag_check) {
89
    return (modifier_flags & flag_check) && (modifier_flags & (KMOD_CTRL | KMOD_SHIFT | KMOD_ALT | KMOD_GUI)) == (modifier_flags & flag_check);
90
}
91
 
92
static int get_and_handle_message(MSG_* msg) {
93
    SDL_Event event;
94
    int dinput_key;
95
 
96
    while (SDL_PollEvent(&event)) {
97
        switch (event.type) {
98
        case SDL_KEYDOWN:
99
        case SDL_KEYUP:
100
            if (event.key.keysym.sym == SDLK_RETURN) {
101
                if (event.key.type == SDL_KEYDOWN) {
102
                    if ((event.key.keysym.mod & (KMOD_CTRL | KMOD_SHIFT | KMOD_ALT | KMOD_GUI))) {
103
                        // Ignore keydown of RETURN when used together with some modifier
104
                        return 0;
105
                    }
106
                } else if (event.key.type == SDL_KEYUP) {
107
                    if (is_only_key_modifier(event.key.keysym.mod, KMOD_ALT)) {
108
                        SDL_SetWindowFullscreen(window, (SDL_GetWindowFlags(window) & SDL_WINDOW_FULLSCREEN_DESKTOP) ? 0 : SDL_WINDOW_FULLSCREEN_DESKTOP);
109
                    }
110
                }
111
            }
112
 
113
            // Map incoming SDL scancode to DirectInput DIK_* key code.
114
            // https://github.com/DanielGibson/Snippets/blob/master/sdl2_scancode_to_dinput.h
115
            dinput_key = sdlScanCodeToDirectInputKeyNum[event.key.keysym.scancode];
116
            if (dinput_key == 0) {
117
                LOG_WARN("unexpected scan code %s (%d)", SDL_GetScancodeName(event.key.keysym.scancode), event.key.keysym.scancode);
118
                return 0;
119
            }
120
            // DInput expects high bit to be set if key is down
121
            // https://learn.microsoft.com/en-us/previous-versions/windows/desktop/ee418261(v=vs.85)
122
            directinput_key_state[dinput_key] = (event.type == SDL_KEYDOWN ? 0x80 : 0);
123
            break;
124
 
125
        case SDL_QUIT:
126
            msg->message = WM_QUIT;
127
            return 1;
128
        }
129
    }
130
    return 0;
131
}
132
 
133
static void get_keyboard_state(unsigned int count, uint8_t* buffer) {
134
    memcpy(buffer, directinput_key_state, count);
135
}
136
 
137
static int get_mouse_buttons(int* pButton1, int* pButton2) {
138
    int state = SDL_GetMouseState(NULL, NULL);
139
    *pButton1 = state & SDL_BUTTON_LMASK;
140
    *pButton2 = state & SDL_BUTTON_RMASK;
141
    return 0;
142
}
143
 
144
static int get_mouse_position(int* pX, int* pY) {
145
    SDL_GetMouseState(pX, pY);
146
 
147
#if defined(DETHRACE_FIX_BUGS)
148
    // In hires mode (640x480), the menus are still rendered at (320x240),
149
    // so prescale the cursor coordinates accordingly.
150
    *pX *= gGraf_specs[gGraf_data_index].phys_width;
151
    *pX /= gGraf_specs[gReal_graf_data_index].phys_width;
152
    *pY *= gGraf_specs[gGraf_data_index].phys_height;
153
    *pY /= gGraf_specs[gReal_graf_data_index].phys_height;
154
#endif
155
    return 0;
156
}
157
 
158
static void limit_fps(void) {
159
    Uint32 now = SDL_GetTicks();
160
    if (last_frame_time != 0) {
161
        unsigned int frame_time = now - last_frame_time;
162
        last_frame_time = now;
163
        if (frame_time < 100) {
164
            int sleep_time = (1000 / harness_game_config.fps) - frame_time;
165
            if (sleep_time > 5) {
166
                gHarness_platform.Sleep(sleep_time);
167
            }
168
        }
169
    }
170
    last_frame_time = SDL_GetTicks();
171
}
172
 
173
static void present_screen(br_pixelmap* src) {
174
    // fastest way to convert 8 bit indexed to 32 bit
175
    uint8_t* src_pixels = src->pixels;
176
    uint32_t* dest_pixels;
177
    int dest_pitch;
178
 
179
    SDL_LockTexture(screen_texture, NULL, (void**)&dest_pixels, &dest_pitch);
180
    for (int i = 0; i < src->height * src->width; i++) {
181
        *dest_pixels = converted_palette[*src_pixels];
182
        dest_pixels++;
183
        src_pixels++;
184
    }
185
    SDL_UnlockTexture(screen_texture);
186
    SDL_RenderClear(renderer);
187
    SDL_RenderCopy(renderer, screen_texture, NULL, NULL);
188
    SDL_RenderPresent(renderer);
189
 
190
    last_screen_src = src;
191
 
192
    if (harness_game_config.fps != 0) {
193
        limit_fps();
194
    }
195
}
196
 
197
static void set_palette(PALETTEENTRY_* pal) {
198
    for (int i = 0; i < 256; i++) {
199
        converted_palette[i] = (0xff << 24 | pal[i].peRed << 16 | pal[i].peGreen << 8 | pal[i].peBlue);
200
    }
201
    if (last_screen_src != NULL) {
202
        present_screen(last_screen_src);
203
    }
204
}
205
 
206
int show_error_message(void* window, char* text, char* caption) {
207
    fprintf(stderr, "%s", text);
208
    SDL_ShowSimpleMessageBox(SDL_MESSAGEBOX_ERROR, caption, text, window);
209
    return 0;
210
}
211
 
212
void Harness_Platform_Init(tHarness_platform* platform) {
213
    platform->ProcessWindowMessages = get_and_handle_message;
214
    platform->Sleep = SDL_Delay;
215
    platform->GetTicks = SDL_GetTicks;
216
    platform->CreateWindowAndRenderer = create_window_and_renderer;
217
    platform->ShowCursor = SDL_ShowCursor;
218
    platform->SetWindowPos = set_window_pos;
219
    platform->DestroyWindow = destroy_window;
220
    platform->GetKeyboardState = get_keyboard_state;
221
    platform->GetMousePosition = get_mouse_position;
222
    platform->GetMouseButtons = get_mouse_buttons;
223
    platform->DestroyWindow = destroy_window;
224
    platform->ShowErrorMessage = show_error_message;
225
    platform->Renderer_SetPalette = set_palette;
226
    platform->Renderer_Present = present_screen;
227
}