--- configure.in +++ configure.in @@ -2841,6 +2841,11 @@ dnl Do this on all platforms, after everything else. CheckWarnAll +if test \( x$enable_video = xyes -a x$enable_video_opengl = xyes \) -o x$video_opengl = xyes; then + AC_DEFINE(SDL_VIDEO_DRIVER_OPENGLHQ) + SOURCES="$SOURCES $srcdir/src/video/openglhq/SDL*.c" +fi + # Verify that we have all the platform specific files we need if test x$enable_joystick = xyes; then --- include/SDL_config.h.in +++ include/SDL_config.h.in @@ -268,6 +268,7 @@ #undef SDL_VIDEO_DRIVER_GGI #undef SDL_VIDEO_DRIVER_IPOD #undef SDL_VIDEO_DRIVER_NANOX +#undef SDL_VIDEO_DRIVER_OPENGLHQ #undef SDL_VIDEO_DRIVER_OS2FS #undef SDL_VIDEO_DRIVER_PHOTON #undef SDL_VIDEO_DRIVER_PICOGUI --- include/SDL_video.h +++ include/SDL_video.h @@ -324,6 +324,14 @@ extern DECLSPEC SDL_Rect ** SDLCALL SDL_ListModes(SDL_PixelFormat *format, Uint32 flags); /** + * If possible, retrieves the current resolution of the user's display. If this + * operation is supported and succeeds, the width and height are written to the + * values pointed to by the parameters and 1 is returned. If unsupported or + * unsuccessful, the pointed to values are not touched and 0 is returned. + */ +extern DECLSPEC int SDLCALL SDL_GetDesktopMode(int *width, int *height); + +/** * Set up a video mode with the specified width, height and bits-per-pixel. * * If 'bpp' is 0, it is treated as the current display bits per pixel. --- src/events/SDL_mouse.c +++ src/events/SDL_mouse.c @@ -109,6 +109,8 @@ SDL_MouseMaxY = (Sint16)maxY; } +void (*SDL_MouseFilter)(int relative, Sint16 *x, Sint16 *y) = NULL; + /* These are global for SDL_eventloop.c */ int SDL_PrivateMouseMotion(Uint8 buttonstate, int relative, Sint16 x, Sint16 y) { @@ -122,6 +124,8 @@ buttonstate = SDL_ButtonState; } + if (SDL_MouseFilter != NULL) SDL_MouseFilter(relative, &x, &y); + Xrel = x; Yrel = y; if ( relative ) { @@ -203,6 +207,8 @@ SDL_memset(&event, 0, sizeof(event)); + if (SDL_MouseFilter != NULL) SDL_MouseFilter(0, &x, &y); + /* Check parameters */ if ( x || y ) { ClipOffset(&x, &y); --- src/main/macosx/SDLMain.m +++ src/main/macosx/SDLMain.m @@ -354,6 +354,9 @@ /* Main entry point to executable - should *not* be SDL_main! */ int main (int argc, char **argv) { + /* Enable multithreading as early as possible */ + [NSThread detachNewThreadSelector:@selector(self) toTarget:[NSString string] withObject:nil]; + /* Copy the arguments into a global variable */ /* This is passed if we are launched by double-clicking */ if ( argc >= 2 && strncmp (argv[1], "-psn", 4) == 0 ) { --- src/thread/pthread/SDL_systhread.c +++ src/thread/pthread/SDL_systhread.c @@ -44,7 +44,18 @@ static void *RunThread(void *data) { +#ifdef SDL_VIDEO_DRIVER_QUARTZ + extern void* QZ_allocPool(); + extern void QZ_freePool(void *p); + void *pool = QZ_allocPool(); +#endif + SDL_RunThread(data); + +#ifdef SDL_VIDEO_DRIVER_QUARTZ + QZ_freePool(pool); +#endif + pthread_exit((void*)0); return((void *)0); /* Prevent compiler warning */ } --- src/video/openglhq/asciidump.c +++ src/video/openglhq/asciidump.c @@ -0,0 +1,51 @@ +#include +#include +#include + +int main(int argc, char *argv[]) +{ + FILE *dat, *hdr; + char buffer[256], *name; + int i; + + if (argc != 3) { + fprintf(stderr,"wrong number of arguments\n"); + exit(1); + } + + dat = fopen(argv[1],"rb"); + hdr = fopen(argv[2],"w"); + if (dat == NULL || hdr == NULL) { + perror("file open"); + exit(2); + } + +#if defined (_MSC_VER) + name = strrchr(argv[1],'\\'); +#else + name = strrchr(argv[1],'/'); +#endif + if (name == NULL) name=argv[1]; + else name++; + name = strdup(name); + + for (i = 0; name[i]; i++) + if (!((name[i]>='a' && name[i]<='z') || (name[i]>='A' && name[i]<='Z') || (name[i]>='0' && name[i]<='9'))) + name[i] = '_'; + + fprintf(hdr,"#define %s \\\n", name); + while (!feof(dat) && fgets(buffer,256,dat)) { + buffer[strlen(buffer)-1] = 0; + + name = buffer; + while (*name == ' ' || *name == '\t') name++; + if (*name == 0 || *name == '#') continue; + + fprintf(hdr,"\"%s\\n\" \\\n",name); + } + fprintf(hdr,"\n"); + fclose(hdr); + fclose(dat); + + return 0; +} --- src/video/openglhq/hexdump.c +++ src/video/openglhq/hexdump.c @@ -0,0 +1,48 @@ +#include +#include +#include + +int main(int argc, char *argv[]) +{ + FILE *dat, *hdr; + char buffer[16], *name; + int i; + + if (argc != 3) { + fprintf(stderr,"wrong number of arguments\n"); + exit(1); + } + + dat = fopen(argv[1],"rb"); + hdr = fopen(argv[2],"w"); + if (dat == NULL || hdr == NULL) { + perror("file open"); + exit(2); + } + +#if defined (_MSC_VER) + name = strrchr(argv[1],'\\'); +#else + name = strrchr(argv[1],'/'); +#endif + if (name == NULL) name=argv[1]; + else name++; + name = strdup(name); + + for (i = 0; name[i]; i++) + if (!((name[i]>='a' && name[i]<='z') || (name[i]>='A' && name[i]<='Z') || (name[i]>='0' && name[i]<='9'))) + name[i] = '_'; + + fprintf(hdr,"#define %s { \\\n", name); + while (!feof(dat) && fread(buffer,16,1,dat)) { + for (i = 0; i < 16; i++) { + fprintf(hdr,"0x%02x,",(unsigned char)buffer[i]); + } + fprintf(hdr,"\\\n"); + } + fprintf(hdr,"}\n"); + fclose(hdr); + fclose(dat); + + return 0; +} --- src/video/openglhq/Makefile +++ src/video/openglhq/Makefile @@ -0,0 +1,35 @@ +## Makefile.am for SDL using OpenGL hardware HQ scaling + +all: SDL_openglhq_pass1.h SDL_openglhq_pass2.h SDL_openglhq_pass3.h SDL_openglhq_table.h + +patch: + ( cd ../../..; patch -sp1 < src/video/openglhq/SDL-1.2.diff && ./autogen.sh; ) + touch patch + +clean: + -rm tablebuilder SDL_openglhq_pass1.h SDL_openglhq_pass2.h SDL_openglhq_pass3.h SDL_openglhq_table.h hexdump asciidump + +zip: clean + (cd ..; zip -9 ~/SDL-1.2-openglhq-`date +%Y-%m-%d`.zip openglhq/{Makefile,README,*.diff,*.c,*.h,*.ui,*.fp,*.dat,*.DLL}) + +tablebuilder: tablebuilder.ui tablebuilder.ui.h + { echo '#!/usr/bin/python'; echo 'from qtcanvas import *'; pyuic -x $<; } > tablebuilder + chmod 755 tablebuilder + +HOSTCC=gcc + +asciidump: asciidump.c + $(HOSTCC) -o $(@F) $< + +hexdump: hexdump.c + $(HOSTCC) -o $(@F) $< + +test: test.c + gcc -o test test.c `sdl-config --cflags` `sdl-config --libs` + +%.h: %.fp asciidump + ./asciidump $< $@ + +%.h: %.dat hexdump + ./hexdump $< $@ + --- src/video/openglhq/README +++ src/video/openglhq/README @@ -0,0 +1,336 @@ +OpenGL-HQ for SDL +================= + +This readme documents version 2016-10-25 of OpenGL-HQ, if you got +a later version there's a slim chance I forgot to update this :) +The current version and screenshots can be downloaded from +http://www.syntax-k.de/projekte/sdl-opengl-hq/ + +OpenGL-HQ is a video "driver" for SDL that uses your graphics hardware +to scale the output to any size you want. It was originally written for +2D games/emulators like dosbox, scummvm or exult. + +WARNING: This is beta quality software. While it works nicely for me +and several other people, expect bugs to be present. If something +doesn't work, first check for a new version. Please mail me if you +encounter anything that's not yet listed in the README. + +Features: + - uses your hardware to get fast scaling + - scales any 2D SDL program + - scales with any scaling factor, even fractional ones + - switches back to the native driver if an app tries to use OpenGL + - portable + - configurable like SDL + - see the screenshots at the URL above, really + +Requirements: + - a Radeon 9600, GeForce 5700 or higher with current driver; + OpenGL extension ARB_fragment_program must be hardware + accelerated, EXT_framebuffer_object is recommended + -- Note: Since 2012, the fragment programs may no longer be + compatible with an acutal 9600. In case of problems + use an older version of *_pass3.fp + - OpenGL-support for your OS in SDL (which means Windows, + Linux/X11 or MacOS X) + +Limitations: + - may show bad performance with programs that already provide + high-resolution output or with high-quality driver settings + (Radeon 9600-9800 class chips are driven at their limits) + - might not work with FSAA enabled + - MacOS X untested (but should work) + - it has become very unlikely, but it is still possible that desktop + resolution is not autodetected correctly; use SDL_OPENGLHQ_FULLRES + in that case + - untested on non-x86 processors/non-mainstream graphics cards, + notably embedded/mobile platforms + +Bugs unlikely to be fixed, or of unknown origin: + - ATI's Triple-Buffering feature interferes with some apps; if you see + lockups or similar, try setting SDL_OPENGLHQ_DOUBLEBUF as shown below + -- needs to be confirmed against current drivers + +Bugs to be fixed: + +none known + +If you see any problems, CHECK THE TROUBLESHOOTING SECTION BELOW. +If your problem is not solved there, please write as detailed as you can: +Tell me what you did (exactly!), what you expected to happen, what +happened instead, and include screen shots of the problem. Include any +relevant config files as well (dosbox.conf for dosxbox, for example). + + + + +How to use (Quickstart) +======================= + +This is a MS Windows quickstart guide. Other systems adjust as needed. + +1) Copy SDL.DLL into the application's directory, overwriting the shipped + version + +2) Create a batch file (using Notepad) with these contents: + +set SDL_VIDEODRIVER=openglhq +set SDL_OPENGLHQ_WINRES=800x600 +.exe + +3) Save the file as .bat in the same directory + as the EXE file is + +4) Double-click this batch file to start the application; Create a shortcut + or adjust existing shortcuts to use this batch file + + + + +Configuration +============= + +Configuration is done via environment variables (just like the rest of SDL). It +is recommended to set these options in a batch file (see previous section). + +SDL_VIDEODRIVER - set it to openglhq to use OpenGL-HQ +SDL_OPENGLHQ_WINRES +SDL_OPENGLHQ_FULLRES - set to a resolution like "960x720" to set the windowed/ + fullscreen size in all windowed/fullscreen modes; you may + add a bit depth as in "960x720-16"; alternatively, you can + specify a fixed scaling factor (like "2.5") + default: windowed: "1", fullscreen: your desktop resolution +SDL_OPENGLHQ_VIDEODRIVER - set to the name of your SDL video device (the one you'd + normally use for SDL_VIDEODRIVER) +SDL_OPENGLHQ_DOUBLEBUF - override application's choice of doublebuffering; if set + to 1, doublebuffering is always on, if set to 0, doublebuffering + is always off; if unset, the application's choice is respected +SDL_OPENGLHQ_STATIC +SDL_OPENGLHQ_DYNAMIC - two parameters which tweak the HQ calculation; the defaults + (static 10, dynamic 33) are fine in most cases; to optimize + rendering, play with these values (static 0-255, dynamic 0-100) +SDL_OPENGLHQ_SHOWFPS - print average FPS to the console every ten seconds; this + only counts frames actually rendered. See FAQ below. +SDL_OPENGLHQ_DATA - a directory with data files for OpenGL-HQ; You can use this + to load your own fragment programs or edge detect table. + Currently, you will have to read the source code for details. + +You must set SDL_VIDEODRIVER to get any effect at all. If you want windowed +applications to be scaled, set SDL_OPENGLHQ_WINRES. Everything else is usually not +neccessary, the settings are autodetected. + +If you want to set options for ALL SDL apps, you can do so: + +Windows: Control Panel -> System Properties -> Advanced -> Environment Variables +Unix-like systems: add "export =" to ~/.profile + + +Performance +=========== + +To put it short: Absolutely great. + +On hardware barely meeting the minimal requirements, running a demanding +protected-mode high-resolution SVGA program in DOSBox with frameskip 0 and +scaling by a factor of 2, performance drops by just 20%. At frameskip 4, +performance difference is at 5-10%. + +At VGA resolution scaling by 4, the difference is reduced even more: +12% performance loss at frameskip 0. Software scaling is far worse: Normal2x +costs about 20%, advmame2x is at 25%, hq2x (not my optimized version, but the +slower HiEnd3D version) about 40%. + +Above measurements done on a single-core Athlon 3700+. On a dual-core processor, +there is no noticeable speed impact, since OpenGL-HQ uses a second core if +available. + + +Troubleshooting +=============== + +Q: Something doesn't work or looks weird. + +A: Check that you are running the latest official video drivers. It has not been + tested with hacked drivers, and old drivers are known to fail. + +Q: DosBox crashes. + +A: DosBox has bad error handling at video initialization. Until that's fixed, + a crash most probably means your hardware doesn't support OpenGL-HQ. + +Q: DosBox locks up when trying to go fullscreen + +A: ATI driver issue. Set "fulldouble=false" in your dosbox.conf, or set + SDL_OPENGLHQ_DOUBLEBUF + +Q: Performance is terrible! + +A: You've probably set forced vsync-waiting in Catalsyst Control Center and your + app wants double buffering (like "fulldouble=true" in DosBox). On a Radeon + 9600-9800 class chip, that's simply too much at higher resolutions. These + first fully programmable chips are used to their limits, so that's barely + surprising. + +Q: It works partly, but some video modes look exactly like before. +Q: Output looks much worse than in your screenshots, blurry and not sharp at all. +Q: WTF? I did everything as shown, and nothing changed? + +A: Disable all software scaling in your program. Many emulators default to some + kind of scaling, but OpenglHQ can only work with x1 (no) scaling. Moreover, + if the program's output is larger than the selected window size, the output + is scaled down using traditional bilinear filtering. + +Q: My mouse is slow! How can I speed it up? +A: This should mostly be fixed in the last release, but your backend video driver + might change acceleration setting when grabbing the mouse. At least the x11 + driver does that, and you can configure it using environment variables. + +Q: I only get 8 FPS! What crap is this software? +A: The screen is not continuously rendered like in native 3D programs. If the + emulator/emulated program only updates the screen 8 times per second, + OpenGL-HQ will show just 8 FPS. If you want to test how fast OpenGL-HQ can + go on your machine, use a program that does frequent screen updates. + +For more help, contact me at info@syntax-k.de. + +Please DO NOT mail Sam Lantinga or the SDL team about this, they aren't involved in this +in any way at all. + + + +Developer info +============== + +If you are an application developer, you can use the "putenv" (POSIX) / "_putenv" +(MSVC) call to change these settings from within your program. For example, if you +want to enable openglhq, just use: + + putenv("SDL_VIDEODRIVER=openglhq"); + +Of course, to be a fair player, you'd want to save the old value of SDL_VIDEODRIVER +first and set SDL_OPENGLHQ_VIDEODRIVER to that value, like this: + +void EnableOpenglHQ() +{ + static char entry[1024], *oldentry; + oldentry = getenv("SDL_VIDEODRIVER"); + if (oldentry != NULL) { + strcpy(entry, "SDL_OPENGLHQ_VIDEODRIVER="); + strcat(entry, oldentry); + putenv(entry); + } + putenv("SDL_VIDEODRIVER=openglhq"); +} + +void DisableOpenglHQ() +{ + static char entry[1024], *oldentry; + oldentry = getenv("SDL_OPENGLHQ_VIDEODRIVER"); + if (oldentry != NULL) { + strcpy(entry, "SDL_VIDEODRIVER="); + strcat(entry, oldentry); + putenv(entry); + } else { + putenv("SDL_VIDEODRIVER"); + } +} + +Do the same for other configuration variables. One exception is SDL_OPENGLHQ_DOUBLEBUF, +this is intended for users only - developers should use the SDL_DOUBLEBUF flag as usual. + +I've included a DosBox patch for those that want to enable openglhq in +dosbox.conf. It applies to a fairly old version of DOSBox, so you may want to +use the DOSBox build from http://ykhwong.x-y.net/ instead, which is kept up to +date and includes OpenGL-HQ support. + + + + +How to compile +============== + +This assumes you know how to compile C programs under a GNUish environment +(Linux, MingW, MacOS X with extra GNU tools). If you never used "cvs", "patch" +or "make" before, try to get a guide on these topics first. [some helpful soul +please send me a link] + +First, get and extract a copy of the SDL-1.2.15 sources. Other versions have not +been tested. + +Then, move the directory "openglhq" (the one this README is in) below src/video + +Then, patch SDL and create needed data files. cd into the SDL directory and run + +make -C src/video/openglhq + +Watch closely for errors! If you see any, check that you have a recent autoconf +and automake installed, and that you are indeed using a clean source tree of +SDL. + +Now run configuration: + +./configure + +Check that it found your OpenGL libraries and headers. If it doesn't, this code +is automatically disabled. Check "./configure --help" to see how to tell SDL the +location of your GL libraries and headers. + +Finally, compile and install: + +make && make install + +The resulting library should be a drop-in replacement for your existing +libSDL.so/SDL.DLL. It should be binary compatible, meaning that none of the apps +using it must be recompiled. + + + + +License +======= + + SDL OpenGL-HQ - Simple DirectMedia Layer high quality hardware scaling + Copyright (C) 2005, 2006, 2012 Jörg Walter + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library 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 + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with this library; if not, write to the Free + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +The SDL patch uses code published on the SDL mailing list in January 2005 for +desktop resolution autodetect. + +Credits +======= + +Many thanks to all VOGONS users who assited in testing and providing windows +builds. Even more thanks to gulikoza from the VOGONS forums for porting the code +to EXT_framebuffer_object. + + +History +======= + +2016-10-25 improve ListModes, required for ScummVM 1.7.0 +2012-10-19 fix 15-bit mode; it never worked, which shows how rarely it is used +2012-10-17 (b) fix problems with odd video mode widths +2012-10-17 fix/improve math precision for modern screen resolutions, fix + partial screen update bug in (default) fast mode, add optional + FPS output +2006-12-15 fix a subtle mouse movemement bug mainly observable in fullscreen + apps, improve API compatibility, reduce needless pixel copying, + working MacOS X support +2006-11-22 fix 16-bit video modes on ATI cards, improve compilation sequence, + improve rendering accuracy and speed by reducing complexity +2006-11-21 use EXT_framebuffer_object extension for rendering, fix threading + issues, improve performance, port to SDL-1.2, make 64-bit-clean + --- src/video/openglhq/SDL_ohqthread.h +++ src/video/openglhq/SDL_ohqthread.h @@ -0,0 +1,1118 @@ +/* + * OpenGL-HQ rendering code Copyright (C) 2004-2005 Jörg Walter + * + * 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ +/* $Id$ */ +/*--------------------------------------------------------------------- + This code implements a hardware-accelerated, cross-platform OpenGL + based scaler quite similar to the well known Hq2x..Hq4x suite of + software scalers. The general idea is exactly the same, but nothing + else remains: in contrast to my software-hq2x scaler for dosbox, not + even the interpolation rules have been used. Instead, they were + designed from scratch to look well even on high scaling factors. + + Some compromises had to be taken, and it is indeed possible that + my choice of rules don't fit some particular game. For this reason, + the built-in table can be overridden by placing a file called + "openglhq_table.dat" into the working directory. It will + be loaded instead of the shipped table. Use the tablebuilder to + edit the table file. Likewise, you can change the fragment programs + used by creating files called "openglhq_passN.fp" for + N = 1..3. + + As with the software hq2x scaler, the difference calculation is + based on the algorithm described in + http://www.compuphase.com/cmetric.htm, and the edge threshold + calculation has entirely been conceived by me. + + Limitations: + + - None. + + - No really, there are none. + + - Believe me, absolutely none. Even performance is great, current + builds use about as much CPU as software normal2x scaling in dosbox, + and that's on a low-end Mobility Radeon 9700. + + - Everything said applies to a Mobility Radeon 9700. Faster cards + might yield the previous statement untrue, I don't own an Nvidia + card, etc. While I tried to create a universal high-performance, + high-quality scaler, YMMV and Send Patches(tm). + +*/ + +#ifndef _GNU_SOURCE +#define _GNU_SOURCE +#endif + +#include "SDL.h" +#include "SDL_ohqvideo.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#ifndef SCHED_IDLE +#define SCHED_IDLE 5 +#endif + +#include "SDL_opengl.h" + +#ifndef APIENTRY +#define APIENTRY +#endif +#ifndef O_BINARY +#define O_BINARY (0) +#endif + +#define OHQNAME(x) x +/*SDL_OHQ_ ## x*/ + +typedef void * (APIENTRY * OHQ_malloc_t) (int size, float readfreq, float writefreq, float priority); +typedef void (APIENTRY * OHQ_free_t) (void *pointer); + +static OHQ_malloc_t OHQ_malloc = NULL; +static OHQ_free_t OHQ_free = NULL; + +static PFNGLPIXELDATARANGENVPROC OHQNAME(glPixelDataRangeNV) = NULL; + +/* supported only on fairly recent video cards (somewhere around ATI Radeon 9500 or a similar NVidia card) */ +static PFNGLPROGRAMSTRINGARBPROC OHQNAME(glProgramStringARB) = NULL; +static PFNGLBINDPROGRAMARBPROC OHQNAME(glBindProgramARB) = NULL; +static PFNGLGENPROGRAMSARBPROC OHQNAME(glGenProgramsARB) = NULL; +static PFNGLDELETEPROGRAMSARBPROC OHQNAME(glDeleteProgramsARB) = NULL; +static PFNGLGETPROGRAMIVARBPROC OHQNAME(glGetProgramivARB) = NULL; +static PFNGLPROGRAMLOCALPARAMETER4DARBPROC OHQNAME(glProgramLocalParameter4dARB) = NULL; +static PFNGLPROGRAMENVPARAMETER4DARBPROC OHQNAME(glProgramEnvParameter4dARB) = NULL; +static PFNGLCOLORTABLEEXTPROC OHQNAME(glColorTableEXT) = NULL; + +#include "SDL_openglhq_pass1.h" +#include "SDL_openglhq_pass2.h" +#include "SDL_openglhq_pass3.h" +#include "SDL_openglhq_table.h" + +/* framebuffer object extension */ +#ifndef GL_EXT_framebuffer_object +#define GL_EXT_framebuffer_object 1 +typedef void (APIENTRY * PFNGLGENFRAMEBUFFERSEXTPROC) (GLsizei n, GLuint *framebuffers); +typedef void (APIENTRY * PFNGLBINDFRAMEBUFFEREXTPROC) (GLenum target, GLuint framebuffer); +typedef void (APIENTRY * PFNGLFRAMEBUFFERTEXTURE2DEXTPROC) (GLenum target, GLenum attachment, + GLenum textarget, GLuint texture, GLint level); +typedef void (APIENTRY * PFNGLDELETEFRAMEBUFFERSEXTPROC) (GLsizei n, const GLuint *framebuffers); +typedef GLenum (APIENTRY * PFNGLCHECKFRAMEBUFFERSTATUSEXTPROC) (GLenum target); + +// Constants +#define GL_FRAMEBUFFER_EXT 0x8D40 +#define GL_COLOR_ATTACHMENT0_EXT 0x8CE0 + +#define GL_FRAMEBUFFER_COMPLETE_EXT 0x8CD5 +#define GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT_EXT 0x8CD6 +#define GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT_EXT 0x8CD7 +#define GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS_EXT 0x8CD9 +#define GL_FRAMEBUFFER_INCOMPLETE_FORMATS_EXT 0x8CDA +#define GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER_EXT 0x8CDB +#define GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER_EXT 0x8CDC +#define GL_FRAMEBUFFER_UNSUPPORTED_EXT 0x8CDD +#endif + +static PFNGLGENFRAMEBUFFERSEXTPROC OHQNAME(glGenFramebuffersEXT) = NULL; +static PFNGLBINDFRAMEBUFFEREXTPROC OHQNAME(glBindFramebufferEXT) = NULL; +static PFNGLCHECKFRAMEBUFFERSTATUSEXTPROC OHQNAME(glCheckFramebufferStatusEXT) = NULL; +static PFNGLFRAMEBUFFERTEXTURE2DEXTPROC OHQNAME(glFramebufferTexture2DEXT) = NULL; +static PFNGLDELETEFRAMEBUFFERSEXTPROC OHQNAME(glDeleteFramebuffersEXT) = NULL; + +#define OHQ_RESOLUTION 16 +//#define OGL_DEBUG_HQ +//#define OGL_DEBUG_HQ_MAX +#define OHQ_FAST + +#define fmax(x,y) ((x)>(y)?(x):(y)) +#define fmin(x,y) ((x)<(y)?(x):(y)) + +static int safe_semwait(SDL_sem *sem) { + while (SDL_SemWait(sem) != 0) SDL_Delay(1); + return 0; +} +#define SDL_SemWait safe_semwait + +static int int_log2 (int val) { + int log = 0; + while ((val >>= 1) != 0) + log++; + return log; +} + +/* instead of a plain malloc, we try to be nice to DMA-using hardware */ +#define MALLOC_ALIGN 4096 +#define align_upwards(x) ((void *)((intptr_t)((x) + MALLOC_ALIGN - 1) & ~(MALLOC_ALIGN-1))) +static void * APIENTRY default_malloc(int size, float readfreq, float writefreq, float priority) { + char *ptr = (char *)malloc(size+sizeof(void*)+MALLOC_ALIGN-1); + char *retval = (char *)align_upwards(ptr + sizeof(void*)); + void **real_ptr = (void **)(retval-sizeof(void*)); + *real_ptr = ptr; + return retval; +} + +static void APIENTRY default_free(void *pointer) { + void **real_ptr = (void **)((char *)pointer-sizeof(void*)); + free(*real_ptr); +} + +static unsigned int LoadNativeFragmentProgram(_THIS, const char *program, const char *filename) { + GLuint name; + int errorPos, isNative, programFd; + char programString[65536] = ""; + const char *dir; + + OHQNAME(glGenProgramsARB)(1,&name); + OHQNAME(glBindProgramARB)(GL_FRAGMENT_PROGRAM_ARB,name); + if ((dir = getenv("SDL_OPENGLHQ_DATA")) != NULL) { + strcpy(programString,dir); + strcat(programString,filename); + strcat(programString,".fp"); + + if ((programFd = open(programString,O_RDONLY)) >= 0) { + read(programFd,programString,sizeof(programString)); + close(programFd); + program = programString; + } + } + OHQNAME(glProgramStringARB)(GL_FRAGMENT_PROGRAM_ARB, GL_PROGRAM_FORMAT_ASCII_ARB, strlen(program), program); + + this->hidden->real_video->glGetIntegerv(GL_PROGRAM_ERROR_POSITION_ARB, &errorPos); + OHQNAME(glGetProgramivARB)(GL_FRAGMENT_PROGRAM_ARB, GL_PROGRAM_UNDER_NATIVE_LIMITS_ARB, &isNative); + if (errorPos >= 0) { + SDL_SetError("OPENGLHQ: Failed to load fragment program: %s",this->hidden->real_video->glGetString(GL_PROGRAM_ERROR_STRING_ARB)); + OHQNAME(glDeleteProgramsARB)(1,&name); + return 0; + } else if (!isNative) { + SDL_SetError("OPENGLHQ: Hardware doesn't support this fragment program"); + OHQNAME(glDeleteProgramsARB)(1,&name); + return 0; + } + return name; +} + +static double sign(double a) { + return (a < 0?-1:1); +} + +/* + This function calculates what percentage of a rectangle intersected by a line lies near the center of the + cordinate system. It is mathematically exact, and well-tested for xcenter > 0 and ycenter > 0 (it's only + used that way). It should be correct for other cases as well, but well... famous last words :) +*/ +static double intersect_any(double xcenter, double ycenter, double xsize, double ysize, double yoffset, double gradient) { + double g = fabs(gradient)*xsize/ysize; + double o = -((yoffset-ycenter) + gradient*xcenter)/ysize*sign(ycenter)*sign(yoffset)-g*0.5+0.5; + double yl = o, yr = o+g, xb = -o/g, xt = (1-o)/g; + double area = 1.0; + + if (yl >= 1.0) xt = xb = area = 0.0; + else if (yl > 0.0) { + area = 1.0-yl; + xb = 0.0; + } + else if (yr <= 0.0) yl = yr = area = 1.0; + else yl = o+xb*g; + + if (xt <= 0.0) yr = yl = area = 0.0; + else if (xt < 1.0) { + area *= xt; + yr = 1.0; + } + else if (xb >= 1.0) xb = xt = area = 1.0; + else xt = (yr-o)/g; + + area -= (xt-xb)*(yr-yl)/2; + + return area; +} + +static double intersect_h(double xcenter, double ycenter, double xsize, double ysize) { + return fmax(0.0,fmin(1.0,(.55-fabs(xcenter)+xsize/2.0)/xsize)); + //return fmax(0.0,fmin(1.0,(.50-fabs(xcenter)+xsize/2.0)/xsize)); +} + +static double intersect_any_h(double xcenter, double ycenter, double xsize, double ysize, double yoffset, double gradient) { + double hinside = intersect_h(xcenter,ycenter,xsize,ysize); + return hinside*hinside*intersect_any(xcenter,ycenter,xsize,ysize,yoffset,gradient); +} + +static double intersect_v(double xcenter, double ycenter, double xsize, double ysize) { + return fmax(0.0,fmin(1.0,(.55-fabs(ycenter)+ysize/2.0)/ysize)); + //return fmax(0.0,fmin(1.0,(.50-fabs(ycenter)+ysize/2.0)/ysize)); +} + +static double intersect_any_v(double xcenter, double ycenter, double xsize, double ysize, double yoffset, double gradient) { + double vinside = intersect_v(xcenter,ycenter,xsize,ysize); + return vinside*vinside*intersect_any(xcenter,ycenter,xsize,ysize,yoffset,gradient); +} + +static double intersect_hv(double xcenter, double ycenter, double xsize, double ysize) { + double hinside = intersect_h(xcenter,ycenter,xsize,ysize); + double vinside = intersect_v(xcenter,ycenter,xsize,ysize); + return (1-hinside)*(1-vinside)+hinside*vinside; +} + +/* FIXME: not sure if this is correct, but it is rare enough and most likely near enough. fixes welcome :) */ +static double intersect_any_hv(double xcenter, double ycenter, double xsize, double ysize, double yoffset, double gradient) { + double hvinside = intersect_hv(xcenter,ycenter,xsize,ysize); + return hvinside*hvinside*intersect_any(xcenter,ycenter,xsize,ysize,yoffset,gradient); +} + +static double intersect_hvd(double xcenter, double ycenter, double xsize, double ysize) { + return intersect_h(xcenter,ycenter,xsize,ysize)*intersect_v(xcenter,ycenter,xsize,ysize); +} + +static void setinterp(double xcenter, double ycenter, double percentage_inside, int i1, int i2, int i3, int o1, int o2, int o3, unsigned char *factors) { + double d0, d1, d2, d3, percentage_outside, totaldistance_i, totaldistance_o; + xcenter = fabs(xcenter); + ycenter = fabs(ycenter); + d0 = (1-xcenter)*(1-ycenter); + d1 = xcenter*(1-ycenter); + d2 = (1-xcenter)*ycenter; + d3 = xcenter*ycenter; + if (i1 && i2) i3 = 0; + if (o1 && o2) o3 = 0; + percentage_outside = 1.0-percentage_inside; + totaldistance_i = d0+i1*d1+i2*d2+i3*d3; + totaldistance_o = o1*d1+o2*d2+o3*d3+1e-12; /* +1e-12: prevent division by zero */ + + factors[1] = (unsigned char)(((d1/totaldistance_i*percentage_inside*i1)+(d1/totaldistance_o*percentage_outside*o1))*255+.5); + factors[2] = (unsigned char)(((d2/totaldistance_i*percentage_inside*i2)+(d2/totaldistance_o*percentage_outside*o2))*255+.5); + factors[3] = (unsigned char)(((d3/totaldistance_i*percentage_inside*i3)+(d3/totaldistance_o*percentage_outside*o3))*255+.5); + factors[0] = 255-factors[1]-factors[2]-factors[3];/*(unsigned char)((d0/totaldistance_i*percentage_inside)*255+.5);*/ +} + +/* Wanna have gcc fun? #define this as a macro, get a fast machine and go fetch a coffe or two. See how it is used to get an idea why. + I aborted compilation after 5 minutes of CPU time on an Athlon64 3700+. */ +static int swap_bits(int num, int bit1, int bit2) { + return ((num & ~(bit1|bit2))|((num&bit1)?bit2:0)|((num&bit2)?bit1:0)); +} + +/* +static void WaitCommand(_THIS) { + if (this->hidden->busy) SDL_SemWait(this->hidden->render_thread_ack); + this->hidden->busy = 0; +} +*/ + +static void SendAsyncCommand(_THIS, enum OGL_CMD command) { + if (this->hidden->busy) SDL_SemWait(this->hidden->render_thread_ack); + this->hidden->busy = 1; + this->hidden->cmd = command; + SDL_SemPost(this->hidden->render_thread_signal); +} +static int TryWaitCommand(_THIS) { + if (this->hidden->busy && SDL_SemTryWait(this->hidden->render_thread_ack) != 0) return 0; + this->hidden->busy = 0; + return 1; +} + +static int SendSyncCommand(_THIS, enum OGL_CMD command) { + int result; + + if (this->hidden->busy) SDL_SemWait(this->hidden->render_thread_ack); + this->hidden->busy = 1; + this->hidden->cmd = command; + SDL_SemPost(this->hidden->render_thread_signal); + SDL_SemWait(this->hidden->render_thread_ack); + + result = (this->hidden->status != OGL_ERROR); + this->hidden->busy = 0; + return result; +} + +static void Finish(_THIS, GLuint fbo) { + if (fbo) OHQNAME(glBindFramebufferEXT)(GL_FRAMEBUFFER_EXT, fbo); + this->hidden->real_video->glFinish(); + + OHQNAME(glBindProgramARB)(GL_FRAGMENT_PROGRAM_ARB,0); + this->hidden->real_video->glDisable(GL_FRAGMENT_PROGRAM_ARB); + + this->hidden->real_video->glActiveTexture(GL_TEXTURE2); + this->hidden->real_video->glBindTexture(GL_TEXTURE_2D,0); + this->hidden->real_video->glBindTexture(GL_TEXTURE_3D,0); + this->hidden->real_video->glActiveTexture(GL_TEXTURE1); + this->hidden->real_video->glBindTexture(GL_TEXTURE_2D,0); + this->hidden->real_video->glBindTexture(GL_TEXTURE_3D,0); + this->hidden->real_video->glActiveTexture(GL_TEXTURE0); + this->hidden->real_video->glBindTexture(GL_TEXTURE_2D,0); + this->hidden->real_video->glBindTexture(GL_TEXTURE_3D,0); + + this->hidden->real_video->glDisable(GL_TEXTURE_2D); + this->hidden->real_video->glDisable(GL_TEXTURE_3D); + + this->hidden->real_video->glFinish(); + if (fbo) OHQNAME(glBindFramebufferEXT)(GL_FRAMEBUFFER_EXT, 0); +} + +static void DeinitOpenGL(_THIS) { + int i; + + if (this->hidden->real_video->glFinish != NULL) { + Finish(this,0); + if (this->hidden->fbo[0]) { + Finish(this,this->hidden->fbo[0]); + Finish(this,this->hidden->fbo[1]); + } + } + + for (i = 0; i < sizeof(this->hidden->program_name)/sizeof(this->hidden->program_name[0]); i++) { + if (this->hidden->program_name[i] != 0) { + OHQNAME(glDeleteProgramsARB)(1,&this->hidden->program_name[i]); + this->hidden->program_name[i] = 0; + } + } + if (this->hidden->texture[0] != 0) { + this->hidden->real_video->glDeleteTextures(4,this->hidden->texture); + this->hidden->real_video->glDeleteLists(this->hidden->pbuffer_displaylist, 1); + this->hidden->real_video->glDeleteLists(this->hidden->displaylist, 1); + this->hidden->texture[0] = 0; + } + + if (this->hidden->fbo[0] != 0) { + OHQNAME(glDeleteFramebuffersEXT)(2, this->hidden->fbo); + this->hidden->fbo[0] = this->hidden->fbo[1] = 0; + } + + if (this->hidden->framebuf != NULL) { + OHQ_free(this->hidden->framebuf); + } +} + +static int showfps = 0; +static int RenderFrame(_THIS, int ack) { + static time_t lasttime = 0; + static int framecnt = 0; +#ifdef OHQ_FAST + static int lastx = 0, lasty = 0, lastex = 0, lastey = 0; + static int tmpx = 0, tmpy = 0, tmpex = 0, tmpey = 0; + int x = this->hidden->clip.x-1, y = this->hidden->clip.y-1, cw = this->hidden->clip.w+2, ch = this->hidden->clip.h+2, tw = this->hidden->width, th = this->hidden->height; + int dbuf = (this->hidden->flags&SDL_DOUBLEBUF) != 0; + + if (dbuf) { + tmpx = fmin(x, lastx); + tmpy = fmin(y, lasty); + tmpex = fmax(x+cw, lastex); + tmpey = fmax(y+ch, lastey); + lastx = x; + lasty = y; + lastex = x+cw; + lastey = y+ch; + x = tmpx; + y = tmpy; + cw = tmpex-x; + ch = tmpey-y; + } + + if (x < 0) x = 0; + if (y < 0) y = 0; + if (x+cw > this->hidden->width) cw = this->hidden->width-x; + if (y+ch > this->hidden->height) ch = this->hidden->height-y; + +#else + int dbuf = (this->hidden->flags&SDL_DOUBLEBUF) != 0; + int x = 0, y = 0, cw = this->hidden->width, ch = this->hidden->height, tw = cw, th = ch; +#endif + + this->hidden->real_video->glActiveTexture(GL_TEXTURE0); + this->hidden->real_video->glBindTexture(GL_TEXTURE_2D, this->hidden->texture[0]); + this->hidden->postponed = 0; + this->hidden->real_video->glTexSubImage2D(GL_TEXTURE_2D, 0, 0, y, + tw, ch, this->hidden->framebuf_format, + this->hidden->framebuf_datatype, this->hidden->framebuf+y*this->hidden->pitch); + + if (ack) SDL_SemPost(this->hidden->render_thread_ack); + +#ifdef OGL_DEBUG_HQ_MAX + GLubyte buffer[this->hidden->width*this->hidden->height*4]; + int fd = open("framebuf.pam",O_WRONLY|O_CREAT|O_TRUNC|O_BINARY,0666); + sprintf((char *)buffer,"P7\nWIDTH %i\nHEIGHT %i\nMAXVAL 255\nDEPTH 4\nTUPLTYPE RGB_ALPHA\nENDHDR\n",this->hidden->width,this->hidden->height); + write(fd,buffer,strlen((char *)buffer)); + write(fd,this->hidden->framebuf,this->hidden->pitch*this->hidden->height*2); + close(fd); +#endif + + /* align clip rectangle to reduce render errors due to rounding of coordinates, and add some padding */ + // seems not neccessary anymore +#define ALIGN 1 + int xe = x+cw+ALIGN+2, ye = y+ch+ALIGN+2; + int ox = x-2, oy = y-2; + ox = ((int)(x/ALIGN))*ALIGN; + oy = ((int)(y/ALIGN))*ALIGN; + xe = ((int)(xe/ALIGN))*ALIGN; + ye = ((int)(ye/ALIGN))*ALIGN; + if (ox < 0) ox = 0; + if (oy < 0) oy = 0; + if (xe > tw) xe = tw; + if (ye > th) ye = th; + int ocw = xe-ox; + int och = ye-oy; + + int otw = this->hidden->outwidth; + int oth = this->hidden->outheight; + ox = floor(ox*otw/(double)tw); + oy = floor((th-oy-och)*oth/(double)th); + //oy = floor(oy*oth/(double)th); + ocw = ceil(ocw*otw/(double)tw); + och = ceil(och*oth/(double)th); + + if (!this->hidden->nohq) { + this->hidden->real_video->glPushMatrix(); + if (this->hidden->fbo[0]) { + OHQNAME(glBindFramebufferEXT)(GL_FRAMEBUFFER_EXT, this->hidden->fbo[0]); + this->hidden->real_video->glViewport(x,y,cw,ch); + } else { + // "failsafe" fallback for drivers without EXT_framebuffer_object, also see below + // Performance and visual experience is degraded, but still enjoyable. + if (!dbuf) { + this->hidden->real_video->glDrawBuffer(GL_BACK); + this->hidden->real_video->glReadBuffer(GL_BACK); + } + this->hidden->real_video->glViewport(ox,oy,cw,ch); + } + + this->hidden->real_video->glTranslated(-1,-1,0); + this->hidden->real_video->glScaled(tw/(double)cw,th/(double)ch,1); + this->hidden->real_video->glTranslated(1.0-(x/(double)tw*2),1.0-(y/(double)th*2),0); + + OHQNAME(glBindProgramARB)(GL_FRAGMENT_PROGRAM_ARB,this->hidden->program_name[0]); + OHQNAME(glProgramLocalParameter4dARB)(GL_FRAGMENT_PROGRAM_ARB, 0, + ((double)this->hidden->static_threshold)/255.0, 0.0, + 0.0, ((double)this->hidden->dynamic_threshold)/100.0); + OHQNAME(glProgramEnvParameter4dARB)(GL_FRAGMENT_PROGRAM_ARB, 0, + 1.0d/this->hidden->texsize-1.0d/4096, 1.0d/this->hidden->texsize-1.0d/4096, + this->hidden->texsize, this->hidden->texsize); + + this->hidden->real_video->glCallList(this->hidden->pbuffer_displaylist); + this->hidden->real_video->glFinish(); + + this->hidden->real_video->glBindTexture(GL_TEXTURE_2D,this->hidden->texture[1]); + if (this->hidden->fbo[0]) OHQNAME(glBindFramebufferEXT)(GL_FRAMEBUFFER_EXT, this->hidden->fbo[1]); + else this->hidden->real_video->glCopyTexSubImage2D(GL_TEXTURE_2D, 0, x, y, ox, oy, cw, ch); + +#ifdef OGL_DEBUG_HQ_MAX + fd = open("diff1.pam",O_WRONLY|O_CREAT|O_TRUNC|O_BINARY,0666); + sprintf((char *)buffer,"P7\nWIDTH %i\nHEIGHT %i\nMAXVAL 255\nDEPTH 4\nTUPLTYPE RGB_ALPHA\nENDHDR\n",this->hidden->width,this->hidden->height); + write(fd,buffer,strlen((char *)buffer)); + this->hidden->real_video->glReadPixels(0,0,this->hidden->width,this->hidden->height,GL_RGBA,GL_UNSIGNED_BYTE,buffer); + write(fd,buffer,sizeof(buffer)); + close(fd); +#endif + + OHQNAME(glBindProgramARB)(GL_FRAGMENT_PROGRAM_ARB,this->hidden->program_name[1]); + OHQNAME(glProgramLocalParameter4dARB)(GL_FRAGMENT_PROGRAM_ARB, 0, + ((double)this->hidden->static_threshold)/255.0, 0.0, + 0.0, ((double)this->hidden->dynamic_threshold)/100.0); + + this->hidden->real_video->glCallList(this->hidden->pbuffer_displaylist); + this->hidden->real_video->glFinish(); + + this->hidden->real_video->glBindTexture(GL_TEXTURE_2D,this->hidden->texture[0]); + + this->hidden->real_video->glActiveTexture(GL_TEXTURE1); + this->hidden->real_video->glBindTexture(GL_TEXTURE_2D,this->hidden->texture[2]); + + if (this->hidden->fbo[0]) OHQNAME(glBindFramebufferEXT)(GL_FRAMEBUFFER_EXT, 0); + else { + this->hidden->real_video->glCopyTexSubImage2D(GL_TEXTURE_2D, 0, x, y, ox, oy, cw, ch); + if (!dbuf) { + this->hidden->real_video->glDrawBuffer(GL_FRONT); + this->hidden->real_video->glReadBuffer(GL_FRONT); + } + } + +#ifdef OGL_DEBUG_HQ_MAX + fd = open("diff2.pam",O_WRONLY|O_CREAT|O_TRUNC|O_BINARY,0666); + sprintf((char *)buffer,"P7\nWIDTH %i\nHEIGHT %i\nMAXVAL 255\nDEPTH 4\nTUPLTYPE RGB_ALPHA\nENDHDR\n",this->hidden->width,this->hidden->height); + write(fd,buffer,strlen((char *)buffer)); + this->hidden->real_video->glReadPixels(0,0,this->hidden->width,this->hidden->height,GL_RGBA,GL_UNSIGNED_BYTE,buffer); + write(fd,buffer,sizeof(buffer)); + close(fd); +#endif + + this->hidden->real_video->glActiveTexture(GL_TEXTURE0); + + OHQNAME(glBindProgramARB)(GL_FRAGMENT_PROGRAM_ARB,this->hidden->program_name[2]); + OHQNAME(glProgramEnvParameter4dARB)(GL_FRAGMENT_PROGRAM_ARB, 0, + 1.0d/this->hidden->texsize, 1.0d/this->hidden->texsize, + this->hidden->texsize, this->hidden->texsize); + + this->hidden->real_video->glPopMatrix(); + } + + this->hidden->real_video->glViewport(ox,oy,ocw,och); + this->hidden->real_video->glPushMatrix(); + this->hidden->real_video->glTranslated(-1,-1,0); + this->hidden->real_video->glScaled(otw/(double)ocw,oth/(double)och,1); + this->hidden->real_video->glTranslated(1.0-(ox/(double)otw*2),1.0-(oy/(double)oth*2),0); + this->hidden->real_video->glCallList(this->hidden->displaylist); + this->hidden->real_video->glPopMatrix(); + + if (dbuf) this->hidden->real_video->GL_SwapBuffers(this->hidden->real_video); + + if (showfps) { + time_t now = time(NULL); + framecnt++; + + if (lasttime == 0) { + lasttime = now; + } else if (now > lasttime+10) { + fprintf(stderr, "SDL OpenGL-HQ FPS: %li\n", framecnt/(now-lasttime)); + lasttime = now; + framecnt = 0; + } + } + this->hidden->real_video->glFlush(); + + return 1; +} + +static int InitOpenGL(_THIS) { + int w, h, bpp; + int border, x, y, texsize; + SDL_Surface *surface; + GLfloat tex_width, tex_height; + GLubyte *texture; + double xsize, ysize; + unsigned char table[4096] = SDL_openglhq_table_dat; + int has_fbo = 1; +// double adjust = 0; + + showfps = getenv("SDL_OPENGLHQ_SHOWFPS") != NULL; + + SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1);//(this->hidden->flags&SDL_DOUBLEBUF)!=0); + if (this->hidden->flags & SDL_FULLSCREEN) { + const char *res, *res2; + if ((res = getenv("SDL_OPENGLHQ_FULLRES")) != NULL) { + w = atoi(res); + res2 = strchr(res,'x'); + if (res2 == NULL) { + double scale = strtod(res,NULL); + w = (int)(this->hidden->width*scale); + h = (int)(this->hidden->height*scale); + bpp = this->hidden->format.BitsPerPixel; + } else { + h = atoi(res2+1); + res = strchr(res,'-'); + if (res != NULL) { + bpp = atoi(res+1); + } else { + bpp = this->hidden->format.BitsPerPixel; + } + } + } else { + w = this->hidden->screen_width; + h = this->hidden->screen_height; + bpp = this->hidden->format.BitsPerPixel; + } + } else { + const char *res, *res2; + if ((res = getenv("SDL_OPENGLHQ_WINRES")) != NULL) { + w = atoi(res); + res2 = strchr(res,'x'); + if (res2 == NULL) { + double scale = strtod(res,NULL); + w = (int)(this->hidden->width*scale); + h = (int)(this->hidden->height*scale); + bpp = this->hidden->format.BitsPerPixel; + } else { + h = atoi(res2+1); + res = strchr(res,'-'); + if (res != NULL) { + bpp = atoi(res+1); + } else { + bpp = this->hidden->format.BitsPerPixel; + } + } + } else { + w = this->hidden->width; + h = this->hidden->height; + bpp = this->hidden->format.BitsPerPixel; + } + } + + if (w <= 0 || h <= 0) { + SDL_SetError("Invalid mode specification in SDL_OPENGLHQ_WINRES/SDL_OPENGLHQ_FULLRES"); + return 0; + } + if (w > this->hidden->screen_width || h > this->hidden->screen_height) { + w = this->hidden->screen_width; + h = this->hidden->screen_height; + } + + surface = SDL_SetVideoMode(w,h,bpp,SDL_OPENGL|(this->hidden->flags&SDL_FULLSCREEN)); + if (surface == NULL) { + SDL_SetError("OPENGLHQ: Can't open drawing surface, are you running in 16bpp (or higher) mode?"); + return 0; + } + this->hidden->outwidth = surface->w; + this->hidden->outheight = surface->h; + + if (this->hidden->max_texsize == 0) { + const char * gl_ext = (const char *)this->hidden->real_video->glGetString(GL_EXTENSIONS); + + if (getenv("SDL_OPENGLHQ_STATIC") != NULL) this->hidden->static_threshold = atoi(getenv("SDL_OPENGLHQ_STATIC")); + else this->hidden->static_threshold = 10; + if (this->hidden->static_threshold > 255) this->hidden->static_threshold = 255; + if (this->hidden->static_threshold < 0) this->hidden->static_threshold = 0; + if (getenv("SDL_OPENGLHQ_DYNAMIC") != NULL) this->hidden->dynamic_threshold = atoi(getenv("SDL_OPENGLHQ_DYNAMIC")); + else this->hidden->dynamic_threshold = 33; + if (this->hidden->dynamic_threshold > 100) this->hidden->dynamic_threshold = 100; + if (this->hidden->dynamic_threshold < 0) this->hidden->dynamic_threshold = 0; + + this->hidden->real_video->glGetIntegerv(GL_MAX_TEXTURE_SIZE, &this->hidden->max_texsize); + OHQNAME(glPixelDataRangeNV) = (PFNGLPIXELDATARANGENVPROC)SDL_GL_GetProcAddress("glPixelDataRangeNV"); + OHQNAME(glColorTableEXT) = (PFNGLCOLORTABLEEXTPROC)SDL_GL_GetProcAddress("glColorTableEXT"); + + if (gl_ext != NULL && *gl_ext) { + this->hidden->has_pixel_data_range=(strstr(gl_ext,"GL_NV_pixel_data_range") != NULL) && OHQNAME(glPixelDataRangeNV) != NULL; + this->hidden->allow_paletted_texture=(strstr(gl_ext,"EXT_paletted_texture") != NULL) && OHQNAME(glColorTableEXT) != NULL; + + } + + if (this->hidden->has_pixel_data_range) { + OHQ_malloc = (OHQ_malloc_t)SDL_GL_GetProcAddress("wglAllocateMemoryNV"); + if (OHQ_malloc == NULL) OHQ_malloc = (OHQ_malloc_t)SDL_GL_GetProcAddress("glXAllocateMemoryNV"); + OHQ_free = (OHQ_free_t)SDL_GL_GetProcAddress("wglFreeMemoryNV"); + if (OHQ_free == NULL) OHQ_free = (OHQ_free_t)SDL_GL_GetProcAddress("glXFreeMemoryNV"); + } + if (OHQ_malloc == NULL) OHQ_malloc = (OHQ_malloc_t)default_malloc; + if (OHQ_free == NULL) OHQ_free = (OHQ_free_t)default_free; + + OHQNAME(glProgramStringARB) = (PFNGLPROGRAMSTRINGARBPROC)SDL_GL_GetProcAddress("glProgramStringARB"); + OHQNAME(glBindProgramARB) = (PFNGLBINDPROGRAMARBPROC)SDL_GL_GetProcAddress("glBindProgramARB"); + OHQNAME(glGenProgramsARB) = (PFNGLGENPROGRAMSARBPROC)SDL_GL_GetProcAddress("glGenProgramsARB"); + OHQNAME(glDeleteProgramsARB) = (PFNGLDELETEPROGRAMSARBPROC)SDL_GL_GetProcAddress("glDeleteProgramsARB"); + OHQNAME(glGetProgramivARB) = (PFNGLGETPROGRAMIVARBPROC)SDL_GL_GetProcAddress("glGetProgramivARB"); + OHQNAME(glProgramLocalParameter4dARB) = (PFNGLPROGRAMLOCALPARAMETER4DARBPROC)SDL_GL_GetProcAddress("glProgramLocalParameter4dARB"); + OHQNAME(glProgramEnvParameter4dARB) = (PFNGLPROGRAMENVPARAMETER4DARBPROC)SDL_GL_GetProcAddress("glProgramEnvParameter4dARB"); + + if (!gl_ext || !*gl_ext || !((strstr(gl_ext,"ARB_fragment_program") != NULL) && + OHQNAME(glProgramStringARB) && OHQNAME(glBindProgramARB) && OHQNAME(glGenProgramsARB) && OHQNAME(glDeleteProgramsARB) && + OHQNAME(glGetProgramivARB) && OHQNAME(glProgramLocalParameter4dARB) && OHQNAME(glProgramEnvParameter4dARB))) { + SDL_SetError("OPENGLHQ: Video driver doesn't support fragment programs"); + return 0; + } + + OHQNAME(glGenFramebuffersEXT) = (PFNGLGENFRAMEBUFFERSEXTPROC)SDL_GL_GetProcAddress("glGenFramebuffersEXT"); + OHQNAME(glBindFramebufferEXT) = (PFNGLBINDFRAMEBUFFEREXTPROC)SDL_GL_GetProcAddress("glBindFramebufferEXT"); + OHQNAME(glCheckFramebufferStatusEXT) = (PFNGLCHECKFRAMEBUFFERSTATUSEXTPROC)SDL_GL_GetProcAddress("glCheckFramebufferStatusEXT"); + OHQNAME(glFramebufferTexture2DEXT) = (PFNGLFRAMEBUFFERTEXTURE2DEXTPROC)SDL_GL_GetProcAddress("glFramebufferTexture2DEXT"); + OHQNAME(glDeleteFramebuffersEXT) = (PFNGLDELETEFRAMEBUFFERSEXTPROC)SDL_GL_GetProcAddress("glDeleteFramebuffersEXT"); + + if(!OHQNAME(glGenFramebuffersEXT) || !OHQNAME(glBindFramebufferEXT) || + !OHQNAME(glFramebufferTexture2DEXT) || !OHQNAME(glDeleteFramebuffersEXT) || + (strstr(gl_ext,"GL_EXT_framebuffer_object") == NULL)) { + has_fbo = 0; + fprintf(stderr, "OPENGLHQ: Video driver doesn't support framebuffer objects. Using slow fallback renderer.\n"); + } + + } + + this->hidden->framebuf_format = GL_BGRA_EXT; + this->hidden->framebuf_datatype = GL_UNSIGNED_BYTE; + if (this->hidden->bpp == 8 && !this->hidden->allow_paletted_texture) { + this->hidden->bpp = this->hidden->format.BitsPerPixel; + } + if (this->hidden->bpp == 8) { + this->hidden->framebuf_format = GL_COLOR_INDEX8_EXT; + OHQNAME(glColorTableEXT)(GL_TEXTURE_2D,GL_RGBA8,256,GL_RGBA,GL_UNSIGNED_BYTE,this->hidden->pal); + } else if (this->hidden->bpp == 15) { + this->hidden->framebuf_format = GL_BGRA_EXT; + this->hidden->framebuf_datatype = GL_UNSIGNED_SHORT_1_5_5_5_REV; + } else if (this->hidden->bpp == 16) { + this->hidden->framebuf_format = GL_RGB; + this->hidden->framebuf_datatype = GL_UNSIGNED_SHORT_5_6_5; + } else { + this->hidden->bpp = 32; + } + + texsize=this->hidden->texsize=2 << int_log2(this->hidden->width > this->hidden->height ? this->hidden->width : this->hidden->height); + texsize=this->hidden->texsize=2 << int_log2(this->hidden->width > this->hidden->height ? this->hidden->width : this->hidden->height); + tex_width=((GLfloat)(this->hidden->width)/(GLfloat)texsize); + tex_height=((GLfloat)(this->hidden->height)/(GLfloat)texsize); + + if (texsize>this->hidden->max_texsize) { + SDL_SetError("OPENGLHQ: No support for texturesize of %d, falling back to surface",texsize); + return 0; + } + + /* Create the texture and display list */ + this->hidden->real_video->glMatrixMode(GL_PROJECTION); + this->hidden->real_video->glGenTextures(4,this->hidden->texture); + + this->hidden->pitch=this->hidden->width*((this->hidden->bpp+7)/8); + this->hidden->framebuf = OHQ_malloc(this->hidden->pitch*this->hidden->height+MALLOC_ALIGN,0.0,1.0,1.0);; + + if (this->hidden->has_pixel_data_range) { + OHQNAME(glPixelDataRangeNV)(GL_WRITE_PIXEL_DATA_RANGE_NV,this->hidden->width*this->hidden->height*4,this->hidden->framebuf); + this->hidden->real_video->glEnableClientState(GL_WRITE_PIXEL_DATA_RANGE_NV); + } + + if ((this->hidden->program_name[0] = LoadNativeFragmentProgram(this, SDL_openglhq_pass1_fp,"SDL_openglhq_pass1")) == 0 || + (this->hidden->program_name[1] = LoadNativeFragmentProgram(this, SDL_openglhq_pass2_fp,"SDL_openglhq_pass2")) == 0 || + (this->hidden->program_name[2] = LoadNativeFragmentProgram(this, SDL_openglhq_pass3_fp,"SDL_openglhq_pass3")) == 0) { + SDL_SetError("OPENGLHQ: Hardware doesn't support this output"); + return 0; + } + + this->hidden->nohq = 1; + this->hidden->fbo[0] = this->hidden->fbo[1] = 0; + if (this->hidden->width < this->hidden->outwidth && this->hidden->height < this->hidden->outheight) { + this->hidden->nohq = 0; + + this->hidden->real_video->glBindTexture(GL_TEXTURE_2D, this->hidden->texture[1]); + this->hidden->real_video->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + this->hidden->real_video->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + this->hidden->real_video->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP); + this->hidden->real_video->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP); + this->hidden->real_video->glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, texsize, texsize, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL); + + this->hidden->real_video->glBindTexture(GL_TEXTURE_2D, this->hidden->texture[2]); + this->hidden->real_video->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + this->hidden->real_video->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + this->hidden->real_video->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP); + this->hidden->real_video->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP); + this->hidden->real_video->glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, texsize, texsize, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL); + + if (has_fbo) { + OHQNAME(glGenFramebuffersEXT)(2, this->hidden->fbo); + + OHQNAME(glBindFramebufferEXT)(GL_FRAMEBUFFER_EXT, this->hidden->fbo[0]); + OHQNAME(glFramebufferTexture2DEXT)(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_TEXTURE_2D, this->hidden->texture[1], 0); + + OHQNAME(glBindFramebufferEXT)(GL_FRAMEBUFFER_EXT, this->hidden->fbo[1]); + OHQNAME(glFramebufferTexture2DEXT)(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_TEXTURE_2D, this->hidden->texture[2], 0); + + OHQNAME(glBindFramebufferEXT)(GL_FRAMEBUFFER_EXT, 0); + } + } + + if ((this->hidden->flags&SDL_DOUBLEBUF) == 0) { + this->hidden->real_video->glDrawBuffer(GL_FRONT); + this->hidden->real_video->glReadBuffer(GL_FRONT); + } + this->hidden->real_video->glActiveTexture(GL_TEXTURE2); + this->hidden->real_video->glEnable(GL_TEXTURE_3D); + this->hidden->real_video->glBindTexture(GL_TEXTURE_3D, this->hidden->texture[3]); + this->hidden->real_video->glTexEnvi(GL_TEXTURE_ENV,GL_TEXTURE_ENV_MODE,GL_COMBINE); + this->hidden->real_video->glTexEnvi(GL_TEXTURE_ENV,GL_COMBINE_RGB,GL_REPLACE); + this->hidden->real_video->glTexEnvi(GL_TEXTURE_ENV,GL_COMBINE_ALPHA,GL_REPLACE); + this->hidden->real_video->glTexEnvi(GL_TEXTURE_ENV,GL_SRC0_RGB,GL_TEXTURE0); + this->hidden->real_video->glTexEnvi(GL_TEXTURE_ENV,GL_OPERAND0_RGB,GL_SRC_COLOR); + this->hidden->real_video->glTexEnvi(GL_TEXTURE_ENV,GL_SRC0_ALPHA,GL_TEXTURE0); + this->hidden->real_video->glTexEnvi(GL_TEXTURE_ENV,GL_OPERAND0_ALPHA,GL_SRC_ALPHA); + + texture = (GLubyte *)malloc(OHQ_RESOLUTION*OHQ_RESOLUTION*4096*4); + xsize = (double)this->hidden->width/(double)this->hidden->outwidth; + ysize = (double)this->hidden->height/(double)this->hidden->outheight; + + /* + Table layout is a bit convoluted to be better processable in + fragment programs and to save space. Use the table builder + to modify it. If you are interested in details, read its source. + */ + if (getenv("SDL_OPENGLHQ_DATA")) { + char file[4096]; + int tablefd; + strcpy(file,getenv("SDL_OPENGLHQ_DATA")); + strcat(file,"openglhq_table.dat"); + if ((tablefd = open(file,O_RDONLY|O_BINARY)) >= 0) { + read(tablefd,table,sizeof(table)); + close(tablefd); + } + } + +#define R 1 +#define T 2 +#define RT 4 +#define RT2 8 +#define L 16 +#define LB2 32 +#define LT2 64 +#define LT 128 +#define LB 256 +#define B 512 +#define RB2 1024 +#define RB 2048 + +#define NODIAG 0x90 +#define H 1 +#define V 2 +#define D 4 + +#define hmirror(p) swap_bits(swap_bits(swap_bits(swap_bits(swap_bits(p,R,L),RT,LT),RT2,LT2),RB,LB),RB2,LB2) +#define vmirror(p) swap_bits(swap_bits(swap_bits(swap_bits(swap_bits(p,T,B),RT,RB),RT2,RB2),LT,LB),LT2,LB2) +#define NO_BORDER(x) ((b&(x)) == 0) +#define IS_BORDER(x) ((b&(x)) == (x)) +#define SETINTERP(percentage_inside) setinterp(xcenter,ycenter,percentage_inside, \ + NO_BORDER(R),NO_BORDER(T),NO_BORDER(RT), \ + IS_BORDER(R),IS_BORDER(T),IS_BORDER(RT), \ + texture+((x+(border%16)*OHQ_RESOLUTION+y*16*OHQ_RESOLUTION+(border&~15)*OHQ_RESOLUTION*OHQ_RESOLUTION)*4)) + +/* if (getenv("SDL_OPENGLHQ_ADJUST")) + adjust = atof(getenv("SDL_OPENGLHQ_ADJUST")); + if (adjust == 0) adjust = 1.025; //1.0438 = ATI fglrx; 1.025 = generic +*/ +#define adjust 1 + OHQNAME(glProgramEnvParameter4dARB)(GL_FRAGMENT_PROGRAM_ARB, 1, 1.0d/.875d, -(1.0d/.875d-1.0d)/2, .875/adjust, (1-.875/adjust)/2); + + for (border = 0; border < 4096; border++) { + for (y = 0; y < OHQ_RESOLUTION; y++) { + for (x = 0; x < OHQ_RESOLUTION; x++) { + double xcenter = fabs((((double)x)+.5)/(double)(OHQ_RESOLUTION)-.5)*adjust; + double ycenter = fabs((((double)y)+.5)/(double)(OHQ_RESOLUTION)-.5)*adjust; + int sx = (x < OHQ_RESOLUTION/2?-1:1); + int sy = (y < OHQ_RESOLUTION/2?-1:1); + int b = (sy > 0?(sx > 0?border:hmirror(border)):(sx > 0?vmirror(border):vmirror(hmirror(border)))); + + if ((table[b] & NODIAG) == NODIAG) { + if (table[b] & H) { + if (table[b] & V) { + if (table[b] & D) SETINTERP(intersect_hvd(xcenter,ycenter,xsize,ysize)); + else SETINTERP(intersect_hv(xcenter,ycenter,xsize,ysize)); + } else { + SETINTERP(intersect_h(xcenter,ycenter,xsize,ysize)); + } + } else if (table[b] & V) { + SETINTERP(intersect_v(xcenter,ycenter,xsize,ysize)); + } else { + SETINTERP(1.0); + } + } else { + double yoff = (table[b]&4?1:-1)*(((table[b] >> 3) & 3) + 1)/4.0; + double grad = (table[b]&32?1:-1)*(((table[b] >> 6) & 3) + 1)/2.0; + if (table[b] & H) { + if (table[b] & V) { + SETINTERP(intersect_any_hv(xcenter,ycenter,xsize,ysize,yoff,grad)); + } else { + SETINTERP(intersect_any_h(xcenter,ycenter,xsize,ysize,yoff,grad)); + } + } else if (table[b] & V) { + SETINTERP(intersect_any_v(xcenter,ycenter,xsize,ysize,yoff,grad)); + } else { + SETINTERP(intersect_any(xcenter,ycenter,xsize,ysize,yoff,grad)); + } + } + + } + } + } +#ifdef OGL_DEBUG_HQ_MAX + int fd = open("texture.pam",O_WRONLY|O_CREAT|O_TRUNC|O_BINARY,0666); + sprintf((char *)table,"P7\nWIDTH %i\nHEIGHT %i\nMAXVAL 255\nDEPTH 4\nTUPLTYPE RGB_ALPHA\nENDHDR\n",16*OHQ_RESOLUTION,4096/16*OHQ_RESOLUTION); + write(fd,table,strlen((char *)table)); + write(fd,texture,OHQ_RESOLUTION*OHQ_RESOLUTION*4096*4); + close(fd); +#endif + + this->hidden->real_video->glTexImage3D(GL_TEXTURE_3D, 0, GL_RGBA8, 16*OHQ_RESOLUTION, OHQ_RESOLUTION, 256, 0, GL_RGBA, GL_UNSIGNED_BYTE, texture); + free(texture); + this->hidden->real_video->glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + this->hidden->real_video->glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + this->hidden->real_video->glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + this->hidden->real_video->glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + this->hidden->real_video->glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE); + + this->hidden->real_video->glActiveTexture(GL_TEXTURE0); + this->hidden->real_video->glBindTexture(GL_TEXTURE_2D,this->hidden->texture[0]); + this->hidden->real_video->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP); + this->hidden->real_video->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP); + GLenum filter = (this->hidden->nohq?GL_LINEAR:GL_NEAREST); + this->hidden->real_video->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, filter); + this->hidden->real_video->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, filter); + + this->hidden->real_video->glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, texsize, texsize, 0, this->hidden->framebuf_format, GL_UNSIGNED_BYTE, NULL); + this->hidden->real_video->glFinish(); + + this->hidden->real_video->glShadeModel(GL_FLAT); + this->hidden->real_video->glDisable(GL_DEPTH_TEST); + this->hidden->real_video->glDisable(GL_ALPHA_TEST); + this->hidden->real_video->glDisable(GL_STENCIL_TEST); + this->hidden->real_video->glDisable(GL_SCISSOR_TEST); + this->hidden->real_video->glDisable(GL_BLEND); + this->hidden->real_video->glDisable(GL_DITHER); + this->hidden->real_video->glDisable(GL_INDEX_LOGIC_OP); + this->hidden->real_video->glDisable(GL_COLOR_LOGIC_OP); + this->hidden->real_video->glDisable(GL_LIGHTING); + this->hidden->real_video->glDisable(GL_CULL_FACE); + this->hidden->real_video->glDisable(GL_FOG); + this->hidden->real_video->glEnable(GL_TEXTURE_2D); + if (this->hidden->nohq) { + this->hidden->real_video->glDisable(GL_FRAGMENT_PROGRAM_ARB); + } else { + this->hidden->real_video->glEnable(GL_FRAGMENT_PROGRAM_ARB); + } + this->hidden->real_video->glMatrixMode(GL_MODELVIEW); + this->hidden->real_video->glLoadIdentity(); + + this->hidden->pbuffer_displaylist = this->hidden->real_video->glGenLists(1); + this->hidden->real_video->glNewList(this->hidden->pbuffer_displaylist, GL_COMPILE); + this->hidden->real_video->glBegin(GL_QUADS); + this->hidden->real_video->glTexCoord2f(0,0); this->hidden->real_video->glVertex2f(-1.0f,-1.0f); + this->hidden->real_video->glTexCoord2f(tex_width,0); this->hidden->real_video->glVertex2f(1.0f, -1.0f); + this->hidden->real_video->glTexCoord2f(tex_width,tex_height); this->hidden->real_video->glVertex2f(1.0f, 1.0f); + this->hidden->real_video->glTexCoord2f(0,tex_height); this->hidden->real_video->glVertex2f(-1.0f, 1.0f); + this->hidden->real_video->glEnd(); + this->hidden->real_video->glEndList(); + + this->hidden->displaylist = this->hidden->real_video->glGenLists(1); + this->hidden->real_video->glNewList(this->hidden->displaylist, GL_COMPILE); + this->hidden->real_video->glBindTexture(GL_TEXTURE_2D, this->hidden->texture[0]); + this->hidden->real_video->glBegin(GL_QUADS); + this->hidden->real_video->glTexCoord2f(0,tex_height); this->hidden->real_video->glVertex2f(-1.0f,-1.0f); + this->hidden->real_video->glTexCoord2f(tex_width,tex_height); this->hidden->real_video->glVertex2f(1.0f, -1.0f); + this->hidden->real_video->glTexCoord2f(tex_width,0); this->hidden->real_video->glVertex2f(1.0f, 1.0f); + this->hidden->real_video->glTexCoord2f(0,0); this->hidden->real_video->glVertex2f(-1.0f, 1.0f); + this->hidden->real_video->glEnd(); + this->hidden->real_video->glEndList(); + this->hidden->real_video->glFinish(); + return 1; +} + +static int RenderThread(void *data) { + SDL_VideoDevice *this = (SDL_VideoDevice *)data; + SDL_Rect **modes; + const char *driver; + this->hidden->status = OGL_DONE; + current_video = NULL; + if ((driver = getenv("SDL_OPENGLHQ_VIDEODRIVER")) != NULL && !strcmp(driver,"openglhq")) driver = NULL; + SDL_VideoInit(driver, 0); + if (current_video == NULL) { + SDL_SetError("Unable to initialize backend video device, check SDL_OPENGLHQ_VIDEODRIVER"); + this->hidden->status = OGL_ERROR; + } else { + current_video->GL_LoadLibrary(current_video,NULL); + if (current_video->GetDesktopMode != NULL) { + current_video->GetDesktopMode(current_video,&this->hidden->screen_width,&this->hidden->screen_height); + } else { + modes = SDL_ListModes(NULL,SDL_OPENGL|SDL_FULLSCREEN); + if (((intptr_t)modes) != -1 && modes && *modes) { + this->hidden->screen_width = modes[0]->w; + this->hidden->screen_height = modes[0]->h; + } + } + } + SDL_SemPost(this->hidden->render_thread_ack); + + while (SDL_SemWait(this->hidden->render_thread_signal) >= 0) { + if (this->hidden->postponed && this->hidden->cmd != OGL_FRAME) { + RenderFrame(this, 0); + } + + this->hidden->status = OGL_DONE; + + if (this->hidden->cmd == OGL_CALL) { + switch (this->hidden->call.type) { + case OGL_CALL_P: + this->hidden->call.func.p(this->hidden->real_video); + break; + case OGL_CALL_PII: + this->hidden->call.func.pii(this->hidden->real_video,(int)this->hidden->call.args[0],(int)this->hidden->call.args[1]); + break; + case OGL_CALL_PPP: + this->hidden->call.func.ppp(this->hidden->real_video,(const void*)this->hidden->call.args[0],(const void*)this->hidden->call.args[1]); + break; + case OGL_CALL_PP: + this->hidden->call.func.pp(this->hidden->real_video,(const void*)this->hidden->call.args[0]); + break; + case OGL_CALL_PPPIIII_P: + this->hidden->call.result = (intptr_t)this->hidden->call.func.pppiiii_p(this->hidden->real_video,(const void*)this->hidden->call.args[0],(const void*)this->hidden->call.args[1], + (int)this->hidden->call.args[2],(int)this->hidden->call.args[3],(int)this->hidden->call.args[4],(int)this->hidden->call.args[5]); + break; + case OGL_CALL_PP_I: + this->hidden->call.result = (intptr_t)this->hidden->call.func.pp_i(this->hidden->real_video,(const void*)this->hidden->call.args[0]); + break; + case OGL_CALL_P_I: + this->hidden->call.result = (intptr_t)this->hidden->call.func.p_i(this->hidden->real_video); + break; + case OGL_CALL_PI_I: + this->hidden->call.result = (intptr_t)this->hidden->call.func.pi_i(this->hidden->real_video,(int)this->hidden->call.args[0]); + break; + default: + this->hidden->status = OGL_ERROR; + } + + } else if (this->hidden->cmd == OGL_INIT) { + if (!InitOpenGL(this)) { + this->hidden->status = OGL_ERROR; + DeinitOpenGL(this); + } + + // FIXME: ugly hack that probably only works on Linux, improves app responsiveness + setpriority(PRIO_PROCESS, getpid()+1, 19); + { // This is a bit more portable (should work on any POSIX/pthreads system), but SCHED_IDLE is ineffective on unpatched Linux + struct sched_param param = { 0 }; + pthread_setschedparam(pthread_self(), SCHED_IDLE, ¶m); + } + + } else if (this->hidden->cmd == OGL_DEINIT) { + DeinitOpenGL(this); + + } else if (this->hidden->cmd == OGL_FRAME) { + if (!RenderFrame(this, 1)) this->hidden->status = OGL_ERROR; + + } else if (this->hidden->cmd == OGL_PALETTE && this->hidden->allow_paletted_texture) { + this->hidden->real_video->glActiveTexture(GL_TEXTURE0); + OHQNAME(glColorTableEXT)(GL_TEXTURE_2D, GL_RGBA8, 256, GL_RGBA, GL_UNSIGNED_BYTE, this->hidden->pal); + + } else if (this->hidden->cmd == OGL_NONE) { + + } else if (this->hidden->cmd == OGL_QUIT) { + break; + + } else { + this->hidden->status = OGL_ERROR; + } + SDL_SemPost(this->hidden->render_thread_ack); + } + SDL_VideoQuit(); + SDL_SemPost(this->hidden->render_thread_ack); + return 0; +} + +static void StartRenderThread(_THIS) { + this->hidden->cmd = OGL_DONE; + this->hidden->render_thread_signal = SDL_CreateSemaphore(0); + this->hidden->render_thread_ack = SDL_CreateSemaphore(0); + this->hidden->render_thread = SDL_CreateThread(&RenderThread,this); + SDL_SemWait(this->hidden->render_thread_ack); +} + +static void ShutdownRenderThread(_THIS) { + if (this->hidden->render_thread != NULL) { + SendSyncCommand(this,OGL_DEINIT); + SendSyncCommand(this,OGL_QUIT); + SDL_WaitThread(this->hidden->render_thread, NULL); + SDL_DestroySemaphore(this->hidden->render_thread_signal); + SDL_DestroySemaphore(this->hidden->render_thread_ack); + this->hidden->render_thread = NULL; + } +} + --- src/video/openglhq/SDL_ohqvideo.c +++ src/video/openglhq/SDL_ohqvideo.c @@ -0,0 +1,586 @@ +/* + SDL - Simple DirectMedia Layer OpenGL-HQ scaling + Copyright (C) 1997-2004 Sam Lantinga + Copyright (C) 2005 Jörg Walter + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library 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 + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with this library; if not, write to the Free + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + + Sam Lantinga + slouken@libsdl.org +*/ + +#ifdef SAVE_RCSID +static char rcsid = + "@(#) $Id$"; +#endif + +/* SDL video driver implementation which outputs onto a scaled OpenGL-surface + with high quality scaling optimized for framebuffer based games +*/ + +#define TRACE //do { fprintf(stderr,"%s:%i: %p->%s(...)\n",__FILE__,__LINE__,SDL_ThreadID(),__FUNCTION__); } while (0) +#include +#include +#include +#include +#include + +#include "SDL.h" +#include "SDL_error.h" +#include "SDL_video.h" +#include "SDL_opengl.h" +#include "../SDL_pixels_c.h" +#include "../SDL_cursor_c.h" +#include "../SDL_sysvideo.h" +#include "../../events/SDL_events_c.h" +#include "SDL_ohqvideo.h" + +#include "SDL_ohqthread.h" + +#ifndef SDL_memcpy +#define SDL_memcpy memcpy +#endif + +static void OHQ_MouseFilter(int relative, Sint16 *x, Sint16 *y); +extern void (*SDL_MouseFilter)(int relative, Sint16 *x, Sint16 *y); +static void (*OHQ_NextMouseFilter)(int relative, Sint16 *x, Sint16 *y) = (void *)-1; +static SDL_VideoDevice* filter_video = NULL; +static int OHQ_VideoInit(_THIS, SDL_PixelFormat *vformat); + +/* OHQ driver bootstrap functions */ + +static int OHQ_Available(void) +{ + return 1; +} + +static void OHQ_DeleteDevice(SDL_VideoDevice *device) +{ + free(device->hidden); + free(device); +} + +static void OHQ_Call(_THIS, void (*func)(SDL_VideoDevice*)) +{ + if (this->VideoInit != OHQ_VideoInit) { + func(this); + } else if (SDL_ThreadID() == SDL_GetThreadID(this->hidden->render_thread)) { + func(this->hidden->real_video); + } else { + this->hidden->call.type = OGL_CALL_P; + this->hidden->call.func.p = func; + SendSyncCommand(this,OGL_CALL); + } +} + +static void OHQ_Call_ii(_THIS, void (*func)(SDL_VideoDevice*,int,int), int arg1, int arg2) +{ + if (this->VideoInit != OHQ_VideoInit) { + func(this,arg1,arg2); + } else if (SDL_ThreadID() == SDL_GetThreadID(this->hidden->render_thread)) { + func(this->hidden->real_video,arg1,arg2); + } else { + this->hidden->call.type = OGL_CALL_PII; + this->hidden->call.func.pii = func; + this->hidden->call.args[0] = (intptr_t)arg1; + this->hidden->call.args[1] = (intptr_t)arg2; + SendSyncCommand(this,OGL_CALL); + } +} + +static void OHQ_Call_pp(_THIS, void (*func)(SDL_VideoDevice*,const void*,const void*), const void* arg1, const void* arg2) +{ + if (this->VideoInit != OHQ_VideoInit) { + func(this,arg1,arg2); + } else if (SDL_ThreadID() == SDL_GetThreadID(this->hidden->render_thread)) { + func(this->hidden->real_video,arg1,arg2); + } else { + this->hidden->call.type = OGL_CALL_PPP; + this->hidden->call.func.ppp = func; + this->hidden->call.args[0] = (intptr_t)arg1; + this->hidden->call.args[1] = (intptr_t)arg2; + SendSyncCommand(this,OGL_CALL); + } +} + +static void OHQ_Call_p(_THIS, void (*func)(SDL_VideoDevice*,const void*), const void* arg1) +{ + if (this->VideoInit != OHQ_VideoInit) { + func(this,arg1); + } else if (SDL_ThreadID() == SDL_GetThreadID(this->hidden->render_thread)) { + func(this->hidden->real_video,arg1); + } else { + this->hidden->call.type = OGL_CALL_PP; + this->hidden->call.func.pp = func; + this->hidden->call.args[0] = (intptr_t)arg1; + SendSyncCommand(this,OGL_CALL); + } +} + +static int OHQ_Call_p_i(_THIS, int (*func)(SDL_VideoDevice*,const void*), const void* arg1) +{ + if (this->VideoInit != OHQ_VideoInit) { + return func(this,arg1); + } else if (SDL_ThreadID() == SDL_GetThreadID(this->hidden->render_thread)) { + return func(this->hidden->real_video,arg1); + } else { + this->hidden->call.type = OGL_CALL_PP_I; + this->hidden->call.func.pp_i = func; + this->hidden->call.args[0] = (intptr_t)arg1; + SendSyncCommand(this,OGL_CALL); + return (int)this->hidden->call.result; + } +} + +static int OHQ_Call__i(_THIS, int (*func)(SDL_VideoDevice*)) +{ + if (this->VideoInit != OHQ_VideoInit) { + return func(this); + } else if (SDL_ThreadID() == SDL_GetThreadID(this->hidden->render_thread)) { + return func(this->hidden->real_video); + } else { + this->hidden->call.type = OGL_CALL_P_I; + this->hidden->call.func.p_i = func; + SendSyncCommand(this,OGL_CALL); + return (int)this->hidden->call.result; + } +} + +static int OHQ_Call_i_i(_THIS, int (*func)(SDL_VideoDevice*,int), int arg1) +{ + if (this->VideoInit != OHQ_VideoInit) { + return func(this,arg1); + } else if (SDL_ThreadID() == SDL_GetThreadID(this->hidden->render_thread)) { + return func(this->hidden->real_video,arg1); + } else { + this->hidden->call.type = OGL_CALL_PI_I; + this->hidden->call.func.pi_i = func; + this->hidden->call.args[0] = (intptr_t)arg1; + SendSyncCommand(this,OGL_CALL); + return (int)this->hidden->call.result; + } +} + +static void* OHQ_Call_ppiiii_p(_THIS, void* (*func)(SDL_VideoDevice*,const void*,const void*,int,int,int,int), const void* arg1, const void* arg2, int arg3, int arg4, int arg5, int arg6) +{ + if (this->VideoInit != OHQ_VideoInit) { + return func(this,arg1,arg2,arg3,arg4,arg5,arg6); + } else if (SDL_ThreadID() == SDL_GetThreadID(this->hidden->render_thread)) { + return func(this->hidden->real_video,arg1,arg2,arg3,arg4,arg5,arg6); + } else { + this->hidden->call.type = OGL_CALL_PPPIIII_P; + this->hidden->call.func.pppiiii_p = func; + this->hidden->call.args[0] = (intptr_t)arg1; + this->hidden->call.args[1] = (intptr_t)arg2; + this->hidden->call.args[2] = (intptr_t)arg3; + this->hidden->call.args[3] = (intptr_t)arg4; + this->hidden->call.args[4] = (intptr_t)arg5; + this->hidden->call.args[5] = (intptr_t)arg6; + SendSyncCommand(this,OGL_CALL); + return (void*)this->hidden->call.result; + } +} + +#define SAVE_VIDEO { SDL_VideoDevice *saved_video = current_video; current_video = this->hidden->real_video; +#define RESTORE_VIDEO current_video = saved_video; } +#define SAVE_SCREEN { SDL_Surface *saved_screen = this->hidden->real_video->screen; this->hidden->real_video->screen = this->screen; +#define RESTORE_SCREEN this->hidden->real_video->screen = saved_screen; } + +static int OHQ_VideoInit(_THIS, SDL_PixelFormat *vformat) +{ + const SDL_VideoInfo *vinfo; + + fprintf(stderr, "SDL OpenGL-HQ initialized\n"); + SAVE_VIDEO; + + StartRenderThread(this); + this->hidden->real_video = current_video; + vinfo = SDL_GetVideoInfo(); + SDL_memcpy(vformat,(SDL_PixelFormat*)vinfo->vfmt,sizeof(*vinfo->vfmt)); + SDL_memcpy((void *)&this->hidden->format,(SDL_PixelFormat*)vinfo->vfmt,sizeof(*vinfo->vfmt)); + + RESTORE_VIDEO; + + return(0); +} + +static void OHQ_SwitchOff(_THIS) { + static char env[1024] = "SDL_VIDEODRIVER="; + SendSyncCommand(this,OGL_NONE); + current_video = this->hidden->real_video; + strcat(env,current_video->name); + ShutdownRenderThread(this); + putenv(env); + SDL_VideoInit(NULL,0); + free(this->hidden); + SDL_memcpy(this, current_video, sizeof(*current_video)); + current_video = this; + if (OHQ_NextMouseFilter != (void *)-1) { + SDL_MouseFilter = OHQ_NextMouseFilter; + OHQ_NextMouseFilter = (void *)-1; + } +} + +static SDL_Rect **OHQ_ListModes(_THIS, SDL_PixelFormat *format, Uint32 flags) { + if (flags & SDL_OPENGL) { + SDL_Rect **ret; + SAVE_VIDEO; + ret = current_video->ListModes(current_video, format, flags); + RESTORE_VIDEO; + return ret; + } + return (SDL_Rect **)(intptr_t)(format->BitsPerPixel == 8 && !this->hidden->allow_paletted_texture?0:-1); +} + +static SDL_Surface *OHQ_SetVideoMode(_THIS, SDL_Surface *current, int width, int height, int bpp, Uint32 flags) { + if (flags & SDL_OPENGL) { + fprintf(stderr, "SDL OpenGL-HQ disabled, application requests OpenGL\n"); + OHQ_SwitchOff(this); + return current_video->SetVideoMode(current_video,current,width,height,bpp,flags); + } + + fprintf(stderr, "SDL OpenGL-HQ enabled\n"); + SDL_UnlockCursor(); + + SendSyncCommand(this,OGL_NONE); + filter_video = current_video; + SAVE_VIDEO; + if (!SendSyncCommand(this,OGL_DEINIT)) return NULL; + if (this->hidden->surface == NULL) { + this->hidden->surface = malloc(sizeof(*current)); + SDL_memcpy((SDL_Surface *)this->hidden->surface,current,sizeof(*current)); + } + flags &= ~(SDL_HWPALETTE|SDL_HWSURFACE|SDL_ASYNCBLIT); + + // some video drivers can't handle odd widths properly + width = (width+1)&~1; + + this->hidden->width = width; + this->hidden->height = height; + this->hidden->flags = flags; + if (getenv("SDL_OPENGLHQ_DOUBLEBUF")) { + if (getenv("SDL_OPENGLHQ_DOUBLEBUF")[0] == '1') this->hidden->flags |= SDL_DOUBLEBUF; + else this->hidden->flags &= ~(SDL_DOUBLEBUF); + } + this->hidden->bpp = bpp; + this->hidden->postponed = 0; + if (!SendSyncCommand(this,OGL_INIT)) return NULL; + if (OHQ_NextMouseFilter == (void *)-1) { + OHQ_NextMouseFilter = SDL_MouseFilter; + SDL_MouseFilter = OHQ_MouseFilter; + } + bpp = this->hidden->bpp; + + if (!SDL_ReallocFormat(current, bpp, (bpp==32?0xff0000:bpp==16?0xf800:0x7c00), (bpp==32?0xff00:bpp==16?0x7e0:0x3e0), (bpp==32?0xff:0x1f), 0)) { + return NULL; + } + + current->w = this->hidden->width; + current->h = this->hidden->height; + current->pitch = this->hidden->pitch; + current->flags = flags|SDL_PREALLOC; + if (bpp == 8) current->flags |= SDL_HWPALETTE; + current->pixels = this->hidden->framebuf; + this->input_grab = this->hidden->real_video->input_grab; + + this->hidden->clip.x = 0; + this->hidden->clip.y = 0; + this->hidden->clip.w = current->w; + this->hidden->clip.h = current->h; + + RESTORE_VIDEO; + + return current; +} + +static void OHQ_UpdateMouse(_THIS) { + SAVE_VIDEO; + //SAVE_SCREEN; + OHQ_Call(this,this->hidden->real_video->UpdateMouse); + //RESTORE_SCREEN; + RESTORE_VIDEO; +} + +static int OHQ_SetColors(_THIS, int firstcolor, int ncolors, SDL_Color *colors) { + int i, end = firstcolor+ncolors; + if (end > 256) return 0; + for (i = firstcolor; i < end; i++) { + this->hidden->pal[i].r = colors[i].r; + this->hidden->pal[i].g = colors[i].g; + this->hidden->pal[i].b = colors[i].b; + this->hidden->pal[i].a = 255; + } + SendSyncCommand(this,OGL_PALETTE); + return 1; +} + +static int OHQ_FlipHWSurface(_THIS, SDL_Surface *surface) +{ +TRACE; + if (!this->hidden->dirty) { + if (surface->flags&SDL_DOUBLEBUF) SDL_UpdateRect(surface, 0, 0, 0, 0); + return 0; + } + this->hidden->dirty = 0; + if (!TryWaitCommand(this)) { + this->hidden->postponed = 1; + return 0; + } + + SAVE_VIDEO; + SendAsyncCommand(this,OGL_FRAME); + SDL_SemWait(this->hidden->render_thread_ack); + RESTORE_VIDEO; + return 0; +} + +static void OHQ_UpdateRects(_THIS, int numrects, SDL_Rect *rects) { +TRACE; + int i, minx = this->hidden->width, miny = this->hidden->height, maxx = 0, maxy = 0; + if (!numrects) return; + + if (this->hidden->postponed) { + minx = this->hidden->clip.x; + miny = this->hidden->clip.y; + maxx = minx+this->hidden->clip.w; + maxy = miny+this->hidden->clip.h; + } + + for (i = 0; i < numrects; i++) { + if (rects[i].x < minx) minx = rects[i].x; + if (rects[i].y < miny) miny = rects[i].y; + if (rects[i].x+rects[i].w > maxx) maxx = rects[i].x+rects[i].w; + if (rects[i].y+rects[i].h > maxy) maxy = rects[i].y+rects[i].h; + } + + this->hidden->clip.x = minx; + this->hidden->clip.y = miny; + this->hidden->clip.w = maxx-minx; + this->hidden->clip.h = maxy-miny; + this->hidden->dirty = 1; + + if (!(this->screen->flags&SDL_DOUBLEBUF)) OHQ_FlipHWSurface(this, this->screen); + return; +} + +static void OHQ_VideoQuit(_THIS) { + SAVE_VIDEO; + ShutdownRenderThread(this); + if (OHQ_NextMouseFilter != (void *)-1) { + SDL_MouseFilter = OHQ_NextMouseFilter; + OHQ_NextMouseFilter = (void *)-1; + } + RESTORE_VIDEO; +} + +static int OHQ_AllocHWSurface(_THIS, SDL_Surface *surface) +{ + return -1; +} + +static void OHQ_FreeHWSurface(_THIS, SDL_Surface *surface) +{ + return; +} + +static int OHQ_LockHWSurface(_THIS, SDL_Surface *surface) +{ +TRACE; + return 0; +} + +static void OHQ_UnlockHWSurface(_THIS, SDL_Surface *surface) +{ +TRACE; + if (surface->flags&SDL_DOUBLEBUF) SDL_UpdateRect(surface, 0, 0, 0, 0); + return; +} + + +static void OHQ_SetCaption(_THIS, const char *title, const char *icon) { + SAVE_VIDEO; + OHQ_Call_pp(this, (void (*)(SDL_VideoDevice*,const void*,const void*))this->hidden->real_video->SetCaption, title, icon); + RESTORE_VIDEO; +} + +static void OHQ_SetIcon(_THIS, SDL_Surface *icon, Uint8 *mask) { + SAVE_VIDEO; + OHQ_Call_pp(this, (void (*)(SDL_VideoDevice*,const void*,const void*))this->hidden->real_video->SetIcon, icon, mask); + RESTORE_VIDEO; +} + +static int OHQ_IconifyWindow(_THIS) { + int result; + SAVE_VIDEO; + result = OHQ_Call__i(this, this->hidden->real_video->IconifyWindow); + RESTORE_VIDEO; + return result; +} + +static SDL_GrabMode OHQ_GrabInput(_THIS, SDL_GrabMode mode) { + int result; + SAVE_VIDEO; + result = OHQ_Call_i_i(this, this->hidden->real_video->GrabInput,mode); + current_video->input_grab = result; + RESTORE_VIDEO; + return result; +} + +static int OHQ_GetWMInfo(_THIS, SDL_SysWMinfo *info) { + int result; + SAVE_VIDEO; + result = OHQ_Call_p_i(this, (int (*)(SDL_VideoDevice*,const void*))this->hidden->real_video->GetWMInfo, info); + RESTORE_VIDEO; + return result; +} + +static void OHQ_FreeWMCursor(_THIS, WMcursor *cursor) { + SAVE_VIDEO; + OHQ_Call_p(this, (void (*)(SDL_VideoDevice*,const void*))this->hidden->real_video->FreeWMCursor, cursor); + RESTORE_VIDEO; +} + +static WMcursor *OHQ_CreateWMCursor(_THIS, Uint8 *data, Uint8 *mask, int w, int h, int hot_x, int hot_y) { + void *result; + SAVE_VIDEO; + result = OHQ_Call_ppiiii_p(this, (void* (*)(SDL_VideoDevice*,const void*,const void*,int,int,int,int))this->hidden->real_video->CreateWMCursor, data, mask, w, h, hot_x, hot_y); + RESTORE_VIDEO; + return result; +} + +static int OHQ_ShowWMCursor(_THIS, WMcursor *cursor) { + int result; + SAVE_VIDEO; + result = OHQ_Call_p_i(this, (int (*)(SDL_VideoDevice*,const void*))this->hidden->real_video->ShowWMCursor, cursor); + RESTORE_VIDEO; + return result; +} + +static void OHQ_WarpWMCursor(_THIS, Uint16 x, Uint16 y) { + SAVE_VIDEO; + OHQ_Call_ii(this, (void (*)(SDL_VideoDevice*,int,int))this->hidden->real_video->WarpWMCursor, x*this->hidden->outwidth/this->hidden->width, y*this->hidden->outheight/this->hidden->height); + RESTORE_VIDEO; +} + +static void OHQ_MoveWMCursor(_THIS, int x, int y) { + if (!this->hidden->real_video->MoveWMCursor) return; + SAVE_VIDEO; + OHQ_Call_ii(this, this->hidden->real_video->MoveWMCursor, x*this->hidden->outwidth/this->hidden->width, y*this->hidden->outheight/this->hidden->height); + RESTORE_VIDEO; +} + +static void OHQ_CheckMouseMode(_THIS) { + SAVE_VIDEO; + OHQ_Call(this, this->hidden->real_video->CheckMouseMode); + RESTORE_VIDEO; +} + +static void OHQ_InitOSKeymap(_THIS) { + SAVE_VIDEO; + OHQ_Call(this, this->hidden->real_video->InitOSKeymap); + RESTORE_VIDEO; +} + +static void OHQ_MouseFilter(int relative, Sint16 *x, Sint16 *y) +{ + if (!relative) { + *x = (*x*filter_video->hidden->width)/filter_video->hidden->outwidth; + *y = (*y*filter_video->hidden->height)/filter_video->hidden->outheight; + } + if (OHQ_NextMouseFilter != NULL) OHQ_NextMouseFilter(relative,x,y); +} + +static void OHQ_PumpEvents(_THIS) { + SAVE_VIDEO; + +#ifdef WIN32 + OHQ_Call(this, this->hidden->real_video->PumpEvents); +#else + this->hidden->real_video->PumpEvents(this->hidden->real_video); + if (this->hidden->postponed && !(this->hidden->postponed++ & 255) && TryWaitCommand(this)) SendSyncCommand(this,OGL_NONE); +#endif + + RESTORE_VIDEO; +} + +static SDL_VideoDevice *OHQ_CreateDevice(int devindex) +{ + SDL_VideoDevice *this; + + /* Initialize all variables that we clean on shutdown */ + this = (SDL_VideoDevice *)malloc(sizeof(SDL_VideoDevice)); + if (this) { + memset(this, 0, (sizeof *this)); + this->hidden = (struct SDL_PrivateVideoData *)malloc((sizeof *this->hidden)); + } + if ( (this == NULL) || (this->hidden == NULL) ) { + SDL_OutOfMemory(); + if (this) free(this); + return(0); + } + memset(this->hidden, 0, (sizeof *this->hidden)); + + /* Set the function pointers */ + this->VideoInit = OHQ_VideoInit; + this->ListModes = OHQ_ListModes; + this->SetVideoMode = OHQ_SetVideoMode; + this->ToggleFullScreen = NULL; + this->UpdateMouse = OHQ_UpdateMouse; + this->CreateYUVOverlay = NULL; + this->SetColors = OHQ_SetColors; + this->UpdateRects = OHQ_UpdateRects; + this->VideoQuit = OHQ_VideoQuit; + this->AllocHWSurface = OHQ_AllocHWSurface; + this->CheckHWBlit = NULL; + this->FillHWRect = NULL; + this->SetHWColorKey = NULL; + this->SetHWAlpha = NULL; + this->LockHWSurface = OHQ_LockHWSurface; + this->UnlockHWSurface = OHQ_UnlockHWSurface; + this->FlipHWSurface = OHQ_FlipHWSurface; + this->FreeHWSurface = OHQ_FreeHWSurface; + this->SetGamma = NULL; + this->GetGamma = NULL; + this->SetGammaRamp = NULL; + this->GetGammaRamp = NULL; + this->GL_LoadLibrary = NULL; + this->GL_GetProcAddress = NULL; + this->GL_GetAttribute = NULL; + this->GL_MakeCurrent = NULL; + this->GL_SwapBuffers = NULL; + this->SetCaption = OHQ_SetCaption; + this->SetIcon = OHQ_SetIcon; + this->IconifyWindow = OHQ_IconifyWindow; + this->GrabInput = OHQ_GrabInput; + this->GetWMInfo = OHQ_GetWMInfo; + this->FreeWMCursor = OHQ_FreeWMCursor; + this->CreateWMCursor = OHQ_CreateWMCursor; + this->ShowWMCursor = OHQ_ShowWMCursor; + this->WarpWMCursor = OHQ_WarpWMCursor; + this->MoveWMCursor = OHQ_MoveWMCursor; + this->CheckMouseMode = OHQ_CheckMouseMode; + this->InitOSKeymap = OHQ_InitOSKeymap; + this->PumpEvents = OHQ_PumpEvents; + this->free = OHQ_DeleteDevice; + + this->info.wm_available = 1; + + return this; +} + +VideoBootStrap OPENGLHQ_bootstrap = { + "openglhq", "OpenGL-HQ scaling", + OHQ_Available, OHQ_CreateDevice +}; --- src/video/openglhq/SDL_ohqvideo.h +++ src/video/openglhq/SDL_ohqvideo.h @@ -0,0 +1,134 @@ +/* + SDL - Simple DirectMedia Layer OpenGL-HQ scaling + Copyright (C) 2005 Jörg Walter + SDL - Simple DirectMedia Layer + Copyright (C) 1997-2004 Sam Lantinga + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library 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 + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with this library; if not, write to the Free + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + + Sam Lantinga + slouken@libsdl.org +*/ + +#ifdef SAVE_RCSID +static char rcsid = + "@(#) $Id$"; +#endif + +#ifndef _SDL_ohqvideo_h +#define _SDL_ohqvideo_h + +#include +#include + +#include "SDL_mutex.h" +#include "../SDL_sysvideo.h" +#include "SDL_thread.h" + +/* Hidden "this" pointer for the video functions */ +#define _THIS SDL_VideoDevice *this + +enum OGL_CMD { + OGL_NONE, + OGL_CALL, + OGL_INIT, + OGL_DEINIT, + OGL_FRAME, + OGL_PALETTE, + OGL_QUIT +}; + +enum OGL_STATUS { + OGL_DONE, + OGL_ERROR +}; + +/* Private display data */ +struct SDL_PrivateVideoData { + SDL_VideoDevice *real_video; + volatile SDL_Surface *volatile surface; + int screen_width, screen_height; + + volatile int width; + volatile int height; + volatile int pitch; + volatile int outwidth; + volatile int outheight; + volatile int flags; + volatile int bpp; + volatile SDL_PixelFormat format; + volatile SDL_Rect clip; + + int busy; + + struct { + enum { + OGL_CALL_P, + OGL_CALL_P_I, + OGL_CALL_PP, + OGL_CALL_PP_I, + OGL_CALL_PI_I, + OGL_CALL_PII, + OGL_CALL_PPP, + OGL_CALL_PPPIIII_P + } type; + intptr_t args[6]; + union { + void (*p)(SDL_VideoDevice*); + void (*pii)(SDL_VideoDevice*, int, int); + void (*pp)(SDL_VideoDevice*, const void*); + int (*pp_i)(SDL_VideoDevice*, const void*); + int (*p_i)(SDL_VideoDevice *); + int (*pi_i)(SDL_VideoDevice *, int); + void (*ppp)(SDL_VideoDevice *, const void*, const void*); + void* (*pppiiii_p)(SDL_VideoDevice *, const void*, const void*, int, int, int, int); + } func; + intptr_t result; + } call; + + volatile GLenum framebuf_format; + volatile GLenum framebuf_datatype; + + GLuint texture[4]; + GLuint displaylist; + GLint texsize, max_texsize; + int has_pixel_data_range; + int allow_paletted_texture; + + struct { + GLubyte r, g, b, a; + } pal[256]; + + GLuint program_name[3]; + GLuint fbo[2]; + GLuint pbuffer_displaylist; + + SDL_sem *render_thread_signal; + SDL_sem *render_thread_ack; + SDL_mutex *render_frame_lock; + SDL_Thread *render_thread; + + void * volatile framebuf; + int static_threshold; + int dynamic_threshold; + volatile int postponed; + int nohq; + int dirty; + + volatile enum OGL_CMD cmd; + volatile enum OGL_STATUS status; +}; + +#endif /* _SDL_ohqvideo_h */ --- src/video/openglhq/SDL_openglhq_pass1.fp +++ src/video/openglhq/SDL_openglhq_pass1.fp @@ -0,0 +1,81 @@ +!!ARBfp1.0 + +# +# Copyright (C) 2004 Jörg Walter +# +# 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, version 2 of the License. +# +# 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +# + +TEMP pixel0, pixel1, pixel2, pixel3; +ALIAS coord1 = pixel1; +ALIAS coord2 = pixel2; +ALIAS coord3 = pixel3; +ALIAS rmean = pixel3; +TEMP diff; + +PARAM pixel_size = program.env[0]; +ATTRIB coord0 = fragment.texcoord[0]; +OUTPUT res = result.color; + +PARAM coordmask = { 1, 0, 1, 0 }; +PARAM weight = { 1.884313725490196078431372549, 3.768627450980392156862745098, 2.822790287990196078431372548, 0 }; +PARAM mask = { 0.4710784313725490196078431372, 0, -0.4710784313725490196078431372, 0 }; + +MAD coord1.xy, pixel_size, coordmask, coord0; +MAD coord2.xy, pixel_size, coordmask.gbra, coord0; +ADD coord3.xy, pixel_size, coord0; + +TEX pixel0.rgb, coord0, texture[0], 2D; +TEX pixel1.rgb, coord1, texture[0], 2D; +TEX pixel2.rgb, coord2, texture[0], 2D; +TEX pixel3.rgb, coord3, texture[0], 2D; + +# +# Original formula, [0;255] per component, result range [0;764.83]: +# sqrt( (2+rmean/256)*r*r + 4*g*g + (2.99609375-rmean/256)*b*b ) +# (see http://www.compuphase.com/cmetric.htm) +# +# Formula used in software hq2x scaler, range [0;31] per component, result range [0;2161.31] clamped to [0;255]: +# (0.5+(2*rmean/2048))*r*r + g*g + (0.7490234375-(2*rmean/2048))*b*b +# +# This code uses this formula, range [0;1] per component, result range [0;2161.31/255] clamped to [0;1]: +# (1.884313725490196078431372549+(2*rmean*0.4710784313725490196078431372))*r*r + 3.768627450980392156862745098*g*g + (2.822790287990196078431372548-(2*rmean*0.4710784313725490196078431372))*b*b +# (which means that the same trigger values can be used for both) +# + +SUB diff.rgb, pixel0, pixel3; +ADD rmean.a, pixel0.r, pixel3.r; +MAD rmean.rgb, rmean.a, mask, weight; +MUL diff.rgb, diff, diff; +DP3_SAT res.b, rmean, diff; + +SUB diff.rgb, pixel0, pixel1; +ADD rmean.a, pixel0.r, pixel1.r; +MAD rmean.rgb, rmean.a, mask, weight; +MUL diff.rgb, diff, diff; +DP3_SAT res.r, rmean, diff; + +SUB diff.rgb, pixel0, pixel2; +ADD rmean.a, pixel0.r, pixel2.r; +MAD rmean.rgb, rmean.a, mask, weight; +MUL diff.rgb, diff, diff; +DP3_SAT res.g, rmean, diff; + +SUB diff.rgb, pixel1, pixel2; +ADD rmean.a, pixel1.r, pixel2.r; +MAD rmean.rgb, rmean.a, mask, weight; +MUL diff.rgb, diff, diff; +DP3_SAT res.a, rmean, diff; + +END --- src/video/openglhq/SDL_openglhq_pass2.fp +++ src/video/openglhq/SDL_openglhq_pass2.fp @@ -0,0 +1,69 @@ +!!ARBfp1.0 + +# +# Copyright (C) 2004 Jörg Walter +# +# 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, version 2 of the License. +# +# 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +# + +TEMP pixel0, pixel1, pixel2, pixel3; +TEMP max; +ALIAS coord0 = pixel0; +ALIAS coord1 = pixel1; +ALIAS coord2 = pixel2; +TEMP min; +TEMP current_trigger; + +PARAM pixel_size = program.env[0]; +PARAM trigger = program.local[0]; +ATTRIB coord3 = fragment.texcoord[0]; + +PARAM coordmask = { 0, -1, 0, .0625 }; +PARAM factors = { 0.0627450980392157, 0.125490196078431, 0.250980392156863, 0.501960784313725 }; +PARAM const = { 65536, 0.1666666666666666, 1, 0 }; +ALIAS one_sixteenth = coordmask; + +SUB coord0.xy, coord3, pixel_size; +MAD coord1.xy, pixel_size.y, coordmask, coord3; +MAD coord2.xy, pixel_size.x, coordmask.gbra, coord3; + +TEX pixel0, coord0, texture[0], 2D; +TEX pixel1, coord1, texture[0], 2D; +TEX pixel2, coord2, texture[0], 2D; +TEX pixel3, coord3, texture[0], 2D; + +MOV pixel1.r, pixel0.b; +MOV pixel2.g, pixel0.a; + +ADD min, pixel1, pixel2; +ADD min, min, pixel3; +DP3 current_trigger.a, min, const.g; +MUL_SAT current_trigger.a, current_trigger.a, trigger.a; +MAX current_trigger.a, current_trigger.a, trigger.r; + +MUL current_trigger.a, current_trigger.a, const.r; +MAD_SAT pixel1, pixel1, const.r, -current_trigger.a; +MAD_SAT pixel2, pixel2, const.r, -current_trigger.a; +MAD_SAT pixel3, pixel3, const.r, -current_trigger.a; + +# on a Radeon 9500, these three expand to 6 native insns +#SLT pixel1, current_trigger.a, pixel1; +#SLT pixel2, current_trigger.a, pixel2; +#SLT pixel3, current_trigger.a, pixel3; + +DP4 result.color.a, pixel3, factors; +MAD pixel2, pixel2, one_sixteenth.a, pixel1; +DP4 result.color.rgb, pixel2, factors; + +END --- src/video/openglhq/SDL_openglhq_pass3.fp +++ src/video/openglhq/SDL_openglhq_pass3.fp @@ -0,0 +1,115 @@ +!!ARBfp1.0 + +# +# Copyright (C) 2004 Jörg Walter +# +# 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, version 2 of the License. +# +# 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +# + +TEMP coord1, coord2, coord3, pixel0; +ALIAS pixel1 = coord1; +ALIAS pixel2 = coord2; +ALIAS pixel3 = coord3; +TEMP diff; +TEMP center_offset; +TEMP factors; +TEMP coord0; + +PARAM pixel_size = program.env[0]; + +# 1/16, 1/2, 1-1/256, 1/512 +PARAM const = { .0625, .5, .99609375, .001953125 }; + +ATTRIB coord0hw = fragment.texcoord[0]; + +# 1/.875, (1/.875-1)/2, .875/adjust, (1-.875/adjust)/2 +#PARAM cap = { 1.142857142857142857127368540393064222371, -0.07142857142857143002735720305196309709572, .83825, .080875 }; +#PARAM cap = { 1.142857142857142857127368540393064222371, -0.07142857142857143002735720305196309709572, .875, .0625 }; +PARAM cap = program.env[1]; + +# normalize coordinates to eliminate FP precision errors +MUL center_offset.xy, coord0hw, pixel_size.abgr; +FLR coord0.xy, center_offset; +ADD coord0.xy, coord0, const.g; +MUL coord0.xy, coord0, pixel_size; + +# sub-pixel offset +FRC center_offset.xy, center_offset; + +# fetch interpolation mask coordinates +TEX diff, coord0, texture[1], 2D; + +# calculate neighbour pixel coordinates +SUB coord3.xy, center_offset, const.g; +CMP coord3.xy, coord3, -pixel_size, pixel_size; +ADD coord3.xy, coord0, coord3; +MOV coord1.x, coord3; +MOV coord1.y, coord0; +MOV coord2.x, coord0; +MOV coord2.y, coord3; + +# The interpolation mask 3D texture is arranged +# as 16x1x256 masks like this: +# +# +--+--+--+-- --+--+ +-> x +# | | | | ... 16 masks ... | |+ |\ +# +--+--+--+-- --+--+|+ V \| +# +--+--+--+-- --+--+| y z +# +--+--+--+-- --+--+ +# . +# . 256 masks +# . +# +# This is more robust across GPUs than an 1x1x4096 arrangement. + +# Clamp x offset to a reduced interval. This is required since +# otherwise precision errors will make the final coordinate wrap +# into the opposite end of the next mask. +MAD_SAT center_offset.x, center_offset, cap.r, cap.g; +MAD center_offset.x, center_offset, cap.b, cap.a; + +# This could be used if wrapping occurs on the z coordinate, which +# should not happen. +#MAD center_offset.z, diff, const.b, const.a; + +# final coordinate calculation: +# x = x_offset/16 + mask_x; y = y_offset; z = mask_z; +MAD center_offset.x, center_offset, const, diff.a; +MOV center_offset.z, diff; + +# fetch color values +TEX pixel0, coord0, texture[0], 2D; +TEX pixel1, coord1, texture[0], 2D; +TEX pixel2, coord2, texture[0], 2D; +TEX pixel3, coord3, texture[0], 2D; + +# fetch pixel weights from mask +TEX factors, center_offset, texture[2], 3D; + +# apply mask factors +MUL pixel0, pixel0, factors.r; +MAD pixel0, pixel1, factors.g, pixel0; +MAD pixel0, pixel2, factors.b, pixel0; +MAD result.color, pixel3, factors.a, pixel0; + +# debugging +#MOV result.color, pixel0; +#MOV result.color, diff; +#MOV result.color, factors; +#MOV result.color.g, test.y; +#MOV result.color.r, test.z; +#SUB test.z, test, const.b; +#CMP result.color.r, test.z, const.r, const.b; + +END --- src/video/openglhq/SDL_openglhq_table.dat +++ src/video/openglhq/SDL_openglhq_table.dat @@ -0,0 +1 @@ +LL$$LLl$$LLLLLlllnLll$$LlllnLll$$llLLL씑쐑씑쐑LLLLLllLnLllnlLllLnLllllLLlLLL萑L蒗Lh萑L蒗L萑LLL萑LL蒗ll萑lllLllll萑llnLl$ll萑llLl萑蒗LHHHHHHHLHHHHHH 쓔 에LHHHHHHHLHHHHH L L LLlHHllHHlLHHlHHl l l n l nLlHHHHHlHhHHlL  l   LL$$LLL$$LLLLLLLlllnLll$$LllhnLll$$llLLL쓔L씑쐑LLLLLLLllLnLllnlLllnLlhnllLLlLLLLLLLLLLLLlllllLlllllnLl$lllLlLHHHHHHHLHHHHHL씑L쓔LLHHHLHHHLHHHHHHLLLLLLlHHllHHlLHHlHHLlllnLlnlHHHHHlHHHHHllLhlh$$Lhlh$$LhlhLhlhhlllnlhll$$hlllnlhll$$hllhhllhLhLhLh씑h씑쐑LhLhLhLhhlllnlhllnlhlllnlhllnlhlhhlhhhiLhhhhlLhl$hhiLhhhhiLh$hhiLhhhhlLhhliLhhhhiLh蒗hhilhlhhlinlhl$hhilhlhhllinlhl$hhilhlhhhihh蒗hhihlhhihh蒗hLiLhhihHhHhHlHLHhHHlHhLiLhhhhih쓔iLhLiLhhihHhHhHlHLHhHHHhiLhlihhhiLhihhihhlhihHhllHinHhlHinhhihhlhihhllinlhlinhhihhlhihHhHhHiHhHhHHHh ihl ihhhihhi̔̐hlh$$̔̐hLh$$̔̐h̐h̔̐hL̐hhlllnlhll$$hlllnhll$$hlhhlh̔̐h̔̐h̔̐h쓔̐h씑쐑̔̐h̔̐h̔̐h̔̐hhlllnlhllnlhll씑nhl씑nlhlhhl씑̐h̔̐l̐l̔̐̐$̔̐l̐l̔̐̐llllnll$lllnll$llLLHHHHlHHHlHlLLL̔̐쓔에LLHHHHlHHHHHlH̔L̔̐lHHllHHnlHHlHHlllnllnlHHHHHHHHHHHH l \ No newline at end of file --- src/video/openglhq/tablebuilder.ui +++ src/video/openglhq/tablebuilder.ui @@ -0,0 +1,1038 @@ + + + Jörg Walter <jwalt@garni.ch> + Builds scaling tables for the DosBox OpenGL-HQ renderer + + TableBuilder + + + + 0 + 0 + 762 + 516 + + + + DosBox OpenGL-HQ Table Builder + + + + + + + Qt::Horizontal + + + QSizePolicy::Expanding + + + + 44 + 20 + + + + + + + + Qt::Horizontal + + + QSizePolicy::Expanding + + + + 43 + 20 + + + + + + + + Qt::Horizontal + + + QSizePolicy::Expanding + + + + 44 + 20 + + + + + + + + Qt::Vertical + + + QSizePolicy::Expanding + + + + 20 + 40 + + + + + + + + + 1 + 1 + + + + Resulting Borders + + + + + + + + + 0 + 0 + + + + diagonal: + + + + + + + + + + 0 + 0 + + + + Y<sub>0</sub> + + + false + + + + + + + false + + + + 0 + 0 + + + + /4 + + + -4 + + + 4 + + + 1 + + + 0 + + + + + + + + + + + + 0 + 0 + + + + grad. + + + false + + + + + + + false + + + + 0 + 0 + + + + /2 + + + -4 + + + 4 + + + + + + + + + + + + + + 0 + 0 + + + + &Reset + + + Alt+R + + + + + + + + 0 + 0 + + + + &Save + + + Alt+S + + + true + + + true + + + + + + + + + + + Mirror: + + + false + + + + + + + H/V + + + + + + + H+V + + + + + + + + + + 0 + 0 + + + + + + + true + + + true + + + + + + + + 0 + 0 + + + + + + + true + + + true + + + + + + + + 200 + 200 + + + + + 200 + 200 + + + + + + + + + 0 + 0 + + + + + 40 + 40 + + + + + 40 + 40 + + + + + + + true + + + true + + + + + + + + + + Qt::Vertical + + + QSizePolicy::Expanding + + + + 20 + 16 + + + + + + + + + 1 + 1 + + + + Source Pixels + + + + + + Reset all + + + + + + + + 1 + 1 + + + + C + + + + + + + + 1 + 1 + + + + DH + + + + + + + + 1 + 1 + + + + D + + + + + + + + 1 + 1 + + + + H + + + + + + + + 1 + 1 + + + + HB + + + + + + + + 1 + 1 + + + + DB + + + + + + + + 1 + 1 + + + + VB + + + + + + + + 1 + 1 + + + + DV + + + + + + + + 1 + 1 + + + + V + + + + + + + + + + + + 0 + 0 + 762 + 21 + + + + + &File + + + + + + + + + + + + + + image1image1 + + + &New + + + New + + + Ctrl+N + + + fileNewAction + + + + + + image2image2 + + + &Open... + + + Open + + + Ctrl+O + + + fileOpenAction + + + + + + image3image3 + + + &Save + + + Save + + + Ctrl+S + + + fileSaveAction + + + + + Save &As... + + + Save As + + + + + + fileSaveAsAction + + + + + E&xit + + + Exit + + + + + + fileExitAction + + + + + + + QCanvasView + QWidget +
qcanvasview.h
+
+
+ + qcanvasview.h + + + + + fileNewAction + activated() + TableBuilder + file_new() + + + -1 + -1 + + + 20 + 20 + + + + + fileExitAction + activated() + TableBuilder + close() + + + -1 + -1 + + + 20 + 20 + + + + + sourceReset + clicked() + TableBuilder + sourceReset_clicked() + + + 20 + 20 + + + 20 + 20 + + + + + resultReset + clicked() + TableBuilder + resultReset_clicked() + + + 20 + 20 + + + 20 + 20 + + + + + dEnabled + toggled(bool) + dGrad + setEnabled(bool) + + + 20 + 20 + + + 20 + 20 + + + + + dEnabled + toggled(bool) + dY0 + setEnabled(bool) + + + 20 + 20 + + + 20 + 20 + + + + + resultSave + clicked() + TableBuilder + resultSave_clicked() + + + 20 + 20 + + + 20 + 20 + + + + + dhColor + clicked() + TableBuilder + dhColor_clicked() + + + 20 + 20 + + + 20 + 20 + + + + + vColor + clicked() + TableBuilder + vColor_clicked() + + + 20 + 20 + + + 20 + 20 + + + + + dColor + clicked() + TableBuilder + dColor_clicked() + + + 20 + 20 + + + 20 + 20 + + + + + hbColor + clicked() + TableBuilder + hbColor_clicked() + + + 20 + 20 + + + 20 + 20 + + + + + cColor + clicked() + TableBuilder + cColor_clicked() + + + 20 + 20 + + + 20 + 20 + + + + + hColor + clicked() + TableBuilder + hColor_clicked() + + + 20 + 20 + + + 20 + 20 + + + + + dbColor + clicked() + TableBuilder + dbColor_clicked() + + + 20 + 20 + + + 20 + 20 + + + + + vbColor + clicked() + TableBuilder + vbColor_clicked() + + + 20 + 20 + + + 20 + 20 + + + + + dvColor + clicked() + TableBuilder + dvColor_clicked() + + + 20 + 20 + + + 20 + 20 + + + + + vBorder + toggled(bool) + TableBuilder + result_changed() + + + 20 + 20 + + + 20 + 20 + + + + + dBorder + toggled(bool) + TableBuilder + result_changed() + + + 20 + 20 + + + 20 + 20 + + + + + hBorder + toggled(bool) + TableBuilder + result_changed() + + + 20 + 20 + + + 20 + 20 + + + + + dEnabled + toggled(bool) + TableBuilder + result_changed() + + + 20 + 20 + + + 20 + 20 + + + + + dY0 + valueChanged(int) + TableBuilder + result_changed() + + + 20 + 20 + + + 20 + 20 + + + + + dGrad + valueChanged(int) + TableBuilder + result_changed() + + + 20 + 20 + + + 20 + 20 + + + + + fileOpenAction + activated() + TableBuilder + fileOpenAction_activated() + + + -1 + -1 + + + 20 + 20 + + + + + fileSaveAction + activated() + TableBuilder + fileSaveAction_activated() + + + -1 + -1 + + + 20 + 20 + + + + + fileSaveAsAction + activated() + TableBuilder + fileSaveAsAction_activated() + + + -1 + -1 + + + 20 + 20 + + + + +
--- src/video/openglhq/test.c +++ src/video/openglhq/test.c @@ -0,0 +1,77 @@ +#include +#include "SDL.h" + +#define min(a,b) ((a)<(b)?(a):(b)) +#define max(a,b) ((a)>(b)?(a):(b)) + +int main(int argc, char *argv[]) +{ + int w = 0, h = 0; + int c1 = 0x00ffffff, c2 = 0x00000000, c3 = 0x00ff0000; + int once = 0; + + if (argc > 1 && !strcmp(argv[0], "--once")) { + once = 1; + argv++; + argc--; + } + if (argc > 1) w = atoi(argv[1]); + if (argc > 2) h = atoi(argv[2]); + if (argc > 3) c1 = atoi(argv[3]); + if (argc > 4) c2 = atoi(argv[4]); + if (w <= 0) w = 160; + if (h <= 0) h = 120; + + if (SDL_Init(SDL_INIT_VIDEO|SDL_INIT_NOPARACHUTE) < 0) { + fprintf(stderr, "SDL error: %s\n", SDL_GetError()); + exit(1); + } + atexit(SDL_Quit); + + SDL_Surface *display; +#define SET(x,y,c) do { uint32_t *line = display->pixels+(y)*display->pitch; line[(x)] = (c); } while (0) + + display = SDL_SetVideoMode(w, h, 0,0);//32, SDL_SWSURFACE); + if (display == NULL) { + fprintf(stderr, "SDL error: %s\n", SDL_GetError()); + exit(1); + } + + SDL_Event event; + int end = 0; + int mx = 0, my = 0, i; + + while (!end) { + SDL_FillRect(display, NULL, c2); + + SDL_Rect r = { 3, 0, w-3, 1 }; + for (; r.y < h; r.y += 2, r.x += 2, r.w -= 2) SDL_FillRect(display, &r, c1); + r.x = 0; + r.y = 3; + r.w = 1; + r.h = h-3; + for (; r.x < w; r.x += 2, r.y += 2, r.h -= 2) SDL_FillRect(display, &r, c1); + + for (i = 0; i < w && i < h; i++) SET(i, i, c1); + + SET(mx, my, c3); + SDL_UpdateRect(display, max(0,mx-10), max(0,my-10), min(w-mx+10,20), min(h-my+10,20)); + + end = !SDL_WaitEvent(&event) || once; + switch (event.type) { + case SDL_QUIT: + end = 1; + break; + case SDL_MOUSEMOTION: + SET(mx, my, (mx&1 && my&1?c2:c1)); + SDL_UpdateRect(display, max(0,mx-10), max(0,my-10), min(w-mx+10,20), min(h-my+10,20)); + mx = event.motion.x; + my = event.motion.y; + break; + default: + break; + } + } + + return 0; +} --- src/video/quartz/SDL_QuartzVideo.m +++ src/video/quartz/SDL_QuartzVideo.m @@ -24,6 +24,18 @@ #include "SDL_QuartzVideo.h" #include "SDL_QuartzWindow.h" +/* functions called in RunThread */ +void* QZ_allocPool() { + NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; + return (void *)pool; +} + +void QZ_freePool(void *p) { + NSAutoreleasePool *pool = (NSAutoreleasePool *)p; + [pool release]; +} + + /* These APIs aren't just deprecated; they're gone from the headers in the 10.7 SDK. If we're using a >= 10.7 SDK, but targeting < 10.7, then we force these function declarations. */ --- src/video/SDL_glfuncs.h +++ src/video/SDL_glfuncs.h @@ -4,6 +4,7 @@ */ #define SDL_PROC_UNUSED(ret,func,params) SDL_PROC_UNUSED(void,glAccum,(GLenum,GLfloat)) +SDL_PROC(void,glActiveTexture,(GLenum)) SDL_PROC_UNUSED(void,glAlphaFunc,(GLenum,GLclampf)) SDL_PROC_UNUSED(GLboolean,glAreTexturesResident,(GLsizei,const GLuint*,GLboolean*)) SDL_PROC_UNUSED(void,glArrayElement,(GLint)) @@ -11,7 +12,7 @@ SDL_PROC(void,glBindTexture,(GLenum,GLuint)) SDL_PROC_UNUSED(void,glBitmap,(GLsizei,GLsizei,GLfloat,GLfloat,GLfloat,GLfloat,const GLubyte*)) SDL_PROC(void,glBlendFunc,(GLenum,GLenum)) -SDL_PROC_UNUSED(void,glCallList,(GLuint)) +SDL_PROC(void,glCallList,(GLuint)) SDL_PROC_UNUSED(void,glCallLists,(GLsizei,GLenum,const GLvoid*)) SDL_PROC_UNUSED(void,glClear,(GLbitfield)) SDL_PROC_UNUSED(void,glClearAccum,(GLfloat,GLfloat,GLfloat,GLfloat)) @@ -57,28 +58,28 @@ SDL_PROC_UNUSED(void,glColorPointer,(GLint size, GLenum type, GLsizei stride, const GLvoid *pointer)) SDL_PROC_UNUSED(void,glCopyPixels,(GLint x, GLint y, GLsizei width, GLsizei height, GLenum type)) SDL_PROC_UNUSED(void,glCopyTexImage1D,(GLenum target, GLint level, GLenum internalFormat, GLint x, GLint y, GLsizei width, GLint border)) -SDL_PROC_UNUSED(void,glCopyTexImage2D,(GLenum target, GLint level, GLenum internalFormat, GLint x, GLint y, GLsizei width, GLsizei height, GLint border)) +SDL_PROC(void,glCopyTexImage2D,(GLenum target, GLint level, GLenum internalFormat, GLint x, GLint y, GLsizei width, GLsizei height, GLint border)) SDL_PROC_UNUSED(void,glCopyTexSubImage1D,(GLenum target, GLint level, GLint xoffset, GLint x, GLint y, GLsizei width)) -SDL_PROC_UNUSED(void,glCopyTexSubImage2D,(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height)) +SDL_PROC(void,glCopyTexSubImage2D,(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height)) SDL_PROC_UNUSED(void,glCullFace,(GLenum mode)) -SDL_PROC_UNUSED(void,glDeleteLists,(GLuint list, GLsizei range)) -SDL_PROC_UNUSED(void,glDeleteTextures,(GLsizei n, const GLuint *textures)) +SDL_PROC(void,glDeleteLists,(GLuint list, GLsizei range)) +SDL_PROC(void,glDeleteTextures,(GLsizei n, const GLuint *textures)) SDL_PROC_UNUSED(void,glDepthFunc,(GLenum func)) SDL_PROC_UNUSED(void,glDepthMask,(GLboolean flag)) SDL_PROC_UNUSED(void,glDepthRange,(GLclampd zNear, GLclampd zFar)) SDL_PROC(void,glDisable,(GLenum cap)) SDL_PROC_UNUSED(void,glDisableClientState,(GLenum array)) SDL_PROC_UNUSED(void,glDrawArrays,(GLenum mode, GLint first, GLsizei count)) -SDL_PROC_UNUSED(void,glDrawBuffer,(GLenum mode)) +SDL_PROC(void,glDrawBuffer,(GLenum mode)) SDL_PROC_UNUSED(void,glDrawElements,(GLenum mode, GLsizei count, GLenum type, const GLvoid *indices)) -SDL_PROC_UNUSED(void,glDrawPixels,(GLsizei width, GLsizei height, GLenum format, GLenum type, const GLvoid *pixels)) +SDL_PROC(void,glDrawPixels,(GLsizei width, GLsizei height, GLenum format, GLenum type, const GLvoid *pixels)) SDL_PROC_UNUSED(void,glEdgeFlag,(GLboolean flag)) SDL_PROC_UNUSED(void,glEdgeFlagPointer,(GLsizei stride, const GLvoid *pointer)) SDL_PROC_UNUSED(void,glEdgeFlagv,(const GLboolean *flag)) SDL_PROC(void,glEnable,(GLenum cap)) -SDL_PROC_UNUSED(void,glEnableClientState,(GLenum array)) +SDL_PROC(void,glEnableClientState,(GLenum array)) SDL_PROC(void,glEnd,(void)) -SDL_PROC_UNUSED(void,glEndList,(void)) +SDL_PROC(void,glEndList,(void)) SDL_PROC_UNUSED(void,glEvalCoord1d,(GLdouble u)) SDL_PROC_UNUSED(void,glEvalCoord1dv,(const GLdouble *u)) SDL_PROC_UNUSED(void,glEvalCoord1f,(GLfloat u)) @@ -92,7 +93,7 @@ SDL_PROC_UNUSED(void,glEvalPoint1,(GLint i)) SDL_PROC_UNUSED(void,glEvalPoint2,(GLint i, GLint j)) SDL_PROC_UNUSED(void,glFeedbackBuffer,(GLsizei size, GLenum type, GLfloat *buffer)) -SDL_PROC_UNUSED(void,glFinish,(void)) +SDL_PROC(void,glFinish,(void)) SDL_PROC(void,glFlush,(void)) SDL_PROC_UNUSED(void,glFogf,(GLenum pname, GLfloat param)) SDL_PROC_UNUSED(void,glFogfv,(GLenum pname, const GLfloat *params)) @@ -100,14 +101,14 @@ SDL_PROC_UNUSED(void,glFogiv,(GLenum pname, const GLint *params)) SDL_PROC_UNUSED(void,glFrontFace,(GLenum mode)) SDL_PROC_UNUSED(void,glFrustum,(GLdouble left, GLdouble right, GLdouble bottom, GLdouble top, GLdouble zNear, GLdouble zFar)) -SDL_PROC_UNUSED(GLuint,glGenLists,(GLsizei range)) +SDL_PROC(GLuint,glGenLists,(GLsizei range)) SDL_PROC(void,glGenTextures,(GLsizei n, GLuint *textures)) SDL_PROC_UNUSED(void,glGetBooleanv,(GLenum pname, GLboolean *params)) SDL_PROC_UNUSED(void,glGetClipPlane,(GLenum plane, GLdouble *equation)) SDL_PROC_UNUSED(void,glGetDoublev,(GLenum pname, GLdouble *params)) SDL_PROC_UNUSED(GLenum,glGetError,(void)) SDL_PROC_UNUSED(void,glGetFloatv,(GLenum pname, GLfloat *params)) -SDL_PROC_UNUSED(void,glGetIntegerv,(GLenum pname, GLint *params)) +SDL_PROC(void,glGetIntegerv,(GLenum pname, GLint *params)) SDL_PROC_UNUSED(void,glGetLightfv,(GLenum light, GLenum pname, GLfloat *params)) SDL_PROC_UNUSED(void,glGetLightiv,(GLenum light, GLenum pname, GLint *params)) SDL_PROC_UNUSED(void,glGetMapdv,(GLenum target, GLenum query, GLdouble *v)) @@ -180,7 +181,7 @@ SDL_PROC(void,glMatrixMode,(GLenum mode)) SDL_PROC_UNUSED(void,glMultMatrixd,(const GLdouble *m)) SDL_PROC_UNUSED(void,glMultMatrixf,(const GLfloat *m)) -SDL_PROC_UNUSED(void,glNewList,(GLuint list, GLenum mode)) +SDL_PROC(void,glNewList,(GLuint list, GLenum mode)) SDL_PROC_UNUSED(void,glNormal3b,(GLbyte nx, GLbyte ny, GLbyte nz)) SDL_PROC_UNUSED(void,glNormal3bv,(const GLbyte *v)) SDL_PROC_UNUSED(void,glNormal3d,(GLdouble nx, GLdouble ny, GLdouble nz)) @@ -219,7 +220,7 @@ SDL_PROC_UNUSED(void,glRasterPos2dv,(const GLdouble *v)) SDL_PROC_UNUSED(void,glRasterPos2f,(GLfloat x, GLfloat y)) SDL_PROC_UNUSED(void,glRasterPos2fv,(const GLfloat *v)) -SDL_PROC_UNUSED(void,glRasterPos2i,(GLint x, GLint y)) +SDL_PROC(void,glRasterPos2i,(GLint x, GLint y)) SDL_PROC_UNUSED(void,glRasterPos2iv,(const GLint *v)) SDL_PROC_UNUSED(void,glRasterPos2s,(GLshort x, GLshort y)) SDL_PROC_UNUSED(void,glRasterPos2sv,(const GLshort *v)) @@ -239,8 +240,8 @@ SDL_PROC_UNUSED(void,glRasterPos4iv,(const GLint *v)) SDL_PROC_UNUSED(void,glRasterPos4s,(GLshort x, GLshort y, GLshort z, GLshort w)) SDL_PROC_UNUSED(void,glRasterPos4sv,(const GLshort *v)) -SDL_PROC_UNUSED(void,glReadBuffer,(GLenum mode)) -SDL_PROC_UNUSED(void,glReadPixels,(GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, GLvoid *pixels)) +SDL_PROC(void,glReadBuffer,(GLenum mode)) +SDL_PROC(void,glReadPixels,(GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, GLvoid *pixels)) SDL_PROC_UNUSED(void,glRectd,(GLdouble x1, GLdouble y1, GLdouble x2, GLdouble y2)) SDL_PROC_UNUSED(void,glRectdv,(const GLdouble *v1, const GLdouble *v2)) SDL_PROC_UNUSED(void,glRectf,(GLfloat x1, GLfloat y1, GLfloat x2, GLfloat y2)) @@ -252,11 +253,11 @@ SDL_PROC_UNUSED(GLint,glRenderMode,(GLenum mode)) SDL_PROC_UNUSED(void,glRotated,(GLdouble angle, GLdouble x, GLdouble y, GLdouble z)) SDL_PROC_UNUSED(void,glRotatef,(GLfloat angle, GLfloat x, GLfloat y, GLfloat z)) -SDL_PROC_UNUSED(void,glScaled,(GLdouble x, GLdouble y, GLdouble z)) +SDL_PROC(void,glScaled,(GLdouble x, GLdouble y, GLdouble z)) SDL_PROC_UNUSED(void,glScalef,(GLfloat x, GLfloat y, GLfloat z)) SDL_PROC_UNUSED(void,glScissor,(GLint x, GLint y, GLsizei width, GLsizei height)) SDL_PROC_UNUSED(void,glSelectBuffer,(GLsizei size, GLuint *buffer)) -SDL_PROC_UNUSED(void,glShadeModel,(GLenum mode)) +SDL_PROC(void,glShadeModel,(GLenum mode)) SDL_PROC_UNUSED(void,glStencilFunc,(GLenum func, GLint ref, GLuint mask)) SDL_PROC_UNUSED(void,glStencilMask,(GLuint mask)) SDL_PROC_UNUSED(void,glStencilOp,(GLenum fail, GLenum zfail, GLenum zpass)) @@ -295,7 +296,7 @@ SDL_PROC_UNUSED(void,glTexCoordPointer,(GLint size, GLenum type, GLsizei stride, const GLvoid *pointer)) SDL_PROC(void,glTexEnvf,(GLenum target, GLenum pname, GLfloat param)) SDL_PROC_UNUSED(void,glTexEnvfv,(GLenum target, GLenum pname, const GLfloat *params)) -SDL_PROC_UNUSED(void,glTexEnvi,(GLenum target, GLenum pname, GLint param)) +SDL_PROC(void,glTexEnvi,(GLenum target, GLenum pname, GLint param)) SDL_PROC_UNUSED(void,glTexEnviv,(GLenum target, GLenum pname, const GLint *params)) SDL_PROC_UNUSED(void,glTexGend,(GLenum coord, GLenum pname, GLdouble param)) SDL_PROC_UNUSED(void,glTexGendv,(GLenum coord, GLenum pname, const GLdouble *params)) @@ -305,17 +306,18 @@ SDL_PROC_UNUSED(void,glTexGeniv,(GLenum coord, GLenum pname, const GLint *params)) SDL_PROC_UNUSED(void,glTexImage1D,(GLenum target, GLint level, GLint internalformat, GLsizei width, GLint border, GLenum format, GLenum type, const GLvoid *pixels)) SDL_PROC(void,glTexImage2D,(GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLint border, GLenum format, GLenum type, const GLvoid *pixels)) +SDL_PROC(void,glTexImage3D,(GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLenum format, GLenum type, const GLvoid *pixels)) SDL_PROC_UNUSED(void,glTexParameterf,(GLenum target, GLenum pname, GLfloat param)) SDL_PROC_UNUSED(void,glTexParameterfv,(GLenum target, GLenum pname, const GLfloat *params)) SDL_PROC(void,glTexParameteri,(GLenum target, GLenum pname, GLint param)) SDL_PROC_UNUSED(void,glTexParameteriv,(GLenum target, GLenum pname, const GLint *params)) SDL_PROC_UNUSED(void,glTexSubImage1D,(GLenum target, GLint level, GLint xoffset, GLsizei width, GLenum format, GLenum type, const GLvoid *pixels)) SDL_PROC(void,glTexSubImage2D,(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, const GLvoid *pixels)) -SDL_PROC_UNUSED(void,glTranslated,(GLdouble x, GLdouble y, GLdouble z)) +SDL_PROC(void,glTranslated,(GLdouble x, GLdouble y, GLdouble z)) SDL_PROC_UNUSED(void,glTranslatef,(GLfloat x, GLfloat y, GLfloat z)) SDL_PROC_UNUSED(void,glVertex2d,(GLdouble x, GLdouble y)) SDL_PROC_UNUSED(void,glVertex2dv,(const GLdouble *v)) -SDL_PROC_UNUSED(void,glVertex2f,(GLfloat x, GLfloat y)) +SDL_PROC(void,glVertex2f,(GLfloat x, GLfloat y)) SDL_PROC_UNUSED(void,glVertex2fv,(const GLfloat *v)) SDL_PROC(void,glVertex2i,(GLint x, GLint y)) SDL_PROC_UNUSED(void,glVertex2iv,(const GLint *v)) --- src/video/SDL_sysvideo.h +++ src/video/SDL_sysvideo.h @@ -63,6 +63,9 @@ */ SDL_Rect **(*ListModes)(_THIS, SDL_PixelFormat *format, Uint32 flags); + /* Get the current resolution of the user's display. */ + int (*GetDesktopMode)(_THIS, int *width, int *height); + /* Set the requested video mode, returning a surface which will be set to the SDL_VideoSurface. The width and height will already be verified by ListModes(), and the video subsystem is free to @@ -413,6 +416,9 @@ #if SDL_VIDEO_DRIVER_DUMMY extern VideoBootStrap DUMMY_bootstrap; #endif +#if SDL_VIDEO_DRIVER_OPENGLHQ +extern VideoBootStrap OPENGLHQ_bootstrap; +#endif /* This is the current video device */ extern SDL_VideoDevice *current_video; --- src/video/SDL_video.c +++ src/video/SDL_video.c @@ -129,6 +129,9 @@ #if SDL_VIDEO_DRIVER_DUMMY &DUMMY_bootstrap, #endif +#if SDL_VIDEO_DRIVER_OPENGLHQ + &OPENGLHQ_bootstrap, +#endif NULL }; @@ -345,6 +348,24 @@ } /* + * If possible, retrieves the current resolution of the user's display. If this + * operation is supported and succeeds, the width and height are written to the + * values pointed to by the parameters and 1 is returned. If unsupported or + * unsuccessful, the pointed to values are not touched and 0 is returned. + */ +int SDL_GetDesktopMode(int *width, int *height) +{ + SDL_VideoDevice *video = current_video; + SDL_VideoDevice *this = current_video; + + if (video && video->GetDesktopMode) { + return video->GetDesktopMode(this, width, height); + } else { + return 0; + } +} + +/* * Check to see if a particular video mode is supported. * It returns 0 if the requested mode is not supported under any bit depth, * or returns the bits-per-pixel of the closest available mode with the --- src/video/wincommon/SDL_syswm.c +++ src/video/wincommon/SDL_syswm.c @@ -295,3 +295,15 @@ return(-1); } } + +int WIN_GetDesktopMode(_THIS, int *width, int *height) +{ + DEVMODE dm; + if (EnumDisplaySettings(NULL, ENUM_CURRENT_SETTINGS, &dm)) { + *width = dm.dmPelsWidth; + *height = dm.dmPelsHeight; + return 1; + } else { + return 0; + } +} --- src/video/wincommon/SDL_syswm_c.h +++ src/video/wincommon/SDL_syswm_c.h @@ -32,4 +32,4 @@ extern int WIN_IconifyWindow(_THIS); extern SDL_GrabMode WIN_GrabInput(_THIS, SDL_GrabMode mode); extern int WIN_GetWMInfo(_THIS, SDL_SysWMinfo *info); - +extern int WIN_GetDesktopMode(_THIS, int *width, int *height); --- src/video/windib/SDL_dibvideo.c +++ src/video/windib/SDL_dibvideo.c @@ -176,6 +176,7 @@ /* Set the function pointers */ device->VideoInit = DIB_VideoInit; device->ListModes = DIB_ListModes; + device->GetDesktopMode = WIN_GetDesktopMode; device->SetVideoMode = DIB_SetVideoMode; device->UpdateMouse = WIN_UpdateMouse; device->SetColors = DIB_SetColors; --- src/video/windx5/SDL_dx5video.c +++ src/video/windx5/SDL_dx5video.c @@ -599,6 +599,7 @@ /* Set the function pointers */ device->VideoInit = DX5_VideoInit; device->ListModes = DX5_ListModes; + device->GetDesktopMode = WIN_GetDesktopMode; device->SetVideoMode = DX5_SetVideoMode; device->UpdateMouse = WIN_UpdateMouse; device->CreateYUVOverlay = DX5_CreateYUVOverlay; --- src/video/x11/SDL_x11modes.c +++ src/video/x11/SDL_x11modes.c @@ -928,6 +928,13 @@ #endif /* SDL_VIDEO_DRIVER_X11_XRANDR */ } +int X11_GetDesktopMode(_THIS, int *width, int *height) +{ + *width = DisplayWidth(SDL_Display, SDL_Screen); + *height = DisplayHeight(SDL_Display, SDL_Screen); + return 1; +} + int X11_ResizeFullScreen(_THIS) { int x = 0, y = 0; --- src/video/x11/SDL_x11modes_c.h +++ src/video/x11/SDL_x11modes_c.h @@ -35,6 +35,7 @@ extern int X11_GetVideoModes(_THIS); extern SDL_Rect **X11_ListModes(_THIS, SDL_PixelFormat *format, Uint32 flags); extern void X11_FreeVideoModes(_THIS); +extern int X11_GetDesktopMode(_THIS, int *width, int *height); extern int X11_ResizeFullScreen(_THIS); extern void X11_WaitMapped(_THIS, Window win); extern void X11_WaitUnmapped(_THIS, Window win); --- src/video/x11/SDL_x11sym.h +++ src/video/x11/SDL_x11sym.h @@ -165,7 +165,7 @@ */ #ifdef LONG64 SDL_X11_MODULE(IO_32BIT) -SDL_X11_SYM(int,_XData32,(Display *dpy,register long *data,unsigned len),(dpy,data,len),return) +/*SDL_X11_SYM(int,_XData32,(Display *dpy,register long *data,unsigned len),(dpy,data,len),return)*/ SDL_X11_SYM(void,_XRead32,(Display *dpy,register long *data,long len),(dpy,data,len),) #endif --- src/video/x11/SDL_x11video.c +++ src/video/x11/SDL_x11video.c @@ -131,6 +131,7 @@ /* Set the function pointers */ device->VideoInit = X11_VideoInit; device->ListModes = X11_ListModes; + device->GetDesktopMode = X11_GetDesktopMode; device->SetVideoMode = X11_SetVideoMode; device->ToggleFullScreen = X11_ToggleFullScreen; device->UpdateMouse = X11_UpdateMouse;