diff options
-rw-r--r-- | Makefile | 68 | ||||
-rw-r--r-- | src/unix/sdl2/sound.c | 159 | ||||
-rw-r--r-- | src/unix/sdl2/video.c | 700 | ||||
-rw-r--r-- | src/unix/system.c | 4 |
4 files changed, 903 insertions, 28 deletions
@@ -476,37 +476,45 @@ ifdef CONFIG_WINDOWS LIBS_s += -lws2_32 -lwinmm -ladvapi32 LIBS_c += -lws2_32 -lwinmm else - SDL_CFLAGS ?= $(shell sdl-config --cflags) - SDL_LIBS ?= $(shell sdl-config --libs) - CFLAGS_c += -DUSE_SDL=1 $(SDL_CFLAGS) - LIBS_c += $(SDL_LIBS) - OBJS_c += src/unix/sdl/video.o - OBJS_c += src/unix/sdl/clipboard.o - - ifdef CONFIG_SOFTWARE_RENDERER - OBJS_c += src/unix/sdl/swimp.o + ifdef CONFIG_SDL2 + SDL_CFLAGS ?= $(shell sdl2-config --cflags) + SDL_LIBS ?= $(shell sdl2-config --libs) + CFLAGS_c += -DUSE_SDL=2 $(SDL_CFLAGS) + LIBS_c += $(SDL_LIBS) + OBJS_c += src/unix/sdl2/video.o else - OBJS_c += src/unix/sdl/glimp.o - endif + SDL_CFLAGS ?= $(shell sdl-config --cflags) + SDL_LIBS ?= $(shell sdl-config --libs) + CFLAGS_c += -DUSE_SDL=1 $(SDL_CFLAGS) + LIBS_c += $(SDL_LIBS) + OBJS_c += src/unix/sdl/video.o + OBJS_c += src/unix/sdl/clipboard.o + + ifdef CONFIG_SOFTWARE_RENDERER + OBJS_c += src/unix/sdl/swimp.o + else + OBJS_c += src/unix/sdl/glimp.o + endif - ifdef CONFIG_X11 - X11_CFLAGS ?= - X11_LIBS ?= -lX11 - CFLAGS_c += -DUSE_X11=1 $(X11_CFLAGS) - LIBS_c += $(X11_LIBS) - ifndef CONFIG_SOFTWARE_RENDERER - OBJS_c += src/unix/sdl/glx.o + ifdef CONFIG_X11 + X11_CFLAGS ?= + X11_LIBS ?= -lX11 + CFLAGS_c += -DUSE_X11=1 $(X11_CFLAGS) + LIBS_c += $(X11_LIBS) + ifndef CONFIG_SOFTWARE_RENDERER + OBJS_c += src/unix/sdl/glx.o + endif endif - endif - ifdef CONFIG_DIRECT_INPUT - CFLAGS_c += -DUSE_DINPUT=1 - OBJS_c += src/unix/evdev.o - ifndef CONFIG_NO_UDEV - UDEV_CFLAGS ?= - UDEV_LIBS ?= -ludev - CFLAGS_c += -DUSE_UDEV=1 $(UDEV_CFLAGS) - LIBS_c += $(UDEV_LIBS) + ifdef CONFIG_DIRECT_INPUT + CFLAGS_c += -DUSE_DINPUT=1 + OBJS_c += src/unix/evdev.o + ifndef CONFIG_NO_UDEV + UDEV_CFLAGS ?= + UDEV_LIBS ?= -ludev + CFLAGS_c += -DUSE_UDEV=1 $(UDEV_CFLAGS) + LIBS_c += $(UDEV_LIBS) + endif endif endif @@ -519,7 +527,11 @@ else endif ifndef CONFIG_NO_SOFTWARE_SOUND - OBJS_c += src/unix/sdl/sound.o + ifdef CONFIG_SDL2 + OBJS_c += src/unix/sdl2/sound.o + else + OBJS_c += src/unix/sdl/sound.o + endif ifdef CONFIG_DIRECT_SOUND CFLAGS_c += -DUSE_DSOUND=1 OBJS_c += src/unix/oss.o diff --git a/src/unix/sdl2/sound.c b/src/unix/sdl2/sound.c new file mode 100644 index 0000000..a38cb29 --- /dev/null +++ b/src/unix/sdl2/sound.c @@ -0,0 +1,159 @@ +/* +Copyright (C) 2007-2008 Andrey Nazarov + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License along +with this program; if not, write to the Free Software Foundation, Inc., +51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +*/ + +// +// snd_sdl.c +// + +#include "shared/shared.h" +#include "common/zone.h" +#include "client/sound/dma.h" +#include <SDL.h> + +static void Filler(void *userdata, Uint8 *stream, int len) +{ + int size = dma.samples << 1; + int pos = dma.samplepos << 1; + int wrapped = pos + len - size; + + if (wrapped < 0) { + memcpy(stream, dma.buffer + pos, len); + dma.samplepos += len >> 1; + } else { + int remaining = size - pos; + memcpy(stream, dma.buffer + pos, remaining); + memcpy(stream + remaining, dma.buffer, wrapped); + dma.samplepos = wrapped >> 1; + } +} + +static void Shutdown(void) +{ + Com_Printf("Shutting down SDL audio.\n"); + + SDL_CloseAudio(); + if (SDL_WasInit(SDL_INIT_EVERYTHING) == SDL_INIT_AUDIO) { + SDL_Quit(); + } else { + SDL_QuitSubSystem(SDL_INIT_AUDIO); + } + + if (dma.buffer) { + Z_Free(dma.buffer); + dma.buffer = NULL; + } +} + +static sndinitstat_t Init(void) +{ + SDL_AudioSpec desired, obtained; + int ret; + + if (SDL_WasInit(SDL_INIT_EVERYTHING) == 0) { + ret = SDL_Init(SDL_INIT_AUDIO); + } else { + ret = SDL_InitSubSystem(SDL_INIT_AUDIO); + } + if (ret == -1) { + Com_EPrintf("Couldn't initialize SDL audio: %s\n", SDL_GetError()); + return SIS_FAILURE; + } + + memset(&desired, 0, sizeof(desired)); + switch (s_khz->integer) { + case 48: + desired.freq = 48000; + break; + case 44: + desired.freq = 44100; + break; + case 22: + desired.freq = 22050; + break; + default: + desired.freq = 11025; + break; + } + + desired.format = AUDIO_S16LSB; + desired.samples = 512; + desired.channels = 2; + desired.callback = Filler; + ret = SDL_OpenAudio(&desired, &obtained); + if (ret == -1) { + Com_EPrintf("Couldn't open SDL audio: %s\n", SDL_GetError()); + return SIS_FAILURE; + } + + if (obtained.format != AUDIO_S16LSB) { + Com_EPrintf("SDL audio format %d unsupported.\n", obtained.format); + goto fail; + } + + if (obtained.channels != 1 && obtained.channels != 2) { + Com_EPrintf("SDL audio channels %d unsupported.\n", obtained.channels); + goto fail; + } + + dma.speed = obtained.freq; + dma.channels = obtained.channels; + dma.samples = 0x8000 * obtained.channels; + dma.submission_chunk = 1; + dma.samplebits = 16; + dma.buffer = Z_Mallocz(dma.samples * 2); + dma.samplepos = 0; + + Com_Printf("Using SDL audio driver: %s\n", SDL_GetCurrentAudioDriver()); + + SDL_PauseAudio(0); + + return SIS_SUCCESS; + +fail: + Shutdown(); + return SIS_FAILURE; +} + +static void BeginPainting(void) +{ + SDL_LockAudio(); +} + +static void Submit(void) +{ + SDL_UnlockAudio(); +} + +static void Activate(qboolean active) +{ + if (active) { + SDL_PauseAudio(0); + } else { + SDL_PauseAudio(1); + } +} + +void WAVE_FillAPI(snddmaAPI_t *api) +{ + api->Init = Init; + api->Shutdown = Shutdown; + api->BeginPainting = BeginPainting; + api->Submit = Submit; + api->Activate = Activate; +} + diff --git a/src/unix/sdl2/video.c b/src/unix/sdl2/video.c new file mode 100644 index 0000000..1e649f9 --- /dev/null +++ b/src/unix/sdl2/video.c @@ -0,0 +1,700 @@ +/* +Copyright (C) 2013 Andrey Nazarov + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License along +with this program; if not, write to the Free Software Foundation, Inc., +51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +*/ + +// +// video.c +// + +#include "shared/shared.h" +#include "common/cvar.h" +#include "common/common.h" +#include "common/files.h" +#include "common/zone.h" +#include "client/client.h" +#include "client/input.h" +#include "client/keys.h" +#include "client/ui.h" +#include "client/video.h" +#include "refresh/refresh.h" +#include "system/system.h" +#include "../res/q2pro.xbm" +#include <SDL.h> + +static SDL_Window *sdl_window; +static vidFlags_t sdl_flags; + +/* +=============================================================================== + +OPENGL STUFF + +=============================================================================== +*/ + +#if USE_REF == REF_GL + +static SDL_GLContext *sdl_context; + +static void gl_swapinterval_changed(cvar_t *self) +{ + if (SDL_GL_SetSwapInterval(self->integer) < 0) { + Com_EPrintf("Couldn't set swap interval %d: %s\n", self->integer, SDL_GetError()); + } +} + +static qboolean VID_SDL_GL_LoadLibrary(void) +{ +#if USE_FIXED_LIBGL + Cvar_Get("gl_driver", LIBGL, CVAR_ROM); + return qtrue; +#else + cvar_t *gl_driver = Cvar_Get("gl_driver", LIBGL, CVAR_REFRESH); + + // don't allow absolute or relative paths + FS_SanitizeFilenameVariable(gl_driver); + + while (1) { + char *s; + + // ugly hack to work around brain-dead servers that actively + // check and enforce `gl_driver' cvar to `opengl32', unaware + // of other systems than Windows + s = gl_driver->string; + if (!Q_stricmp(s, "opengl32") || !Q_stricmp(s, "opengl32.dll")) { + Com_Printf("...attempting to load %s instead of %s\n", + gl_driver->default_string, s); + s = gl_driver->default_string; + } + + if (SDL_GL_LoadLibrary(s) == 0) { + break; + } + + Com_EPrintf("Couldn't load OpenGL library: %s\n", SDL_GetError()); + if (!strcmp(s, gl_driver->default_string)) { + return qfalse; + } + + // attempt to recover + Com_Printf("...falling back to %s\n", gl_driver->default_string); + Cvar_Reset(gl_driver); + } + + return qtrue; +#endif +} + +static void VID_SDL_GL_SetAttributes(void) +{ + int colorbits = Cvar_ClampInteger( + Cvar_Get("gl_colorbits", "0", CVAR_REFRESH), 0, 32); + int depthbits = Cvar_ClampInteger( + Cvar_Get("gl_depthbits", "0", CVAR_REFRESH), 0, 32); + int stencilbits = Cvar_ClampInteger( + Cvar_Get("gl_stencilbits", "8", CVAR_REFRESH), 0, 8); + int multisamples = Cvar_ClampInteger( + Cvar_Get("gl_multisamples", "0", CVAR_REFRESH), 0, 32); + + if (colorbits == 0) + colorbits = 24; + + if (depthbits == 0) + depthbits = colorbits > 16 ? 24 : 16; + + if (depthbits < 24) + stencilbits = 0; + + if (colorbits > 16) { + SDL_GL_SetAttribute(SDL_GL_RED_SIZE, 8); + SDL_GL_SetAttribute(SDL_GL_GREEN_SIZE, 8); + SDL_GL_SetAttribute(SDL_GL_BLUE_SIZE, 8); + } else { + SDL_GL_SetAttribute(SDL_GL_RED_SIZE, 5); + SDL_GL_SetAttribute(SDL_GL_GREEN_SIZE, 5); + SDL_GL_SetAttribute(SDL_GL_BLUE_SIZE, 5); + } + + SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, depthbits); + SDL_GL_SetAttribute(SDL_GL_STENCIL_SIZE, stencilbits); + SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1); + + if (multisamples > 1) { + SDL_GL_SetAttribute(SDL_GL_MULTISAMPLEBUFFERS, 1); + SDL_GL_SetAttribute(SDL_GL_MULTISAMPLESAMPLES, multisamples); + } +} + +#if !USE_FIXED_LIBGL +void *VID_GetCoreAddr(const char *sym) +{ + void *entry = SDL_GL_GetProcAddress(sym); + + if (!entry) + Com_EPrintf("Couldn't get OpenGL entry point: %s\n", sym); + + return entry; +} +#endif + +void *VID_GetProcAddr(const char *sym) +{ + void *entry = SDL_GL_GetProcAddress(sym); + + if (!entry) + Com_EPrintf("Couldn't get OpenGL entry point: %s\n", sym); + + return entry; +} + +#endif + +/* +=============================================================================== + +VIDEO + +=============================================================================== +*/ + +static void VID_SDL_ModeChanged(void) +{ + int width, height; + void *pixels; + int rowbytes; + + SDL_GetWindowSize(sdl_window, &width, &height); + + Uint32 flags = SDL_GetWindowFlags(sdl_window); + if (flags & SDL_WINDOW_FULLSCREEN) + sdl_flags |= QVF_FULLSCREEN; + else + sdl_flags &= ~QVF_FULLSCREEN; + +#if USE_REF == REF_SOFT + SDL_Surface *surf = SDL_GetWindowSurface(sdl_window); + if (!surf) + Com_Error(ERR_FATAL, "Couldn't (re)create window surface: %s", SDL_GetError()); + pixels = surf->pixels; + rowbytes = surf->pitch; +#else + pixels = NULL; + rowbytes = 0; +#endif + + R_ModeChanged(width, height, sdl_flags, rowbytes, pixels); + SCR_ModeChanged(); +} + +static void VID_SDL_SetMode(void) +{ + Uint32 flags; + vrect_t rc; + int freq; + + if (vid_fullscreen->integer) { + if (VID_GetFullscreen(&rc, &freq, NULL)) { + SDL_DisplayMode mode = { + .format = SDL_PIXELFORMAT_UNKNOWN, + .w = rc.width, + .h = rc.height, + .refresh_rate = freq, + .driverdata = NULL + }; + SDL_SetWindowDisplayMode(sdl_window, &mode); + flags = SDL_WINDOW_FULLSCREEN; + } else { + flags = SDL_WINDOW_FULLSCREEN_DESKTOP; + } + } else { + flags = 0; + } + + SDL_SetWindowFullscreen(sdl_window, flags); +} + +void VID_SetMode(void) +{ + VID_SDL_SetMode(); + VID_SDL_ModeChanged(); +} + +void VID_VideoWait(void) +{ +} + +qboolean VID_VideoSync(void) +{ + return qtrue; +} + +void VID_BeginFrame(void) +{ +} + +void VID_EndFrame(void) +{ +#if USE_REF == REF_GL + SDL_GL_SwapWindow(sdl_window); +#else + SDL_UpdateWindowSurface(sdl_window); +#endif +} + +void VID_FatalShutdown(void) +{ + SDL_SetWindowGrab(sdl_window, SDL_FALSE); + SDL_SetRelativeMouseMode(SDL_FALSE); + SDL_ShowCursor(SDL_ENABLE); + SDL_Quit(); +} + +char *VID_GetClipboardData(void) +{ + // returned data must be Z_Free'd + char *text = SDL_GetClipboardText(); + char *copy = Z_CopyString(text); + SDL_free(text); + return copy; +} + +void VID_SetClipboardData(const char *data) +{ + SDL_SetClipboardText(data); +} + +void VID_UpdateGamma(const byte *table) +{ + Uint16 ramp[256]; + int i; + + if (sdl_flags & QVF_GAMMARAMP) { + for (i = 0; i < 256; i++) { + ramp[i] = table[i] << 8; + } + SDL_SetWindowGammaRamp(sdl_window, ramp, ramp, ramp); + } +} + +static int VID_SDL_InitSubSystem(void) +{ + int ret; + + ret = SDL_WasInit(SDL_INIT_EVERYTHING); + if (ret == 0) + ret = SDL_Init(SDL_INIT_VIDEO); + else if (!(ret & SDL_INIT_VIDEO)) + ret = SDL_InitSubSystem(SDL_INIT_VIDEO); + else + ret = 0; + + if (ret == -1) + Com_EPrintf("Couldn't initialize SDL video: %s\n", SDL_GetError()); + + return ret; +} + +static int VID_SDL_EventFilter(void *userdata, SDL_Event *event) +{ + // SDL uses relative time, we need absolute + event->common.timestamp = Sys_Milliseconds(); + return 1; +} + +char *VID_GetDefaultModeList(void) +{ + SDL_DisplayMode mode; + size_t size, len; + char *buf; + int i, num_modes; + + if (VID_SDL_InitSubSystem()) + return NULL; + + num_modes = SDL_GetNumDisplayModes(0); + if (num_modes < 1) + return Z_CopyString(VID_MODELIST); + + size = 8 + num_modes * 32 + 1; + buf = Z_Malloc(size); + + len = Q_strlcpy(buf, "desktop ", size); + for (i = 0; i < num_modes; i++) { + if (SDL_GetDisplayMode(0, i, &mode) < 0) + break; + if (mode.refresh_rate == 0) + continue; + len += Q_scnprintf(buf + len, size - len, "%dx%d@%d ", + mode.w, mode.h, mode.refresh_rate); + } + + if (len == 0) + buf[0] = 0; + else if (buf[len - 1] == ' ') + buf[len - 1] = 0; + + return buf; +} + +qboolean VID_Init(void) +{ + Uint32 flags = SDL_WINDOW_RESIZABLE; + vrect_t rc; + + if (VID_SDL_InitSubSystem()) { + return qfalse; + } + +#if USE_REF == REF_GL + if (!VID_SDL_GL_LoadLibrary()) { + goto fail; + } + + VID_SDL_GL_SetAttributes(); + flags |= SDL_WINDOW_OPENGL; +#endif + + SDL_SetEventFilter(VID_SDL_EventFilter, NULL); + + if (!VID_GetGeometry(&rc)) { + rc.x = SDL_WINDOWPOS_UNDEFINED; + rc.y = SDL_WINDOWPOS_UNDEFINED; + } + + sdl_window = SDL_CreateWindow(PRODUCT, rc.x, rc.y, rc.width, rc.height, flags); + if (!sdl_window) { + Com_EPrintf("Couldn't create SDL window: %s\n", SDL_GetError()); + goto fail; + } + + SDL_SetWindowMinimumSize(sdl_window, 320, 240); + + SDL_Surface *icon = SDL_CreateRGBSurfaceFrom(q2icon_bits, q2icon_width, q2icon_height, + 1, q2icon_width / 8, 0, 0, 0, 0); + if (icon) { + SDL_Color colors[2] = { + { 255, 255, 255 }, + { 0, 128, 128 } + }; + SDL_SetPaletteColors(icon->format->palette, colors, 0, 2); + SDL_SetColorKey(icon, SDL_TRUE, 0); + SDL_SetWindowIcon(sdl_window, icon); + SDL_FreeSurface(icon); + } + + VID_SDL_SetMode(); + +#if USE_REF == REF_GL + sdl_context = SDL_GL_CreateContext(sdl_window); + if (!sdl_context) { + Com_EPrintf("Couldn't create OpenGL context: %s\n", SDL_GetError()); + goto fail; + } + + cvar_t *gl_swapinterval = Cvar_Get("gl_swapinterval", "0", 0); + gl_swapinterval->changed = gl_swapinterval_changed; + gl_swapinterval_changed(gl_swapinterval); +#endif + + cvar_t *vid_hwgamma = Cvar_Get("vid_hwgamma", "0", CVAR_REFRESH); + if (vid_hwgamma->integer) { + Uint16 gamma[3][256]; + + if (SDL_GetWindowGammaRamp(sdl_window, gamma[0], gamma[1], gamma[2]) == 0 && + SDL_SetWindowGammaRamp(sdl_window, gamma[0], gamma[1], gamma[2]) == 0) { + Com_Printf("...enabling hardware gamma\n"); + sdl_flags |= QVF_GAMMARAMP; + } else { + Com_Printf("...hardware gamma not supported\n"); + Cvar_Reset(vid_hwgamma); + } + } + + VID_SDL_ModeChanged(); + return qtrue; + +fail: + VID_Shutdown(); + return qfalse; +} + +void VID_Shutdown(void) +{ +#if USE_REF == REF_GL + if (sdl_context) { + SDL_GL_DeleteContext(sdl_context); + sdl_context = NULL; + } +#endif + if (sdl_window) { + SDL_DestroyWindow(sdl_window); + sdl_window = NULL; + } + sdl_flags = 0; + if (SDL_WasInit(SDL_INIT_EVERYTHING) == SDL_INIT_VIDEO) { + SDL_Quit(); + } else { + SDL_QuitSubSystem(SDL_INIT_VIDEO); + } +} + +/* +========================================================================== + +EVENTS + +========================================================================== +*/ + +static void window_event(SDL_WindowEvent *event) +{ + Uint32 flags = SDL_GetWindowFlags(sdl_window); + active_t active; + vrect_t rc; + + switch (event->event) { + case SDL_WINDOWEVENT_MINIMIZED: + case SDL_WINDOWEVENT_RESTORED: + case SDL_WINDOWEVENT_ENTER: + case SDL_WINDOWEVENT_LEAVE: + case SDL_WINDOWEVENT_FOCUS_GAINED: + case SDL_WINDOWEVENT_FOCUS_LOST: + if (flags & (SDL_WINDOW_INPUT_FOCUS | SDL_WINDOW_MOUSE_FOCUS)) { + active = ACT_ACTIVATED; + } else if (flags & SDL_WINDOW_MINIMIZED) { + active = ACT_MINIMIZED; + } else { + active = ACT_RESTORED; + } + CL_Activate(active); + break; + + case SDL_WINDOWEVENT_MOVED: + if (!(flags & SDL_WINDOW_FULLSCREEN)) { + SDL_GetWindowSize(sdl_window, &rc.width, &rc.height); + rc.x = event->data1; + rc.y = event->data2; + VID_SetGeometry(&rc); + } + break; + + case SDL_WINDOWEVENT_RESIZED: + if (!(flags & SDL_WINDOW_FULLSCREEN)) { + SDL_GetWindowPosition(sdl_window, &rc.x, &rc.y); + rc.width = event->data1; + rc.height = event->data2; + VID_SetGeometry(&rc); + } + VID_SDL_ModeChanged(); + break; + } +} + +static const byte scantokey[128] = { +// 0 1 2 3 4 5 6 7 +// 8 9 A B C D E F + 0, 0, 0, 0, 'a', 'b', 'c', 'd', // 0 + 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', + 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', // 1 + 'u', 'v', 'w', 'x', 'y', 'z', '1', '2', + '3', '4', '5', '6', '7', '8', '9', '0', // 2 + K_ENTER, K_ESCAPE, K_BACKSPACE, K_TAB, K_SPACE, '-', '=', '[', + ']', '\\', 0, ';', '\'', '`', ',', '.', // 3 + '/' , K_CAPSLOCK, K_F1, K_F2, K_F3, K_F4, K_F5, K_F6, + K_F7, K_F8, K_F9, K_F10, K_F11, K_F12, K_PRINTSCREEN, K_SCROLLOCK, // 4 + K_PAUSE, K_INS, K_HOME, K_PGUP, K_DEL, K_END, K_PGDN, K_RIGHTARROW, + K_LEFTARROW, K_DOWNARROW, K_UPARROW, K_NUMLOCK, K_KP_SLASH, K_KP_MULTIPLY, K_KP_MINUS, K_KP_PLUS, // 5 + K_KP_ENTER, K_KP_END, K_KP_DOWNARROW, K_KP_PGDN, K_KP_LEFTARROW, K_KP_5, K_KP_RIGHTARROW, K_KP_HOME, + K_KP_UPARROW, K_KP_PGUP, K_KP_INS, K_KP_DEL, K_102ND, 0, 0, 0, // 6 + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, K_MENU, 0, // 7 + K_LCTRL, K_LSHIFT, K_LALT, K_LWINKEY, K_RCTRL, K_RSHIFT, K_RALT, K_RWINKEY, // E +}; + +static void key_event(SDL_KeyboardEvent *event) +{ + byte result; + + if (event->keysym.scancode < 120) + result = scantokey[event->keysym.scancode]; + else if (event->keysym.scancode >= 224 && event->keysym.scancode < 224 + 8) + result = scantokey[event->keysym.scancode - 104]; + else + result = 0; + + if (result == 0) { + Com_DPrintf("%s: unknown scancode %d\n", __func__, event->keysym.scancode); + return; + } + + if (result == K_LALT || result == K_RALT) + Key_Event(K_ALT, event->state, event->timestamp); + else if (result == K_LCTRL || result == K_RCTRL) + Key_Event(K_CTRL, event->state, event->timestamp); + else if (result == K_LSHIFT || result == K_RSHIFT) + Key_Event(K_SHIFT, event->state, event->timestamp); + + Key_Event(result, event->state, event->timestamp); +} + +static void mouse_button_event(SDL_MouseButtonEvent *event) +{ + unsigned key; + + switch (event->button) { + case SDL_BUTTON_LEFT: + key = K_MOUSE1; + break; + case SDL_BUTTON_RIGHT: + key = K_MOUSE2; + break; + case SDL_BUTTON_MIDDLE: + key = K_MOUSE3; + break; + case SDL_BUTTON_X1: + key = K_MOUSE4; + break; + case SDL_BUTTON_X2: + key = K_MOUSE5; + break; + default: + Com_DPrintf("%s: unknown button %d\n", __func__, event->button); + return; + } + + Key_Event(key, event->state, event->timestamp); +} + +static void mouse_wheel_event(SDL_MouseWheelEvent *event) +{ + if (event->x > 0) { + Key_Event(K_MWHEELRIGHT, qtrue, event->timestamp); + Key_Event(K_MWHEELRIGHT, qfalse, event->timestamp); + } else if (event->x < 0) { + Key_Event(K_MWHEELLEFT, qtrue, event->timestamp); + Key_Event(K_MWHEELLEFT, qfalse, event->timestamp); + } + + if (event->y > 0) { + Key_Event(K_MWHEELUP, qtrue, event->timestamp); + Key_Event(K_MWHEELUP, qfalse, event->timestamp); + } else if (event->y < 0) { + Key_Event(K_MWHEELDOWN, qtrue, event->timestamp); + Key_Event(K_MWHEELDOWN, qfalse, event->timestamp); + } +} + +/* +============ +VID_PumpEvents +============ +*/ +void VID_PumpEvents(void) +{ + SDL_Event event; + + while (SDL_PollEvent(&event)) { + switch (event.type) { + case SDL_QUIT: + Com_Quit(NULL, ERR_DISCONNECT); + break; + case SDL_WINDOWEVENT: + window_event(&event.window); + break; + case SDL_KEYDOWN: + case SDL_KEYUP: + key_event(&event.key); + break; + case SDL_MOUSEMOTION: + UI_MouseEvent(event.motion.x, event.motion.y); + break; + case SDL_MOUSEBUTTONDOWN: + case SDL_MOUSEBUTTONUP: + mouse_button_event(&event.button); + break; + case SDL_MOUSEWHEEL: + mouse_wheel_event(&event.wheel); + break; + } + } +} + +/* +=============================================================================== + +MOUSE + +=============================================================================== +*/ + +static qboolean GetMouseMotion(int *dx, int *dy) +{ + if (!SDL_GetRelativeMouseMode()) { + return qfalse; + } + SDL_GetRelativeMouseState(dx, dy); + return qtrue; +} + +static void WarpMouse(int x, int y) +{ + SDL_WarpMouseInWindow(sdl_window, x, y); + SDL_GetRelativeMouseState(NULL, NULL); +} + +static void ShutdownMouse(void) +{ + SDL_SetWindowGrab(sdl_window, SDL_FALSE); + SDL_SetRelativeMouseMode(SDL_FALSE); + SDL_ShowCursor(SDL_ENABLE); +} + +static qboolean InitMouse(void) +{ + if (SDL_WasInit(SDL_INIT_VIDEO) != SDL_INIT_VIDEO) { + return qfalse; + } + + Com_Printf("SDL mouse initialized.\n"); + return qtrue; +} + +static void GrabMouse(qboolean grab) +{ + SDL_bool relative = grab && !(Key_GetDest() & KEY_MENU); + int cursor = (sdl_flags & QVF_FULLSCREEN) ? SDL_DISABLE : SDL_ENABLE; + + SDL_SetWindowGrab(sdl_window, (SDL_bool)grab); + SDL_SetRelativeMouseMode(relative); + SDL_GetRelativeMouseState(NULL, NULL); + SDL_ShowCursor(cursor); +} + +/* +============ +VID_FillInputAPI +============ +*/ +void VID_FillInputAPI(inputAPI_t *api) +{ + api->Init = InitMouse; + api->Shutdown = ShutdownMouse; + api->Grab = GrabMouse; + api->Warp = WarpMouse; + api->GetEvents = NULL; + api->GetMotion = GetMouseMotion; +} diff --git a/src/unix/system.c b/src/unix/system.c index 24642a2..7772ec5 100644 --- a/src/unix/system.c +++ b/src/unix/system.c @@ -38,6 +38,10 @@ with this program; if not, write to the Free Software Foundation, Inc., #include <dlfcn.h> #include <errno.h> +#if USE_SDL +#include <SDL_main.h> +#endif + cvar_t *sys_basedir; cvar_t *sys_libdir; cvar_t *sys_homedir; |