diff --git a/Makefile b/Makefile index 2cab3856..5f105d93 100644 --- a/Makefile +++ b/Makefile @@ -7,7 +7,7 @@ # - Quake II Game (baseq2) # # # # Base dependencies: # -# - SDL 1.2 # +# - SDL 1.2 or SDL 2.0 # # - libGL # # # # Platforms: # @@ -24,6 +24,7 @@ # for the background music and doesn't add any further # dependencies. It should work on all platforms where # CD playback is supported by SDL. +# was yes WITH_CDA:=yes # Enables OGG/Vorbis support. OGG/Vorbis files can be @@ -41,6 +42,12 @@ WITH_OPENAL:=yes # a dependency to libjpeg WITH_RETEXTURING:=yes +# Use SDL2 instead of SDL1.2. Disables CD audio support, +# because SDL2 has none. Use OGG/Vorbis music instead :-) +# On Windows sdl-config isn't used, so make sure that +# you've got the SDL2 headers and libs installed. +WITH_SDL2:=yes + # Set the gamma via X11 and not via SDL. This works # around problems in some SDL version. Adds dependencies # to pkg-config, libX11 and libXxf86vm. Unsupported on @@ -102,6 +109,18 @@ ifeq ($(findstring $(ARCH), i386 x86_64 sparc64 ia64),) $(error arch $(ARCH) is currently not supported) endif +# Disable CDA for SDL2 +ifeq ($(WITH_SDL2),yes) +ifeq ($(WITH_CDA),yes) +WITH_CDA:=no + +# Evil hack to tell the "all" target +# that CDA was disabled because SDL2 +# is enabled. +CDA_ENABLED:=yes +endif +endif + # ---------- # Base CFLAGS. @@ -146,10 +165,15 @@ endif ifneq ($(OSTYPE), Windows) ifeq ($(OSTYPE), Darwin) SDLCFLAGS := -else +else # not darwin +ifeq ($(WITH_SDL2),yes) +SDLCFLAGS := $(shell sdl2-config --cflags) +else # not SDL2 SDLCFLAGS := $(shell sdl-config --cflags) -endif -endif +endif # SDL2 + +endif # darwin's else +endif # not windows # ---------- @@ -195,12 +219,24 @@ endif # Extra LDFLAGS for SDL ifeq ($(OSTYPE), Windows) +ifeq ($(WITH_SDL2),yes) +SDLLDFLAGS := -lSDL2main -lSDL2 -mwindows -lm -ldinput8 -ldxguid -ldxerr8 -luser32 -lgdi32 -lwinmm -limm32 -lole32 -loleaut32 -lshell32 -lversion -luuid +else # not SDL2 SDLLDFLAGS := -lSDL +endif # SDL2 else ifeq ($(OSTYPE), Darwin) +ifeq ($(WITH_SDL2),yes) +SDLLDFLAGS := -framework SDL2 -framework OpenGL -framework Cocoa +else # not SDL2 SDLLDFLAGS := -framework SDL -framework OpenGL -framework Cocoa -else +endif # SDL2 +else # not Darwin/Win +ifeq ($(WITH_SDL2),yes) +SDLLDFLAGS := $(shell sdl2-config --libs) +else # not SDL2 SDLLDFLAGS := $(shell sdl-config --libs) -endif +endif # SDL2 +endif # Darwin/Win # ---------- @@ -210,6 +246,7 @@ ifneq ($(OSTYPE), Darwin) ifeq ($(WITH_X11GAMMA),yes) X11LDFLAGS := $(shell pkg-config x11 --libs) X11LDFLAGS += $(shell pkg-config xxf86vm --libs) +X11LDFLAGS += $(shell pkg-config xrandr --libs) endif endif endif @@ -243,11 +280,19 @@ config: @echo "WITH_CDA = $(WITH_CDA)" @echo "WITH_OPENAL = $(WITH_OPENAL)" @echo "WITH_RETEXTURING = $(WITH_RETEXTURING)" + @echo "WITH_SDL2 = $(WITH_SDL2)" @echo "WITH_X11GAMMA = $(WITH_X11GAMMA)" @echo "WITH_ZIP = $(WITH_ZIP)" @echo "WITH_SYSTEMWIDE = $(WITH_SYSTEMWIDE)" @echo "WITH_SYSTEMDIR = $(WITH_SYSTEMDIR)" @echo "============================" + @echo "" +ifeq ($(WITH_SDL2),yes) +ifeq ($(CDA_ENABLED),yes) + @echo "WARNING: CDA disabled because SDL2 doesn't support it!" + @echo "" +endif +endif # ---------- @@ -310,6 +355,10 @@ release/quake2.exe : CFLAGS += -DRETEXTURE release/quake2.exe : LDFLAGS += -ljpeg endif +ifeq ($(WITH_SDL2),yes) +release/quake2.exe : CFLAGS += -DSDL2 +endif + release/quake2.exe : LDFLAGS += -mwindows -lopengl32 else client: @@ -370,6 +419,10 @@ else release/quake2 : LDFLAGS += -ljpeg endif endif + +ifeq ($(WITH_SDL2),yes) +release/quake2 : CFLAGS += -DSDL2 +endif ifeq ($(OSTYPE), Darwin) ifeq ($(OSX_APP), yes) diff --git a/README b/README index 782984f3..d17d55b9 100644 --- a/README +++ b/README @@ -11,9 +11,10 @@ II. The main focus is single player, the gameplay and the graphics are unchanged, but many bugs were fixed. Unlike most other Quake II ports Yamagi Quake II is full 64 bit clean so it works perfectly on modern amd64 (x86_64) processors and operating systems. This code should run on Windows XP or later, -Mac OS X 10.6 or higher and on most unix-like operating systems (only FreeBSD, -Linux and OpenBSD are officially supported and tested, for other systems you'd -at least have to edit the Makefile), just type "make" or "gmake" to compile. +Mac OS X 10.6 or higher (unsupported!) and on most unix-like operating systems +(only FreeBSD, Linux and OpenBSD are officially supported and tested, for other +systems you'd at least have to edit the Makefile), just type "make" or "gmake" +to compile. This code is based upon Icculus Quake II, which itself is built upon id Software's original code drop. Additional code and patches by many contributers @@ -147,7 +148,7 @@ it'll lead to the loss of features): - libogg with development headers - libvorbis with development headers - OpenAL with development headers - - SDL with development headers and sdl-config(1) + - SDL 1.2 or 2.0 with development headers and sdl-config(1) - ZLib Extract the source, change into the new created directory and type "make" @@ -156,7 +157,6 @@ following files from "release/" to your installation directory preserving the directory structure: - q2ded - quake2 -- ref_gl.so - baseq2/game.so 1.6 Default Configuration @@ -242,7 +242,7 @@ use the github version or want to develop on Windows. If you really want to compile Yamagi Quake II by yourself follow these steps: 1. Grab a copy of Nuwens MinGW distribution from http://nuwen.net/mingw.html - Our code is tested with version 9.0, newer version may work but we can not + Our code is tested with version 11.0, newer version may work but we can not guarantee that. Extract the distribution to a directory of your choice. 2. Grab a copy of OpenAL Soft from http://kcat.strangesoft.net/openal.html (the binary release for Windows). Our code is tested with version 1.14. @@ -256,14 +256,12 @@ After compiling, copy the following files from "release\" to your Quake II installation preserving the directory structure: - q2ded.exe - quake2.exe -- ref_gl.dll - baseq2\game.dll -You'll need a "openal32.dll" and an "SDL.dll" next to "quake2.exe". You can use -and rename the OpenAL DLL that came with OpenAL Soft. We recommend to use a -"SDL.dll" from http://libsdl.org and not the one supplied with Nuwens MinGW -distribution. Known to be good DLLs can be found in the stuff/win32-libs -directory of the source code distribution. +You'll need a "openal32.dll. You can use and rename the OpenAL DLL that +came with OpenAL Soft. Known to be good DLLs can be found in the +stuff/win32-libs directory of the source code distribution. The supplied +SDL.dll is an SDL 1.2 build, required if you're still using SDL 1.2. 2.7 Default Configuration ------------------------- @@ -283,6 +281,10 @@ supported, including the IPv6 network code and the OpenAL sound backend. Installation can be done by using the binary release (this is highly recommended) or by compiling the source. +ATTENTION: OS X is currently unsupported. I neither have a Mac nor the time to +maintain this platform. If you're interested in spending work on OS X please +write an e-mail to quake2@yamagi.org. + 3.1 Supported Systems --------------------- Yamagi Quake II should run on every Mac with Intel CPU and OS X 10.6 @@ -375,8 +377,9 @@ Now you are ready to start your brand new Quake II. Have fun. ====================== Since most modern CD-ROM and DVD drives don't have an analog audio output and most sound codecs don't have the appropriate input header, it's not possible to -use CD audio as background music on such systems. Therefore OGG/Vorbis music -support has been added to Yamagi Quake II. +use CD audio as background music on such systems. With SDL 2.0 CD audio is +unsupported Therefore OGG/Vorbis music support has been added to Yamagi Quake +II. 4.1 Setup for the original soundtrack: -------------------------------------- @@ -649,9 +652,7 @@ My SDL sound is not working! Does the sound work in other SDL games? Does your setup support at least five virtual channels? In most cases it's better to not use sound servers like Pulseaudio but the plain sound system like OSS or ALSA with libasound instead. - Also see the "Sound" section in this file! On Windows the SDL sound backend - may not work on all installations. This is due to a limitation of SDL. Use - OpenAL instead. + Also see the "Sound" section in this file! My OpenGL is not working! - Make sure, that OpenGL is working in other games. Use "glxinfo" and @@ -699,7 +700,7 @@ that, so that Quake II behaves like a normal window? Hey, my screensaver crashes Quake II or I experience strange crashes after a fixed amount of time! - - This is a known bug in some linux distributions. SDL fails to disable + - This is a known bug in some linux distributions. SDL 1.2 fails to disable the screensaver even if we tell him to do so. See this Ubuntu bugreport: https://bugs.launchpad.net/ubuntu/+source/gnome-screensaver/+bug/32457 As a work around use the startscript in stuff/quake-start.sh It deactivates @@ -794,4 +795,14 @@ Why is the FOV different than in id Softwares client? Why doesn't gl_showtris work? - gl_showtris requires gl_ext_multitexturing set to 0. +How do I disable the vsync? + - Set gl_swapinterval to 0 and type vid_restart. Beware that this may + not work with SDL 1.2 due to bugs in SDL. + +I've build Yamagi Quake II with SDL 2.0 and now my mouse behaves strange. + - If it feels like your mouse is hitting the window borders you're + experiencing a problem in SDL 2.0. SDL 2.0 needs XInput 2.2 or higher + and fails when the installed version is older. So make sure that you + have XInput 2.2 or higher installed. + ============================================================================== diff --git a/src/backends/sdl/input.c b/src/backends/sdl/input.c index 887a12d8..b000c4de 100644 --- a/src/backends/sdl/input.c +++ b/src/backends/sdl/input.c @@ -29,12 +29,36 @@ #include "../../client/header/keyboard.h" #include "../generic/header/input.h" -#ifdef _WIN32 +#if defined(_WIN32) || defined(__APPLE__) +#ifdef SDL2 +#include +#else // SDL1.2 #include -#elif defined(__APPLE__) -#include -#else +#endif //SDL2 +#else // not _WIN32 || APPLE #include +#endif // _WIN32 || APPLE + +#if SDL_VERSION_ATLEAST(2, 0, 0) + #define SDLK_KP0 SDLK_KP_0 + #define SDLK_KP1 SDLK_KP_1 + #define SDLK_KP2 SDLK_KP_2 + #define SDLK_KP3 SDLK_KP_3 + #define SDLK_KP4 SDLK_KP_4 + #define SDLK_KP5 SDLK_KP_5 + #define SDLK_KP6 SDLK_KP_6 + #define SDLK_KP7 SDLK_KP_7 + #define SDLK_KP8 SDLK_KP_8 + #define SDLK_KP9 SDLK_KP_9 + + #define SDLK_RMETA SDLK_RGUI + #define SDLK_LMETA SDLK_LGUI + + #define SDLK_COMPOSE SDLK_APPLICATION // really? + + #define SDLK_PRINT SDLK_PRINTSCREEN + #define SDLK_SCROLLOCK SDLK_SCROLLLOCK + #define SDLK_NUMLOCK SDLK_NUMLOCKCLEAR #endif #define MOUSE_MAX 3000 @@ -61,9 +85,7 @@ int my; Key_Event_fp_t Key_Event_fp; -extern SDL_Surface *surface; static in_state_t *in_state; -static unsigned char KeyStates[SDLK_LAST]; static qboolean mlooking; static cvar_t *sensitivity; @@ -232,10 +254,13 @@ IN_TranslateSDLtoQ2Key(unsigned int keysym) case SDLK_LALT: key = K_ALT; break; +#if !SDL_VERSION_ATLEAST(2, 0, 0) + // TODO: delete? what is this anyway? case SDLK_LSUPER: case SDLK_RSUPER: key = K_SUPER; break; +#endif case SDLK_KP5: key = K_KP_5; break; @@ -272,18 +297,24 @@ IN_TranslateSDLtoQ2Key(unsigned int keysym) case SDLK_SYSREQ: key = K_SYSREQ; break; +#if !SDL_VERSION_ATLEAST(2, 0, 0) + // TODO: delete? what is this anyway? case SDLK_BREAK: key = K_BREAK; break; +#endif case SDLK_MENU: key = K_MENU; break; case SDLK_POWER: key = K_POWER; break; +#if !SDL_VERSION_ATLEAST(2, 0, 0) + // TODO: delete? what is this anyway? case SDLK_EURO: key = K_EURO; break; +#endif case SDLK_UNDO: key = K_UNDO; break; @@ -298,12 +329,13 @@ IN_TranslateSDLtoQ2Key(unsigned int keysym) break; default: - +#if !SDL_VERSION_ATLEAST(2, 0, 0) + // FIXME: how could this be used with SDL2?! if ((keysym >= SDLK_WORLD_0) && (keysym <= SDLK_WORLD_95)) { key = (keysym - SDLK_WORLD_0) + K_WORLD_0; } - +#endif break; } } @@ -311,6 +343,19 @@ IN_TranslateSDLtoQ2Key(unsigned int keysym) return key; } +// add down and up event for mousewheel to simulate a "click" +static void IN_AddMouseWheelEvents(int key) +{ + assert(key == K_MWHEELUP || key == K_MWHEELDOWN); + + keyq[keyq_head].key = key; + keyq[keyq_head].down = true; + keyq_head = (keyq_head + 1) & 127; + keyq[keyq_head].key = key; + keyq[keyq_head].down = false; + keyq_head = (keyq_head + 1) & 127; +} + /* * Input event processing */ @@ -318,32 +363,34 @@ void IN_GetEvent(SDL_Event *event) { unsigned int key; +#if SDL_VERSION_ATLEAST(2, 0, 0) + SDL_Keymod modstate = SDL_GetModState(); +#else + SDLMod modstate = SDL_GetModState(); +#endif switch (event->type) { /* The mouse wheel */ +#if SDL_VERSION_ATLEAST(2, 0, 0) + case SDL_MOUSEWHEEL: + IN_AddMouseWheelEvents(event->wheel.y > 0 ? K_MWHEELUP : K_MWHEELDOWN); + break; + +#else case SDL_MOUSEBUTTONDOWN: if (event->button.button == 4) { - keyq[keyq_head].key = K_MWHEELUP; - keyq[keyq_head].down = true; - keyq_head = (keyq_head + 1) & 127; - keyq[keyq_head].key = K_MWHEELUP; - keyq[keyq_head].down = false; - keyq_head = (keyq_head + 1) & 127; + IN_AddMouseWheelEvents(K_MWHEELUP); } else if (event->button.button == 5) { - keyq[keyq_head].key = K_MWHEELDOWN; - keyq[keyq_head].down = true; - keyq_head = (keyq_head + 1) & 127; - keyq[keyq_head].key = K_MWHEELDOWN; - keyq[keyq_head].down = false; - keyq_head = (keyq_head + 1) & 127; + IN_AddMouseWheelEvents(K_MWHEELDOWN); } break; +#endif case SDL_MOUSEBUTTONUP: break; @@ -352,23 +399,10 @@ IN_GetEvent(SDL_Event *event) case SDL_KEYDOWN: /* Fullscreen switch via Alt-Return */ - if ((KeyStates[SDLK_LALT] || - KeyStates[SDLK_RALT]) && + if ((modstate & KMOD_ALT) && (event->key.keysym.sym == SDLK_RETURN)) { - SDL_WM_ToggleFullScreen(surface); - - if (surface->flags & SDL_FULLSCREEN) - { - Cvar_SetValue("vid_fullscreen", 1); - } - else - { - Cvar_SetValue("vid_fullscreen", 0); - } - - vid_fullscreen->modified = false; - + GLimp_ToggleFullscreen(); break; } @@ -376,8 +410,7 @@ IN_GetEvent(SDL_Event *event) really belongs in Key_Event(), but since Key_ClearStates() can mess up the internal K_SHIFT state let's do it here instead. */ - if ((KeyStates[SDLK_LSHIFT] || - KeyStates[SDLK_RSHIFT]) && + if ((modstate & KMOD_SHIFT) && (event->key.keysym.sym == SDLK_ESCAPE)) { Cbuf_ExecuteText(EXEC_NOW, "toggleconsole"); @@ -385,8 +418,6 @@ IN_GetEvent(SDL_Event *event) break; } - KeyStates[event->key.keysym.sym] = 1; - /* Get the pressed key and add it to the key list */ key = IN_TranslateSDLtoQ2Key(event->key.keysym.sym); @@ -401,20 +432,14 @@ IN_GetEvent(SDL_Event *event) /* The user released a key */ case SDL_KEYUP: + /* Get the pressed key and remove it from the key list */ + key = IN_TranslateSDLtoQ2Key(event->key.keysym.sym); - if (KeyStates[event->key.keysym.sym]) + if (key) { - KeyStates[event->key.keysym.sym] = 0; - - /* Get the pressed key and remove it from the key list */ - key = IN_TranslateSDLtoQ2Key(event->key.keysym.sym); - - if (key) - { - keyq[keyq_head].key = key; - keyq[keyq_head].down = false; - keyq_head = (keyq_head + 1) & 127; - } + keyq[keyq_head].key = key; + keyq[keyq_head].down = false; + keyq_head = (keyq_head + 1) & 127; } break; @@ -445,14 +470,15 @@ IN_Update(void) IN_GetEvent(&event); } - /* Mouse button processing. Button 4 - and 5 are the mousewheel and thus - not processed here. */ + if (!mx && !my) { SDL_GetRelativeMouseState(&mx, &my); } + /* Mouse button processing. Button 4 + and 5 are the mousewheel and thus + not processed here. */ mouse_buttonstate = 0; bstate = SDL_GetMouseState(NULL, NULL); @@ -487,7 +513,7 @@ IN_Update(void) (in_grab->value == 2 && windowed_mouse->value)); if (have_grab != want_grab) { - SDL_WM_GrabInput((want_grab ? SDL_GRAB_ON : SDL_GRAB_OFF)); + GLimp_GrabInput(want_grab); have_grab = want_grab; } @@ -572,9 +598,16 @@ IN_KeyboardInit(Key_Event_fp_t fp) /* SDL stuff. Moved here from IN_BackendInit because * this must be done after video is initialized. */ +#if SDL_VERSION_ATLEAST(2, 0, 0) + // TODO: keyrepeat? + // TODO: only if want_grab? + SDL_SetRelativeMouseMode(SDL_TRUE); + have_grab = GLimp_InputIsGrabbed(); +#else SDL_EnableUNICODE(0); SDL_EnableKeyRepeat(SDL_DEFAULT_REPEAT_DELAY, SDL_DEFAULT_REPEAT_INTERVAL); have_grab = (SDL_WM_GrabInput(SDL_GRAB_QUERY) == SDL_GRAB_ON); +#endif } /* diff --git a/src/backends/sdl/refresh.c b/src/backends/sdl/refresh.c index de510fcf..fb2507f2 100644 --- a/src/backends/sdl/refresh.c +++ b/src/backends/sdl/refresh.c @@ -18,6 +18,11 @@ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA * 02111-1307, USA. * + * ---------------------------------------------------------------------- + * CalculateGammaRamp() is derived from SDL2's SDL_CalculateGammaRamp() + * (C) 1997-2013 Sam Lantinga + * Published under zlib License: http://www.libsdl.org/license.php + * * ======================================================================= * * This file implements an OpenGL context via SDL @@ -32,13 +37,15 @@ #include #endif -#ifdef _WIN32 +#if defined(_WIN32) || defined(__APPLE__) +#ifdef SDL2 +#include +#else // SDL1.2 #include -#elif defined(__APPLE__) -#include -#else +#endif //SDL2 +#else // not _WIN32 || APPLE #include -#endif +#endif // _WIN32 || APPLE /* The window icon */ #include "icon/q2icon.xbm" @@ -49,17 +56,31 @@ #include #include #include + #include + + #include +#endif + +#if SDL_VERSION_ATLEAST(2, 0, 0) +SDL_Window* window = NULL; +SDL_GLContext context = NULL; +#else +SDL_Surface* window = NULL; #endif -SDL_Surface *surface; qboolean have_stencil = false; -char *displayname = NULL; -int screen = -1; - #ifdef X11GAMMA -Display *dpy; -XF86VidModeGamma x11_oldgamma; +XRRCrtcGamma** gammaRamps = NULL; +int noGammaRamps = 0; +#endif + +#if SDL_VERSION_ATLEAST(2, 0, 0) +// some compatibility defines +#define SDL_SRCCOLORKEY SDL_TRUE +#define SDL_FULLSCREEN SDL_WINDOW_FULLSCREEN +#define SDL_OPENGL SDL_WINDOW_OPENGL + #endif /* @@ -70,7 +91,6 @@ GLimp_Init(void) { if (!SDL_WasInit(SDL_INIT_VIDEO)) { - char driverName[64]; if (SDL_Init(SDL_INIT_VIDEO) == -1) { @@ -78,8 +98,12 @@ GLimp_Init(void) SDL_GetError()); return false; } - +#if SDL_VERSION_ATLEAST(2, 0, 0) + const char* driverName = SDL_GetCurrentVideoDriver(); +#else + char driverName[64]; SDL_VideoDriverName(driverName, sizeof(driverName) - 1); +#endif VID_Printf(PRINT_ALL, "SDL video driver is \"%s\".\n", driverName); } @@ -102,7 +126,7 @@ static void SetSDLIcon() { SDL_Surface *icon; - SDL_Color color; + SDL_Color transColor, solidColor; Uint8 *ptr; int i; int mask; @@ -118,17 +142,28 @@ SetSDLIcon() SDL_SetColorKey(icon, SDL_SRCCOLORKEY, 0); - color.r = 255; - color.g = 255; - color.b = 255; + transColor.r = 255; + transColor.g = 255; + transColor.b = 255; - SDL_SetColors(icon, &color, 0, 1); + solidColor.r = 0; + solidColor.g = 16; + solidColor.b = 0; - color.r = 0; - color.g = 16; - color.b = 0; +#if SDL_VERSION_ATLEAST(2, 0, 0) + // only SDL2 has alphas there and they must be set apparently + transColor.a = 0; + solidColor.a = 255; - SDL_SetColors(icon, &color, 1, 1); + SDL_Palette* palette = SDL_AllocPalette(256); + SDL_SetPaletteColors(palette, &transColor, 0, 1); + SDL_SetPaletteColors(palette, &solidColor, 1, 1); + + SDL_SetSurfacePalette(icon, palette); +#else + SDL_SetColors(icon, &transColor, 0, 1); + SDL_SetColors(icon, &solidColor, 1, 1); +#endif ptr = (Uint8 *)icon->pixels; @@ -140,11 +175,57 @@ SetSDLIcon() ptr++; } } - +#if SDL_VERSION_ATLEAST(2, 0, 0) + SDL_SetWindowIcon(window, icon); + SDL_FreePalette(palette); +#else SDL_WM_SetIcon(icon, NULL); +#endif + SDL_FreeSurface(icon); } +/* + * from SDL2 SDL_CalculateGammaRamp, adjusted for arbitrary ramp sizes + * because xrandr seems to support ramp sizes != 256 (in theory at least) + */ +void CalculateGammaRamp(float gamma, Uint16* ramp, int len) +{ + int i; + + /* Input validation */ + if (gamma < 0.0f ) { + return; + } + if (ramp == NULL) { + return; + } + + /* 0.0 gamma is all black */ + if (gamma == 0.0f) { + for (i = 0; i < len; ++i) { + ramp[i] = 0; + } + return; + } else if (gamma == 1.0f) { + /* 1.0 gamma is identity */ + for (i = 0; i < len; ++i) { + ramp[i] = (i << 8) | i; + } + return; + } else { + /* Calculate a real gamma ramp */ + int value; + gamma = 1.0f / gamma; + for (i = 0; i < len; ++i) { + value = (int) (pow((double) i / (double) len, gamma) * 65535.0 + 0.5); + if (value > 65535) { + value = 65535; + } + ramp[i] = (Uint16) value; + } + } +} /* * Sets the hardware gamma */ @@ -152,31 +233,264 @@ SetSDLIcon() void UpdateHardwareGamma(void) { - float gamma; - XF86VidModeGamma x11_gamma; + float gamma = (vid_gamma->value); + int i; - gamma = vid_gamma->value; + Display* dpy = NULL; + SDL_SysWMinfo info; - x11_gamma.red = gamma; - x11_gamma.green = gamma; - x11_gamma.blue = gamma; +#if SDL_VERSION_ATLEAST(2, 0, 0) + SDL_VERSION(&info.version); + if(!SDL_GetWindowWMInfo(window, &info)) +#else + if(SDL_GetWMInfo(&info) != 1) +#endif + { + VID_Printf(PRINT_ALL, "Couldn't get Window info from SDL\n"); + return; + } - XF86VidModeSetGamma(dpy, screen, &x11_gamma); + dpy = info.info.x11.display; - /* This forces X11 to update the gamma tables */ - XF86VidModeGetGamma(dpy, screen, &x11_gamma); + XRRScreenResources* res = XRRGetScreenResources(dpy, info.info.x11.window); + if(res == NULL) + { + VID_Printf(PRINT_ALL, "Unable to get xrandr screen resources.\n"); + return; + } + + for(i=0; i < res->ncrtc; ++i) + { + int len = XRRGetCrtcGammaSize(dpy, res->crtcs[i]); + size_t rampSize = len*sizeof(Uint16); + Uint16* ramp = malloc(rampSize); // TODO: check for NULL + if(ramp == NULL) + { + VID_Printf(PRINT_ALL, "Couldn't allocate &zd byte of memory for gamma ramp - OOM?!\n", rampSize); + return; + } + + CalculateGammaRamp(gamma, ramp, len); + + XRRCrtcGamma* gamma = XRRAllocGamma(len); + + memcpy(gamma->red, ramp, rampSize); + memcpy(gamma->green, ramp, rampSize); + memcpy(gamma->blue, ramp, rampSize); + + free(ramp); + + XRRSetCrtcGamma(dpy, res->crtcs[i], gamma); + + XRRFreeGamma(gamma); + } + + XRRFreeScreenResources(res); } -#else +#else // no X11GAMMA void UpdateHardwareGamma(void) { - float gamma; + float gamma = (vid_gamma->value); - gamma = (vid_gamma->value); - SDL_SetGamma(gamma, gamma, gamma); -} + Uint16 ramp[256]; + CalculateGammaRamp(gamma, ramp, 256); +#if SDL_VERSION_ATLEAST(2, 0, 0) + if(SDL_SetWindowGammaRamp(window, ramp, ramp, ramp) != 0) { +#else + if(SDL_SetGammaRamp(ramp, ramp, ramp) < 0) { #endif + VID_Printf(PRINT_ALL, "Setting gamma failed: %s\n", SDL_GetError()); + } +} +#endif // X11GAMMA + +static qboolean IsFullscreen() +{ +#if SDL_VERSION_ATLEAST(2, 0, 0) + return !!(SDL_GetWindowFlags(window) & SDL_WINDOW_FULLSCREEN); +#else + return !!(window->flags & SDL_FULLSCREEN); +#endif +} + +static qboolean CreateSDLWindow(int flags) +{ +#if SDL_VERSION_ATLEAST(2, 0, 0) + int windowPos = SDL_WINDOWPOS_UNDEFINED; + // TODO: support fullscreen on different displays with SDL_WINDOWPOS_UNDEFINED_DISPLAY(displaynum) + window = SDL_CreateWindow("Yamagi Quake II", windowPos, windowPos, + vid.width, vid.height, flags); + + if(window == NULL) + { + return false; + } + + context = SDL_GL_CreateContext(window); + if(context == NULL) + { + SDL_DestroyWindow(window); + window = NULL; + return false; + } + + // set vsync - TODO: -1 could be set for "late swap tearing", + // i.e. only vsync if framerate is high enough + SDL_GL_SetSwapInterval(gl_swapinterval->value ? 1 : 0); + + return true; +#else + window = SDL_SetVideoMode(vid.width, vid.height, 0, flags); + return window != NULL; +#endif +} + +static qboolean GetWindowSize(int* w, int* h) +{ + if(window == NULL || w == NULL || h == NULL) + return false; + +#if SDL_VERSION_ATLEAST(2, 0, 0) + SDL_DisplayMode m; + if(SDL_GetWindowDisplayMode(window, &m) != 0) + { + VID_Printf(PRINT_ALL, "Can't get Displaymode: %s\n", SDL_GetError()); + return false; + } + *w = m.w; + *h = m.h; +#else + *w = window->w; + *h = window->h; +#endif + + return true; +} + +static void InitGamma() +{ +#ifdef X11GAMMA + int i=0; + SDL_SysWMinfo info; + Display* dpy = NULL; + + if(gammaRamps != NULL) // already saved gamma + return; + +#if SDL_VERSION_ATLEAST(2, 0, 0) + SDL_VERSION(&info.version); + if(!SDL_GetWindowWMInfo(window, &info)) +#else + if(SDL_GetWMInfo(&info) != 1) +#endif + { + VID_Printf(PRINT_ALL, "Couldn't get Window info from SDL\n"); + return; + } + + dpy = info.info.x11.display; + + XRRScreenResources* res = XRRGetScreenResources(dpy, info.info.x11.window); + if(res == NULL) + { + VID_Printf(PRINT_ALL, "Unable to get xrandr screen resources.\n"); + return; + } + + noGammaRamps = res->ncrtc; + gammaRamps = calloc(noGammaRamps, sizeof(XRRCrtcGamma*)); + if(gammaRamps == NULL) { + VID_Printf(PRINT_ALL, "Couldn't allocate memory for %d gamma ramps - OOM?!\n", noGammaRamps); + return; + } + + for(i=0; i < noGammaRamps; ++i) + { + int len = XRRGetCrtcGammaSize(dpy, res->crtcs[i]); + size_t rampSize = len*sizeof(Uint16); + + XRRCrtcGamma* origGamma = XRRGetCrtcGamma(dpy, res->crtcs[i]); + + XRRCrtcGamma* gammaCopy = XRRAllocGamma(len); + + memcpy(gammaCopy->red, origGamma->red, rampSize); + memcpy(gammaCopy->green, origGamma->green, rampSize); + memcpy(gammaCopy->blue, origGamma->blue, rampSize); + + gammaRamps[i] = gammaCopy; + } + + XRRFreeScreenResources(res); + + VID_Printf(PRINT_ALL, "Using hardware gamma via X11/xRandR.\n"); + +#else + VID_Printf(PRINT_ALL, "Using hardware gamma via SDL.\n"); +#endif + gl_state.hwgamma = true; + vid_gamma->modified = true; +} + +#ifdef X11GAMMA +static void RestoreGamma() +{ + int i=0; + SDL_SysWMinfo info; + Display* dpy = NULL; + + if(gammaRamps == NULL) + return; + +#if SDL_VERSION_ATLEAST(2, 0, 0) + SDL_VERSION(&info.version); + if(!SDL_GetWindowWMInfo(window, &info)) +#else + if(SDL_GetWMInfo(&info) != 1) +#endif + { + VID_Printf(PRINT_ALL, "Couldn't get Window info from SDL\n"); + return; + } + + dpy = info.info.x11.display; + + XRRScreenResources* res = XRRGetScreenResources(dpy, info.info.x11.window); + if(res == NULL) + { + VID_Printf(PRINT_ALL, "Unable to get xrandr screen resources.\n"); + return; + } + + for(i=0; i < noGammaRamps; ++i) + { + // in case a display was unplugged or something, noGammaRamps may be > res->ncrtc + if(i < res->ncrtc) + { + int len = XRRGetCrtcGammaSize(dpy, res->crtcs[i]); + if(len != gammaRamps[i]->size) { + VID_Printf(PRINT_ALL, "WTF, gamma ramp size for display %d has changed from %d to %d!\n", + i, gammaRamps[i]->size, len); + + continue; + } + + XRRSetCrtcGamma(dpy, res->crtcs[i], gammaRamps[i]); + } + + // the ramp needs to be free()d either way + XRRFreeGamma(gammaRamps[i]); + gammaRamps[i] = NULL; + + } + XRRFreeScreenResources(res); + free(gammaRamps); + gammaRamps = NULL; + + VID_Printf(PRINT_ALL, "Restored original Gamma\n"); +} +#endif // X11GAMMA /* * Initializes the OpenGL window @@ -189,30 +503,32 @@ GLimp_InitGraphics(qboolean fullscreen) int stencil_bits; char title[24]; - if (surface && (surface->w == vid.width) && (surface->h == vid.height)) - { - /* Are we running fullscreen? */ - int isfullscreen = (surface->flags & SDL_FULLSCREEN) ? 1 : 0; + int width, height; - /* We should, but we don't */ - if (fullscreen != isfullscreen) + if (GetWindowSize(&width, &height) && (width == vid.width) && (height == vid.height)) + { + /* If we want fullscreen, but aren't */ + if (fullscreen != IsFullscreen()) { - SDL_WM_ToggleFullScreen(surface); + GLimp_ToggleFullscreen(); } - /* Do we now? */ - isfullscreen = (surface->flags & SDL_FULLSCREEN) ? 1 : 0; - - if (fullscreen == isfullscreen) + /* Are we now? */ + if (fullscreen == IsFullscreen()) { return true; } } /* Is the surface used? */ - if (surface) + if (window) { - SDL_FreeSurface(surface); +#if SDL_VERSION_ATLEAST(2, 0, 0) + SDL_GL_DeleteContext(context); + SDL_DestroyWindow(window); +#else + SDL_FreeSurface(window); +#endif } /* Create the window */ @@ -233,7 +549,8 @@ GLimp_InitGraphics(qboolean fullscreen) flags |= SDL_FULLSCREEN; } - /* Set the icon */ +#if !SDL_VERSION_ATLEAST(2, 0, 0) + /* Set the icon - for SDL1.2 this must be done before creating the window */ SetSDLIcon(); /* Enable vsync */ @@ -241,10 +558,11 @@ GLimp_InitGraphics(qboolean fullscreen) { SDL_GL_SetAttribute(SDL_GL_SWAP_CONTROL, 1); } +#endif while (1) { - if ((surface = SDL_SetVideoMode(vid.width, vid.height, 0, flags)) == NULL) + if (!CreateSDLWindow(flags)) { if (counter == 1) { @@ -270,6 +588,10 @@ GLimp_InitGraphics(qboolean fullscreen) break; } } +#if SDL_VERSION_ATLEAST(2, 0, 0) + /* Set the icon - for SDL2 this must be done after creating the window */ + SetSDLIcon(); +#endif /* Initialize the stencil buffer */ if (!SDL_GL_GetAttribute(SDL_GL_STENCIL_SIZE, &stencil_bits)) @@ -283,34 +605,15 @@ GLimp_InitGraphics(qboolean fullscreen) } /* Initialize hardware gamma */ -#ifdef X11GAMMA - if ((dpy = XOpenDisplay(displayname)) == NULL) - { - VID_Printf(PRINT_ALL, "Unable to open display.\n"); - } - else - { - if (screen == -1) - { - screen = DefaultScreen(dpy); - } - - gl_state.hwgamma = true; - vid_gamma->modified = true; - - XF86VidModeGetGamma(dpy, screen, &x11_oldgamma); - - VID_Printf(PRINT_ALL, "Using hardware gamma via X11.\n"); - } -#else - gl_state.hwgamma = true; - vid_gamma->modified = true; - VID_Printf(PRINT_ALL, "Using hardware gamma via SDL.\n"); -#endif + InitGamma(); /* Window title */ snprintf(title, sizeof(title), "Yamagi Quake II %s", VERSION); +#if SDL_VERSION_ATLEAST(2, 0, 0) + SDL_SetWindowTitle(window, title); +#else SDL_WM_SetCaption(title, title); +#endif /* No cursor */ SDL_ShowCursor(0); @@ -324,7 +627,11 @@ GLimp_InitGraphics(qboolean fullscreen) void GLimp_EndFrame(void) { +#if SDL_VERSION_ATLEAST(2, 0, 0) + SDL_GL_SwapWindow(window); +#else SDL_GL_SwapBuffers(); +#endif } /* @@ -353,6 +660,60 @@ GLimp_SetMode(int *pwidth, int *pheight, int mode, qboolean fullscreen) return rserr_ok; } +/* + * Toggle fullscreen. + */ +void GLimp_ToggleFullscreen(void) +{ +#if SDL_VERSION_ATLEAST(2, 0, 0) + int wantFullscreen = !IsFullscreen(); + + SDL_SetWindowFullscreen(window, wantFullscreen ? SDL_WINDOW_FULLSCREEN : 0); + Cvar_SetValue("vid_fullscreen", wantFullscreen); +#else + SDL_WM_ToggleFullScreen(window); + + if (IsFullscreen()) + { + Cvar_SetValue("vid_fullscreen", 1); + } + else + { + Cvar_SetValue("vid_fullscreen", 0); + } +#endif + vid_fullscreen->modified = false; +} + +/* + * (Un)grab Input + */ +void GLimp_GrabInput(qboolean grab) +{ +#if SDL_VERSION_ATLEAST(2, 0, 0) + SDL_SetWindowGrab(window, grab ? SDL_TRUE : SDL_FALSE); + if(grab) + SDL_SetRelativeMouseMode(SDL_TRUE); + +#else + SDL_WM_GrabInput(grab ? SDL_GRAB_ON : SDL_GRAB_OFF); +#endif +} + +/* + * returns true if input is grabbed, else false + */ +qboolean GLimp_InputIsGrabbed() +{ +#if SDL_VERSION_ATLEAST(2, 0, 0) + return SDL_GetWindowGrab(window) ? true : false; +#else + SDL_GrabMode m = SDL_WM_GrabInput(SDL_GRAB_QUERY); + return m == SDL_GRAB_ON; +#endif +} + + /* * Shuts the SDL render backend down */ @@ -371,12 +732,26 @@ GLimp_Shutdown(void) GLimp_EndFrame(); } - if (surface) +#ifdef X11GAMMA + RestoreGamma(); +#endif + + if (window) { - SDL_FreeSurface(surface); +#if SDL_VERSION_ATLEAST(2, 0, 0) + SDL_DestroyWindow(window); + + if(context) + { + SDL_GL_DeleteContext(context); + context = NULL; + } +#else + SDL_FreeSurface(window); +#endif } - surface = NULL; + window = NULL; if (SDL_WasInit(SDL_INIT_EVERYTHING) == SDL_INIT_VIDEO) { @@ -387,16 +762,6 @@ GLimp_Shutdown(void) SDL_QuitSubSystem(SDL_INIT_VIDEO); } -#ifdef X11GAMMA - if (gl_state.hwgamma == true) - { - XF86VidModeSetGamma(dpy, screen, &x11_oldgamma); - - /* This forces X11 to update the gamma tables */ - XF86VidModeGetGamma(dpy, screen, &x11_oldgamma); - } -#endif - gl_state.hwgamma = false; } diff --git a/src/backends/sdl/sound.c b/src/backends/sdl/sound.c index 1d6b895f..023badbe 100644 --- a/src/backends/sdl/sound.c +++ b/src/backends/sdl/sound.c @@ -34,13 +34,15 @@ */ /* SDL includes */ -#ifdef _WIN32 +#if defined(_WIN32) || defined(__APPLE__) +#ifdef SDL2 +#include +#else // SDL1.2 #include -#elif defined(__APPLE__) -#include -#else +#endif //SDL2 +#else // not _WIN32 || APPLE #include -#endif +#endif // _WIN32 || APPLE /* Local includes */ #include "../../client/header/client.h" @@ -1188,7 +1190,6 @@ SDL_Callback(void *data, Uint8 *stream, int length) qboolean SDL_BackendInit(void) { - char drivername[128]; char reqdriver[128]; SDL_AudioSpec desired; SDL_AudioSpec obtained; @@ -1206,7 +1207,11 @@ SDL_BackendInit(void) int sndchans = (Cvar_Get("sndchannels", "2", CVAR_ARCHIVE))->value; #ifdef _WIN32 +#if SDL_VERSION_ATLEAST(2, 0, 0) + s_sdldriver = (Cvar_Get("s_sdldriver", "directsound", CVAR_ARCHIVE)); +#else s_sdldriver = (Cvar_Get("s_sdldriver", "dsound", CVAR_ARCHIVE)); +#endif #elif __linux__ s_sdldriver = (Cvar_Get("s_sdldriver", "alsa", CVAR_ARCHIVE)); #elif __APPLE__ @@ -1215,7 +1220,7 @@ SDL_BackendInit(void) s_sdldriver = (Cvar_Get("s_sdldriver", "dsp", CVAR_ARCHIVE)); #endif - snprintf(reqdriver, sizeof(drivername), "%s=%s", "SDL_AUDIODRIVER", s_sdldriver->string); + snprintf(reqdriver, sizeof(reqdriver), "%s=%s", "SDL_AUDIODRIVER", s_sdldriver->string); putenv(reqdriver); Com_Printf("Starting SDL audio callback.\n"); @@ -1228,11 +1233,21 @@ SDL_BackendInit(void) return 0; } } +#if SDL_VERSION_ATLEAST(2, 0, 0) + const char* drivername = SDL_GetCurrentAudioDriver(); + if(drivername == NULL) + { + drivername = "(UNKNOWN)"; + } +#else + char drivername[128]; if (SDL_AudioDriverName(drivername, sizeof(drivername)) == NULL) { strcpy(drivername, "(UNKNOWN)"); } +#endif + Com_Printf("SDL audio driver is \"%s\".\n", drivername); diff --git a/src/backends/unix/main.c b/src/backends/unix/main.c index 6da1a15f..680f7a6c 100644 --- a/src/backends/unix/main.c +++ b/src/backends/unix/main.c @@ -77,6 +77,12 @@ main(int argc, char **argv) #ifndef DEDICATED_ONLY printf("Client build options:\n"); +#ifdef SDL2 + printf(" + SDL2\n"); +#else + printf(" - SDL2 (using 1.2)\n"); +#endif + #ifdef CDA printf(" + CD audio\n"); #else diff --git a/src/backends/windows/system.c b/src/backends/windows/system.c index c179aae1..fc2479c5 100644 --- a/src/backends/windows/system.c +++ b/src/backends/windows/system.c @@ -712,6 +712,11 @@ WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, #ifndef DEDICATED_ONLY printf("Client build options:\n"); +#ifdef SDL2 + printf(" + SDL2\n"); +#else + printf(" - SDL2 (using 1.2)\n"); +#endif #ifdef CDA printf(" + CD audio\n"); #else diff --git a/src/client/refresh/header/local.h b/src/client/refresh/header/local.h index 7c2cd38c..07efa6c0 100644 --- a/src/client/refresh/header/local.h +++ b/src/client/refresh/header/local.h @@ -418,4 +418,19 @@ int GLimp_SetMode(int *pwidth, int *pheight, int mode, qboolean fullscreen); */ void *GLimp_GetProcAddress (const char* proc); +/* + * Toggle fullscreen. + */ +void GLimp_ToggleFullscreen(void); + +/* + * (Un)grab Input + */ +void GLimp_GrabInput(qboolean grab); + +/* + * returns true if input is grabbed, else false + */ +qboolean GLimp_InputIsGrabbed(); + #endif