--- 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 <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+
+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 <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+
+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
+<name of your application>.exe
+
+3) Save the file as <name of your application>.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 <name of evironment var>=<value>" 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 <info@syntax-k.de>
+
+	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 <jwalt@garni.ch>
+ *
+ *  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 <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <stdarg.h>
+#include <sys/types.h>
+#include <math.h>
+#include <fcntl.h>
+#include <assert.h>
+
+#include <pthread.h>
+#include <sys/time.h>
+#include <sys/resource.h>
+#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, &param);
+			}
+
+        } 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 <jwalt@garni.ch>
+
+        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 <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <fcntl.h>
+#include <unistd.h>
+
+#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 <jwalt@garni.ch>
+	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 <sys/types.h>
+#include <stdint.h>
+
+#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 <jwalt@garni.ch>
+#
+# 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 <jwalt@garni.ch>
+#
+# 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 <jwalt@garni.ch>
+#
+# 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 @@
+�‘’“”‘’L�‘’“”‘’—�‘’“”‘’L�‘’“”‘$$�‘’“”‘’L�‘’“”‘’—�‘’“”‘’L�‘l“”‘$$�‘’“”‘’L�‘’“”‘’—�‘’“”‘’L�‘’“”‘’—�‘’“”‘’L�‘’“”‘’—�‘’“”‘’L�‘’“”‘’—�‘’“”‘’L�‘l“”‘’—�‘ll”‘nL�‘ll”‘$$�‘’“”‘’L�‘l“”‘’—�‘ll”‘nL�‘ll”‘$$�‘’”‘’�‘l“”‘–—�‘’”‘’�‘’“”‘’—�‘’”‘’�‘l“”‘’—�‘’”‘’�‘’“”‘’—�‘’“”‘’L�‘’“”‘’—�‘’“”‘’L�‘’“”‘’—�‘’“”‘’L�‘’“”‘’—�‘ìì”‘ìì�‘ìì”‘ìì�‘’“”‘’L�‘’“”‘’—�‘’“”‘’L�‘’“”‘’—�‘’“”‘’L�‘’“”‘’—�‘’“”‘’L�‘’“”‘’—�‘’“”‘’L�‘l“”‘’—�‘lL”‘nL�‘ll”‘nl�‘’“”‘’L�‘l“”‘’—�‘lL”‘nL�‘ll”‘’l�‘’”‘’�‘l“”‘’—�‘’L”‘’L�‘’“”‘’—�‘’”‘’�‘l“”‘’—�‘’L”‘’L�‘’“”‘’—�‘’“”‘’L�‘’“”è’è�‘’“”‘’L�‘’“”è’—�‘’“”‘’L�h’“”è’è�‘’“”‘’L�‘’“”è’—�‘’“”‘’L�‘’“”è’è�‘’“”‘’L�‘’“”‘’—�‘’L”‘’L�‘’“”è’è�‘’L”‘’L�‘’“”è’—�‘’“”‘’l�‘l“”è’è�‘ll”‘lL�‘l“”èl—�‘’“”‘’l�‘l“”è’è�‘ll”‘nL�‘l“”è$—�‘’“”‘’l�‘l“”è’è�‘’“”‘l�‘’“”‘l—�‘’“”‘’L�‘l“”è’è�‘’“”‘’�‘’“”è’—�‘’“”‘’L�‘’“”‘’—HHHHHHHLHHH“HHH—� ’ ” ’ � ’ ” ’ � ìì” ìì� ì“” ì—�‘’“”‘’L�‘’“”‘’—HHHHHHHLH‘H“HHH—� ’“” ’L� ’ ” ’ � ’ ” ’L� ’“” ’L�‘’“”‘’L�‘l“”‘’—HHllHHlLHHl“HHl—� ’ ” ’ � l ” ’ � l ” n � l“” nL�‘’”‘’�‘l“”‘’—HHHHHlHhH“HìlL� ’“” ’� l ” ’ � ’” ’� ’“” ’—�‘’“”‘’L�‘’“”‘’—�‘’“”‘’L�‘’“”‘$$�‘’“”‘’L�‘’“”‘’—�‘’L”‘’L�‘’“”‘$$�‘’L”‘’L�‘’“”‘’—�‘’“”‘’L�‘’“”‘’—�‘’“”‘’L�‘’“”‘’—�‘’L”‘’L�‘’“”‘’—�‘’“”‘’L�‘l“”‘’—�‘ll”‘nL�‘ll”‘$$�‘’“”‘’L�‘l“”‘’—�‘lh”‘nL�‘ll”‘$$�‘’”‘’�‘l“”‘’—�‘’”‘’�‘’“”‘’—�‘’”‘’�‘l“”‘’—�‘’”‘’�‘’“”‘’—�‘’“”‘’L�‘’“”‘’—�‘’“”‘’L�‘’“”‘’—�‘’“”‘’L�‘’“”‘’—�‘ì“”‘ìL�‘ìì”‘ìì�‘’L”‘’L�‘’“”‘’—�‘’“”‘’L�‘’“”‘’—�‘’“”‘’L�‘’“”‘’—�‘’L”‘’L�‘’“”‘’—�‘’“”‘’L�‘l“”‘’—�‘lL”‘nL�‘ll”‘nl�‘’“”‘’L�‘l“”‘’—�‘l“”‘nL�‘lh”‘nl�‘’”‘’�‘l“”‘’—�‘’L”‘’L�‘’“”‘’—�‘’”‘’�‘l“”‘’—�‘’”‘’L�‘’—”‘’—�‘’“”‘’L�‘’“”‘’—�‘’“”‘’L�‘’“”‘’—�‘’“”‘’L�‘’“”‘’—�‘’L”‘’L�‘’“”‘’—�‘’“”‘’L�‘’“”‘’—�‘’L”‘’L�‘’“”‘’—�‘’L”‘’L�‘’“”‘’—�‘’“”‘’L�‘’“”‘’—�‘’“”‘’l�‘l“”‘’—�‘ll”‘lL�‘l“”‘’—�‘’“”‘’l�‘l“”‘’—�‘ll”‘nL�‘l“”‘$—�‘’“”‘’�‘l“”‘’—�‘’“”‘l�‘’“”‘l—�‘’L”‘’�‘l“”‘’—�‘’“”‘’�‘’“”‘’—�‘’“”‘’L�‘’“”‘’—HHHHHHHLHH’“HHH—�‘’“”‘’L�‘’“”‘’—�‘ìì”‘ìL�‘ì“”‘ìL�‘’“”‘’L�‘’“”‘’—HHHLHHHLHHH“HHH—�‘’L”‘’L�‘’“”‘’—�‘’L”‘’L�‘’“”‘’L�‘’“”‘’L�‘l“”‘’—HHllHHlLHHl“HH–—�‘’“”‘’L�‘l“”‘’—�‘ll”‘nL�‘l“”‘n—�‘’”‘’�‘l“”‘’—HHHHHlHHH“HHl—�‘’”‘’�‘l“”‘’—�‘’”‘’�‘’“”‘’—�‘’“”‘’L�h’“”‘’—�‘’“”‘’l�h’“”‘$$�‘’“”‘’L�h’“”‘’—�‘’“”‘’l�h’“”‘$$�‘’“”‘’L�h’“”‘’—�‘’“”‘’l�h’“”‘’—�‘’“”‘’L�h’“”‘’—�‘’“”‘’l�h’“”‘’—�‘’“”‘’—�hl“”‘’—�‘ll”‘nl�hll”‘$$�‘’“”‘’—�hl“”‘’—�‘ll”‘nl�hll”‘$$�‘’“”‘’—�hl“”‘’—�‘’“”‘’l�h’“”‘’—�‘’“”‘’—�hl“”‘’—�‘’“”‘’l�h’“”‘’—�‘’“”‘’L�h’“”‘’—�‘’“”‘’L�h’“”‘’—�‘’“”‘’L�h’“”‘’—�‘ìì”‘ìì�hìì”‘ìì�‘’“”‘’L�h’“”‘’—�‘’“”‘’L�h’“”‘’—�‘’“”‘’L�h’“”‘’—�‘’“”‘’L�h’“”‘’—�‘’“”‘’—�hl“”‘’—�‘ll”‘nl�hll”‘nl�‘’“”‘’—�hl“”‘’—�‘ll”‘nl�hll”‘nl�‘’“”‘’—�hl“”‘’—�‘’“”‘’—�h’“”‘’—�‘’“”‘’—�hl“”‘’—�‘’“”‘’—�h’“”‘’—�h’h”i’L�h’h”è’è�h’h”l’L�h’“”l$—�h’h”i’L�h’h”è’è�h’h”i’L�h’“”è$—�h’h”i’L�h’h”è’è�h’h”l’L�h’“”‘’—�h’l”i’L�h’h”è’è�h’h”i’L�h’“”è’—�h’h”i’l�hlh”è’è�hl�”inl�hl“”è$—�h’h”i’l�hlh”è’è�hll”inl�hl“”è$—�h’h”i’l�hlh”è’è�h’h”i’h�h’�”è’—�h’h”i’—�hlh”è’è�h’�”i’h�h’“”è’—�h’L”i’L�h’h”i’hHhHhHlHLHhH“HlH—�h’L”i’L�h’h”‘’h�hìì”iìì�hì“”iìL�h’L”i’L�h’h”i’hHhHhHlHLHhH“H•H—�h’“”i’L�h’l”i’h�h’h”i’L�h’“”i’—�h’h”i’h�hlh”i’hHhllHin�Hhl“Hin—�h’h”i’h�hlh”i’h�hll”inl�hl“”in—�h’h”i’h�hlh”i’hHhHhHiHhHhH“H‘H—�h’ ”i’“�hl ”i’h�h’h”i’h�h’“”i’—�‘’Ì”‘’Ì�h’“”•’—�‘’“”‘’l�h’“”‘$$�‘’Ì”‘’Ì�h’“”‘’—�‘’“”‘’L�h’“”‘$$�‘’Ì”‘’Ì�h’“”‘’—�‘’“”‘’Ì�h’“”‘’—�‘’Ì”‘’Ì�h’“”‘’—�‘’L”‘’Ì�h’“”‘’—�‘’“”‘’—�hl“”‘’—�‘ll”‘nl�hll”‘$$�‘’“”‘’—�hl“”‘’—�‘ll”‘n—�hll”‘$$�‘’“”‘’—�hl“”‘’—�‘’“”‘’—�h’“”‘’—�‘’“”‘’—�hl“”‘’—�‘’“”‘’—�h’“”‘’—�‘’Ì”‘’Ì�h’“”‘’—�‘’Ì”‘’Ì�h’“”‘’—�‘’Ì”‘’Ì�h’“”‘’—�‘ì“”‘ìÌ�hìì”‘ìì�‘’Ì”‘’Ì�h’“”‘’—�‘’Ì”‘’Ì�h’“”‘’—�‘’Ì”‘’Ì�h’“”‘’—�‘’Ì”‘’Ì�h’“”‘’—�‘’“”‘’—�hl“”‘’—�‘ll”‘nl�hll”‘nl�‘’“”‘’—�hl“”‘’—�‘lì”‘n“�hlì”‘nl�‘’“”‘’—�hl“”‘’—�‘’“”‘’—�h’“”‘’—�‘’“”‘’—�hl“”‘’—�‘’ì”‘’Ì�h’“”‘’—�‘’Ì”‘’Ì�‘’“”‘’—�‘’“”l’Ì�‘’“”l’—�‘’Ì”‘’Ì�‘’“”‘’—�‘’“”‘’Ì�‘’“”‘$—�‘’Ì”‘’Ì�‘’“”‘’—�‘’“”l’Ì�‘’“”l’—�‘’Ì”‘’Ì�‘’“”‘’—�‘’“”‘’Ì�‘’“”‘’—�‘’“”‘’l�‘l“”‘’—�‘ll”‘nl�‘l�”‘$—�‘’“”‘’l�‘l“”‘’—�‘l�”‘nl�‘l“”‘$—�‘’“”‘’—�‘l“”‘’—�‘’�”‘’—�‘’“”‘’—�‘’“”‘’—�‘l“”‘’—�‘’“”‘’—�‘’“”‘’—�‘’L”‘’L�‘’“”‘’—HHHÌHlHÌHHl“HlL�‘’L”‘’L�‘’“”‘’—�‘ìÌ”‘ìÌ�‘ì“”‘ì—�‘’L”‘’L�‘’“”‘’—HHHÌHlHÌHHH“HlH—�‘’Ì”‘’L�‘’—”‘’—�‘’Ì”‘’Ì�‘’“”‘’—�‘’“”‘’—�‘l“”‘’—HHllHHnlHHl“HH’—�‘’“”‘’—�‘l“”‘’—�‘ll”‘nl�‘l“”‘n—�‘’“”‘’—�‘l“”‘’—HHH—HHH—HHH“HHH—�‘’ ”‘’�‘l“”‘’—�‘’“”‘’—�‘’“”‘’—
\ No newline at end of file
--- src/video/openglhq/tablebuilder.ui
+++ src/video/openglhq/tablebuilder.ui
@@ -0,0 +1,1038 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <author>JÃ¶rg Walter &lt;jwalt@garni.ch&gt;</author>
+ <comment>Builds scaling tables for the DosBox OpenGL-HQ renderer
+</comment>
+ <class>TableBuilder</class>
+ <widget class="QMainWindow" name="TableBuilder">
+  <property name="geometry">
+   <rect>
+    <x>0</x>
+    <y>0</y>
+    <width>762</width>
+    <height>516</height>
+   </rect>
+  </property>
+  <property name="windowTitle">
+   <string>DosBox OpenGL-HQ Table Builder</string>
+  </property>
+  <widget class="QWidget" name="widget">
+   <layout class="QGridLayout">
+    <item row="1" column="0">
+     <spacer name="spacer2">
+      <property name="orientation">
+       <enum>Qt::Horizontal</enum>
+      </property>
+      <property name="sizeType">
+       <enum>QSizePolicy::Expanding</enum>
+      </property>
+      <property name="sizeHint" stdset="0">
+       <size>
+        <width>44</width>
+        <height>20</height>
+       </size>
+      </property>
+     </spacer>
+    </item>
+    <item row="1" column="2">
+     <spacer name="spacer1">
+      <property name="orientation">
+       <enum>Qt::Horizontal</enum>
+      </property>
+      <property name="sizeType">
+       <enum>QSizePolicy::Expanding</enum>
+      </property>
+      <property name="sizeHint" stdset="0">
+       <size>
+        <width>43</width>
+        <height>20</height>
+       </size>
+      </property>
+     </spacer>
+    </item>
+    <item row="1" column="4">
+     <spacer name="spacer3">
+      <property name="orientation">
+       <enum>Qt::Horizontal</enum>
+      </property>
+      <property name="sizeType">
+       <enum>QSizePolicy::Expanding</enum>
+      </property>
+      <property name="sizeHint" stdset="0">
+       <size>
+        <width>44</width>
+        <height>20</height>
+       </size>
+      </property>
+     </spacer>
+    </item>
+    <item row="0" column="2">
+     <spacer name="spacer5">
+      <property name="orientation">
+       <enum>Qt::Vertical</enum>
+      </property>
+      <property name="sizeType">
+       <enum>QSizePolicy::Expanding</enum>
+      </property>
+      <property name="sizeHint" stdset="0">
+       <size>
+        <width>20</width>
+        <height>40</height>
+       </size>
+      </property>
+     </spacer>
+    </item>
+    <item row="1" column="3">
+     <widget class="QGroupBox" name="groupBox2">
+      <property name="sizePolicy">
+       <sizepolicy hsizetype="Maximum" vsizetype="Maximum">
+        <horstretch>1</horstretch>
+        <verstretch>1</verstretch>
+       </sizepolicy>
+      </property>
+      <property name="title">
+       <string>Resulting Borders</string>
+      </property>
+      <layout class="QGridLayout">
+       <item row="2" column="0" colspan="2">
+        <layout class="QHBoxLayout">
+         <item>
+          <widget class="QCheckBox" name="dEnabled">
+           <property name="sizePolicy">
+            <sizepolicy hsizetype="Minimum" vsizetype="Preferred">
+             <horstretch>0</horstretch>
+             <verstretch>0</verstretch>
+            </sizepolicy>
+           </property>
+           <property name="text">
+            <string>diagonal:</string>
+           </property>
+          </widget>
+         </item>
+         <item>
+          <layout class="QHBoxLayout">
+           <item>
+            <widget class="QLabel" name="y0Label">
+             <property name="sizePolicy">
+              <sizepolicy hsizetype="Maximum" vsizetype="Preferred">
+               <horstretch>0</horstretch>
+               <verstretch>0</verstretch>
+              </sizepolicy>
+             </property>
+             <property name="text">
+              <string>Y&lt;sub&gt;0&lt;/sub&gt;</string>
+             </property>
+             <property name="wordWrap">
+              <bool>false</bool>
+             </property>
+            </widget>
+           </item>
+           <item>
+            <widget class="QSpinBox" name="dY0">
+             <property name="enabled">
+              <bool>false</bool>
+             </property>
+             <property name="sizePolicy">
+              <sizepolicy hsizetype="Minimum" vsizetype="Preferred">
+               <horstretch>0</horstretch>
+               <verstretch>0</verstretch>
+              </sizepolicy>
+             </property>
+             <property name="suffix">
+              <string>/4</string>
+             </property>
+             <property name="minimum">
+              <number>-4</number>
+             </property>
+             <property name="maximum">
+              <number>4</number>
+             </property>
+             <property name="singleStep">
+              <number>1</number>
+             </property>
+             <property name="value">
+              <number>0</number>
+             </property>
+            </widget>
+           </item>
+          </layout>
+         </item>
+         <item>
+          <layout class="QHBoxLayout">
+           <item>
+            <widget class="QLabel" name="gradientLabel">
+             <property name="sizePolicy">
+              <sizepolicy hsizetype="Maximum" vsizetype="Preferred">
+               <horstretch>0</horstretch>
+               <verstretch>0</verstretch>
+              </sizepolicy>
+             </property>
+             <property name="text">
+              <string>grad.</string>
+             </property>
+             <property name="wordWrap">
+              <bool>false</bool>
+             </property>
+            </widget>
+           </item>
+           <item>
+            <widget class="QSpinBox" name="dGrad">
+             <property name="enabled">
+              <bool>false</bool>
+             </property>
+             <property name="sizePolicy">
+              <sizepolicy hsizetype="Minimum" vsizetype="Preferred">
+               <horstretch>0</horstretch>
+               <verstretch>0</verstretch>
+              </sizepolicy>
+             </property>
+             <property name="suffix">
+              <string>/2</string>
+             </property>
+             <property name="minimum">
+              <number>-4</number>
+             </property>
+             <property name="maximum">
+              <number>4</number>
+             </property>
+            </widget>
+           </item>
+          </layout>
+         </item>
+        </layout>
+       </item>
+       <item row="4" column="0" colspan="2">
+        <layout class="QHBoxLayout">
+         <item>
+          <widget class="QPushButton" name="resultReset">
+           <property name="sizePolicy">
+            <sizepolicy hsizetype="Minimum" vsizetype="Preferred">
+             <horstretch>0</horstretch>
+             <verstretch>0</verstretch>
+            </sizepolicy>
+           </property>
+           <property name="text">
+            <string>&amp;Reset</string>
+           </property>
+           <property name="shortcut">
+            <string>Alt+R</string>
+           </property>
+          </widget>
+         </item>
+         <item>
+          <widget class="QPushButton" name="resultSave">
+           <property name="sizePolicy">
+            <sizepolicy hsizetype="Minimum" vsizetype="Preferred">
+             <horstretch>0</horstretch>
+             <verstretch>0</verstretch>
+            </sizepolicy>
+           </property>
+           <property name="text">
+            <string>&amp;Save</string>
+           </property>
+           <property name="shortcut">
+            <string>Alt+S</string>
+           </property>
+           <property name="autoDefault">
+            <bool>true</bool>
+           </property>
+           <property name="default">
+            <bool>true</bool>
+           </property>
+          </widget>
+         </item>
+        </layout>
+       </item>
+       <item row="3" column="0" colspan="2">
+        <layout class="QHBoxLayout">
+         <item>
+          <widget class="QLabel" name="textLabel1_2">
+           <property name="text">
+            <string>Mirror:</string>
+           </property>
+           <property name="wordWrap">
+            <bool>false</bool>
+           </property>
+          </widget>
+         </item>
+         <item>
+          <widget class="QCheckBox" name="hMirror">
+           <property name="text">
+            <string>H/V</string>
+           </property>
+          </widget>
+         </item>
+         <item>
+          <widget class="QCheckBox" name="hvMirror">
+           <property name="text">
+            <string>H+V</string>
+           </property>
+          </widget>
+         </item>
+        </layout>
+       </item>
+       <item row="0" column="0">
+        <widget class="QPushButton" name="vBorder">
+         <property name="sizePolicy">
+          <sizepolicy hsizetype="Minimum" vsizetype="Minimum">
+           <horstretch>0</horstretch>
+           <verstretch>0</verstretch>
+          </sizepolicy>
+         </property>
+         <property name="text">
+          <string/>
+         </property>
+         <property name="checkable">
+          <bool>true</bool>
+         </property>
+         <property name="flat">
+          <bool>true</bool>
+         </property>
+        </widget>
+       </item>
+       <item row="1" column="1">
+        <widget class="QPushButton" name="hBorder">
+         <property name="sizePolicy">
+          <sizepolicy hsizetype="Minimum" vsizetype="Minimum">
+           <horstretch>0</horstretch>
+           <verstretch>0</verstretch>
+          </sizepolicy>
+         </property>
+         <property name="text">
+          <string/>
+         </property>
+         <property name="checkable">
+          <bool>true</bool>
+         </property>
+         <property name="flat">
+          <bool>true</bool>
+         </property>
+        </widget>
+       </item>
+       <item row="1" column="0">
+        <widget class="QCanvasView" name="borderDisplay" native="true">
+         <property name="minimumSize">
+          <size>
+           <width>200</width>
+           <height>200</height>
+          </size>
+         </property>
+         <property name="maximumSize">
+          <size>
+           <width>200</width>
+           <height>200</height>
+          </size>
+         </property>
+        </widget>
+       </item>
+       <item row="0" column="1">
+        <widget class="QPushButton" name="dBorder">
+         <property name="sizePolicy">
+          <sizepolicy hsizetype="Fixed" vsizetype="Fixed">
+           <horstretch>0</horstretch>
+           <verstretch>0</verstretch>
+          </sizepolicy>
+         </property>
+         <property name="minimumSize">
+          <size>
+           <width>40</width>
+           <height>40</height>
+          </size>
+         </property>
+         <property name="maximumSize">
+          <size>
+           <width>40</width>
+           <height>40</height>
+          </size>
+         </property>
+         <property name="text">
+          <string/>
+         </property>
+         <property name="checkable">
+          <bool>true</bool>
+         </property>
+         <property name="flat">
+          <bool>true</bool>
+         </property>
+        </widget>
+       </item>
+      </layout>
+     </widget>
+    </item>
+    <item row="2" column="2">
+     <spacer name="spacer4">
+      <property name="orientation">
+       <enum>Qt::Vertical</enum>
+      </property>
+      <property name="sizeType">
+       <enum>QSizePolicy::Expanding</enum>
+      </property>
+      <property name="sizeHint" stdset="0">
+       <size>
+        <width>20</width>
+        <height>16</height>
+       </size>
+      </property>
+     </spacer>
+    </item>
+    <item row="1" column="1">
+     <widget class="QGroupBox" name="groupBox1">
+      <property name="sizePolicy">
+       <sizepolicy hsizetype="Minimum" vsizetype="Minimum">
+        <horstretch>1</horstretch>
+        <verstretch>1</verstretch>
+       </sizepolicy>
+      </property>
+      <property name="title">
+       <string>Source Pixels</string>
+      </property>
+      <layout class="QGridLayout">
+       <item row="3" column="0" colspan="3">
+        <widget class="QPushButton" name="sourceReset">
+         <property name="text">
+          <string>Reset all</string>
+         </property>
+        </widget>
+       </item>
+       <item row="1" column="1">
+        <widget class="QPushButton" name="cColor">
+         <property name="sizePolicy">
+          <sizepolicy hsizetype="Minimum" vsizetype="Minimum">
+           <horstretch>1</horstretch>
+           <verstretch>1</verstretch>
+          </sizepolicy>
+         </property>
+         <property name="text">
+          <string>C</string>
+         </property>
+        </widget>
+       </item>
+       <item row="0" column="0">
+        <widget class="QPushButton" name="dhColor">
+         <property name="sizePolicy">
+          <sizepolicy hsizetype="Minimum" vsizetype="Minimum">
+           <horstretch>1</horstretch>
+           <verstretch>1</verstretch>
+          </sizepolicy>
+         </property>
+         <property name="text">
+          <string>DH</string>
+         </property>
+        </widget>
+       </item>
+       <item row="0" column="2">
+        <widget class="QPushButton" name="dColor">
+         <property name="sizePolicy">
+          <sizepolicy hsizetype="Minimum" vsizetype="Minimum">
+           <horstretch>1</horstretch>
+           <verstretch>1</verstretch>
+          </sizepolicy>
+         </property>
+         <property name="text">
+          <string>D</string>
+         </property>
+        </widget>
+       </item>
+       <item row="1" column="2">
+        <widget class="QPushButton" name="hColor">
+         <property name="sizePolicy">
+          <sizepolicy hsizetype="Minimum" vsizetype="Minimum">
+           <horstretch>1</horstretch>
+           <verstretch>1</verstretch>
+          </sizepolicy>
+         </property>
+         <property name="text">
+          <string>H</string>
+         </property>
+        </widget>
+       </item>
+       <item row="1" column="0">
+        <widget class="QPushButton" name="hbColor">
+         <property name="sizePolicy">
+          <sizepolicy hsizetype="Minimum" vsizetype="Minimum">
+           <horstretch>1</horstretch>
+           <verstretch>1</verstretch>
+          </sizepolicy>
+         </property>
+         <property name="text">
+          <string>HB</string>
+         </property>
+        </widget>
+       </item>
+       <item row="2" column="0">
+        <widget class="QPushButton" name="dbColor">
+         <property name="sizePolicy">
+          <sizepolicy hsizetype="Minimum" vsizetype="Minimum">
+           <horstretch>1</horstretch>
+           <verstretch>1</verstretch>
+          </sizepolicy>
+         </property>
+         <property name="text">
+          <string>DB</string>
+         </property>
+        </widget>
+       </item>
+       <item row="2" column="1">
+        <widget class="QPushButton" name="vbColor">
+         <property name="sizePolicy">
+          <sizepolicy hsizetype="Minimum" vsizetype="Minimum">
+           <horstretch>1</horstretch>
+           <verstretch>1</verstretch>
+          </sizepolicy>
+         </property>
+         <property name="text">
+          <string>VB</string>
+         </property>
+        </widget>
+       </item>
+       <item row="2" column="2">
+        <widget class="QPushButton" name="dvColor">
+         <property name="sizePolicy">
+          <sizepolicy hsizetype="Minimum" vsizetype="Minimum">
+           <horstretch>1</horstretch>
+           <verstretch>1</verstretch>
+          </sizepolicy>
+         </property>
+         <property name="text">
+          <string>DV</string>
+         </property>
+        </widget>
+       </item>
+       <item row="0" column="1">
+        <widget class="QPushButton" name="vColor">
+         <property name="sizePolicy">
+          <sizepolicy hsizetype="Minimum" vsizetype="Minimum">
+           <horstretch>1</horstretch>
+           <verstretch>1</verstretch>
+          </sizepolicy>
+         </property>
+         <property name="text">
+          <string>V</string>
+         </property>
+        </widget>
+       </item>
+      </layout>
+     </widget>
+    </item>
+   </layout>
+  </widget>
+  <widget class="QMenuBar" name="menubar">
+   <property name="geometry">
+    <rect>
+     <x>0</x>
+     <y>0</y>
+     <width>762</width>
+     <height>21</height>
+    </rect>
+   </property>
+   <widget class="QMenu" name="fileMenu">
+    <property name="title">
+     <string>&amp;File</string>
+    </property>
+    <addaction name="fileNewAction"/>
+    <addaction name="fileOpenAction"/>
+    <addaction name="fileSaveAction"/>
+    <addaction name="fileSaveAsAction"/>
+    <addaction name="separator"/>
+    <addaction name="fileExitAction"/>
+   </widget>
+   <addaction name="fileMenu"/>
+  </widget>
+  <action name="fileNewAction">
+   <property name="icon">
+    <iconset>
+     <normaloff>image1</normaloff>image1</iconset>
+   </property>
+   <property name="text">
+    <string>&amp;New</string>
+   </property>
+   <property name="iconText">
+    <string>New</string>
+   </property>
+   <property name="shortcut">
+    <string>Ctrl+N</string>
+   </property>
+   <property name="name" stdset="0">
+    <cstring>fileNewAction</cstring>
+   </property>
+  </action>
+  <action name="fileOpenAction">
+   <property name="icon">
+    <iconset>
+     <normaloff>image2</normaloff>image2</iconset>
+   </property>
+   <property name="text">
+    <string>&amp;Open...</string>
+   </property>
+   <property name="iconText">
+    <string>Open</string>
+   </property>
+   <property name="shortcut">
+    <string>Ctrl+O</string>
+   </property>
+   <property name="name" stdset="0">
+    <cstring>fileOpenAction</cstring>
+   </property>
+  </action>
+  <action name="fileSaveAction">
+   <property name="icon">
+    <iconset>
+     <normaloff>image3</normaloff>image3</iconset>
+   </property>
+   <property name="text">
+    <string>&amp;Save</string>
+   </property>
+   <property name="iconText">
+    <string>Save</string>
+   </property>
+   <property name="shortcut">
+    <string>Ctrl+S</string>
+   </property>
+   <property name="name" stdset="0">
+    <cstring>fileSaveAction</cstring>
+   </property>
+  </action>
+  <action name="fileSaveAsAction">
+   <property name="text">
+    <string>Save &amp;As...</string>
+   </property>
+   <property name="iconText">
+    <string>Save As</string>
+   </property>
+   <property name="shortcut">
+    <string/>
+   </property>
+   <property name="name" stdset="0">
+    <cstring>fileSaveAsAction</cstring>
+   </property>
+  </action>
+  <action name="fileExitAction">
+   <property name="text">
+    <string>E&amp;xit</string>
+   </property>
+   <property name="iconText">
+    <string>Exit</string>
+   </property>
+   <property name="shortcut">
+    <string/>
+   </property>
+   <property name="name" stdset="0">
+    <cstring>fileExitAction</cstring>
+   </property>
+  </action>
+ </widget>
+ <layoutdefault spacing="6" margin="11"/>
+ <customwidgets>
+  <customwidget>
+   <class>QCanvasView</class>
+   <extends>QWidget</extends>
+   <header>qcanvasview.h</header>
+  </customwidget>
+ </customwidgets>
+ <includes>
+  <include location="local">qcanvasview.h</include>
+ </includes>
+ <resources/>
+ <connections>
+  <connection>
+   <sender>fileNewAction</sender>
+   <signal>activated()</signal>
+   <receiver>TableBuilder</receiver>
+   <slot>file_new()</slot>
+   <hints>
+    <hint type="sourcelabel">
+     <x>-1</x>
+     <y>-1</y>
+    </hint>
+    <hint type="destinationlabel">
+     <x>20</x>
+     <y>20</y>
+    </hint>
+   </hints>
+  </connection>
+  <connection>
+   <sender>fileExitAction</sender>
+   <signal>activated()</signal>
+   <receiver>TableBuilder</receiver>
+   <slot>close()</slot>
+   <hints>
+    <hint type="sourcelabel">
+     <x>-1</x>
+     <y>-1</y>
+    </hint>
+    <hint type="destinationlabel">
+     <x>20</x>
+     <y>20</y>
+    </hint>
+   </hints>
+  </connection>
+  <connection>
+   <sender>sourceReset</sender>
+   <signal>clicked()</signal>
+   <receiver>TableBuilder</receiver>
+   <slot>sourceReset_clicked()</slot>
+   <hints>
+    <hint type="sourcelabel">
+     <x>20</x>
+     <y>20</y>
+    </hint>
+    <hint type="destinationlabel">
+     <x>20</x>
+     <y>20</y>
+    </hint>
+   </hints>
+  </connection>
+  <connection>
+   <sender>resultReset</sender>
+   <signal>clicked()</signal>
+   <receiver>TableBuilder</receiver>
+   <slot>resultReset_clicked()</slot>
+   <hints>
+    <hint type="sourcelabel">
+     <x>20</x>
+     <y>20</y>
+    </hint>
+    <hint type="destinationlabel">
+     <x>20</x>
+     <y>20</y>
+    </hint>
+   </hints>
+  </connection>
+  <connection>
+   <sender>dEnabled</sender>
+   <signal>toggled(bool)</signal>
+   <receiver>dGrad</receiver>
+   <slot>setEnabled(bool)</slot>
+   <hints>
+    <hint type="sourcelabel">
+     <x>20</x>
+     <y>20</y>
+    </hint>
+    <hint type="destinationlabel">
+     <x>20</x>
+     <y>20</y>
+    </hint>
+   </hints>
+  </connection>
+  <connection>
+   <sender>dEnabled</sender>
+   <signal>toggled(bool)</signal>
+   <receiver>dY0</receiver>
+   <slot>setEnabled(bool)</slot>
+   <hints>
+    <hint type="sourcelabel">
+     <x>20</x>
+     <y>20</y>
+    </hint>
+    <hint type="destinationlabel">
+     <x>20</x>
+     <y>20</y>
+    </hint>
+   </hints>
+  </connection>
+  <connection>
+   <sender>resultSave</sender>
+   <signal>clicked()</signal>
+   <receiver>TableBuilder</receiver>
+   <slot>resultSave_clicked()</slot>
+   <hints>
+    <hint type="sourcelabel">
+     <x>20</x>
+     <y>20</y>
+    </hint>
+    <hint type="destinationlabel">
+     <x>20</x>
+     <y>20</y>
+    </hint>
+   </hints>
+  </connection>
+  <connection>
+   <sender>dhColor</sender>
+   <signal>clicked()</signal>
+   <receiver>TableBuilder</receiver>
+   <slot>dhColor_clicked()</slot>
+   <hints>
+    <hint type="sourcelabel">
+     <x>20</x>
+     <y>20</y>
+    </hint>
+    <hint type="destinationlabel">
+     <x>20</x>
+     <y>20</y>
+    </hint>
+   </hints>
+  </connection>
+  <connection>
+   <sender>vColor</sender>
+   <signal>clicked()</signal>
+   <receiver>TableBuilder</receiver>
+   <slot>vColor_clicked()</slot>
+   <hints>
+    <hint type="sourcelabel">
+     <x>20</x>
+     <y>20</y>
+    </hint>
+    <hint type="destinationlabel">
+     <x>20</x>
+     <y>20</y>
+    </hint>
+   </hints>
+  </connection>
+  <connection>
+   <sender>dColor</sender>
+   <signal>clicked()</signal>
+   <receiver>TableBuilder</receiver>
+   <slot>dColor_clicked()</slot>
+   <hints>
+    <hint type="sourcelabel">
+     <x>20</x>
+     <y>20</y>
+    </hint>
+    <hint type="destinationlabel">
+     <x>20</x>
+     <y>20</y>
+    </hint>
+   </hints>
+  </connection>
+  <connection>
+   <sender>hbColor</sender>
+   <signal>clicked()</signal>
+   <receiver>TableBuilder</receiver>
+   <slot>hbColor_clicked()</slot>
+   <hints>
+    <hint type="sourcelabel">
+     <x>20</x>
+     <y>20</y>
+    </hint>
+    <hint type="destinationlabel">
+     <x>20</x>
+     <y>20</y>
+    </hint>
+   </hints>
+  </connection>
+  <connection>
+   <sender>cColor</sender>
+   <signal>clicked()</signal>
+   <receiver>TableBuilder</receiver>
+   <slot>cColor_clicked()</slot>
+   <hints>
+    <hint type="sourcelabel">
+     <x>20</x>
+     <y>20</y>
+    </hint>
+    <hint type="destinationlabel">
+     <x>20</x>
+     <y>20</y>
+    </hint>
+   </hints>
+  </connection>
+  <connection>
+   <sender>hColor</sender>
+   <signal>clicked()</signal>
+   <receiver>TableBuilder</receiver>
+   <slot>hColor_clicked()</slot>
+   <hints>
+    <hint type="sourcelabel">
+     <x>20</x>
+     <y>20</y>
+    </hint>
+    <hint type="destinationlabel">
+     <x>20</x>
+     <y>20</y>
+    </hint>
+   </hints>
+  </connection>
+  <connection>
+   <sender>dbColor</sender>
+   <signal>clicked()</signal>
+   <receiver>TableBuilder</receiver>
+   <slot>dbColor_clicked()</slot>
+   <hints>
+    <hint type="sourcelabel">
+     <x>20</x>
+     <y>20</y>
+    </hint>
+    <hint type="destinationlabel">
+     <x>20</x>
+     <y>20</y>
+    </hint>
+   </hints>
+  </connection>
+  <connection>
+   <sender>vbColor</sender>
+   <signal>clicked()</signal>
+   <receiver>TableBuilder</receiver>
+   <slot>vbColor_clicked()</slot>
+   <hints>
+    <hint type="sourcelabel">
+     <x>20</x>
+     <y>20</y>
+    </hint>
+    <hint type="destinationlabel">
+     <x>20</x>
+     <y>20</y>
+    </hint>
+   </hints>
+  </connection>
+  <connection>
+   <sender>dvColor</sender>
+   <signal>clicked()</signal>
+   <receiver>TableBuilder</receiver>
+   <slot>dvColor_clicked()</slot>
+   <hints>
+    <hint type="sourcelabel">
+     <x>20</x>
+     <y>20</y>
+    </hint>
+    <hint type="destinationlabel">
+     <x>20</x>
+     <y>20</y>
+    </hint>
+   </hints>
+  </connection>
+  <connection>
+   <sender>vBorder</sender>
+   <signal>toggled(bool)</signal>
+   <receiver>TableBuilder</receiver>
+   <slot>result_changed()</slot>
+   <hints>
+    <hint type="sourcelabel">
+     <x>20</x>
+     <y>20</y>
+    </hint>
+    <hint type="destinationlabel">
+     <x>20</x>
+     <y>20</y>
+    </hint>
+   </hints>
+  </connection>
+  <connection>
+   <sender>dBorder</sender>
+   <signal>toggled(bool)</signal>
+   <receiver>TableBuilder</receiver>
+   <slot>result_changed()</slot>
+   <hints>
+    <hint type="sourcelabel">
+     <x>20</x>
+     <y>20</y>
+    </hint>
+    <hint type="destinationlabel">
+     <x>20</x>
+     <y>20</y>
+    </hint>
+   </hints>
+  </connection>
+  <connection>
+   <sender>hBorder</sender>
+   <signal>toggled(bool)</signal>
+   <receiver>TableBuilder</receiver>
+   <slot>result_changed()</slot>
+   <hints>
+    <hint type="sourcelabel">
+     <x>20</x>
+     <y>20</y>
+    </hint>
+    <hint type="destinationlabel">
+     <x>20</x>
+     <y>20</y>
+    </hint>
+   </hints>
+  </connection>
+  <connection>
+   <sender>dEnabled</sender>
+   <signal>toggled(bool)</signal>
+   <receiver>TableBuilder</receiver>
+   <slot>result_changed()</slot>
+   <hints>
+    <hint type="sourcelabel">
+     <x>20</x>
+     <y>20</y>
+    </hint>
+    <hint type="destinationlabel">
+     <x>20</x>
+     <y>20</y>
+    </hint>
+   </hints>
+  </connection>
+  <connection>
+   <sender>dY0</sender>
+   <signal>valueChanged(int)</signal>
+   <receiver>TableBuilder</receiver>
+   <slot>result_changed()</slot>
+   <hints>
+    <hint type="sourcelabel">
+     <x>20</x>
+     <y>20</y>
+    </hint>
+    <hint type="destinationlabel">
+     <x>20</x>
+     <y>20</y>
+    </hint>
+   </hints>
+  </connection>
+  <connection>
+   <sender>dGrad</sender>
+   <signal>valueChanged(int)</signal>
+   <receiver>TableBuilder</receiver>
+   <slot>result_changed()</slot>
+   <hints>
+    <hint type="sourcelabel">
+     <x>20</x>
+     <y>20</y>
+    </hint>
+    <hint type="destinationlabel">
+     <x>20</x>
+     <y>20</y>
+    </hint>
+   </hints>
+  </connection>
+  <connection>
+   <sender>fileOpenAction</sender>
+   <signal>activated()</signal>
+   <receiver>TableBuilder</receiver>
+   <slot>fileOpenAction_activated()</slot>
+   <hints>
+    <hint type="sourcelabel">
+     <x>-1</x>
+     <y>-1</y>
+    </hint>
+    <hint type="destinationlabel">
+     <x>20</x>
+     <y>20</y>
+    </hint>
+   </hints>
+  </connection>
+  <connection>
+   <sender>fileSaveAction</sender>
+   <signal>activated()</signal>
+   <receiver>TableBuilder</receiver>
+   <slot>fileSaveAction_activated()</slot>
+   <hints>
+    <hint type="sourcelabel">
+     <x>-1</x>
+     <y>-1</y>
+    </hint>
+    <hint type="destinationlabel">
+     <x>20</x>
+     <y>20</y>
+    </hint>
+   </hints>
+  </connection>
+  <connection>
+   <sender>fileSaveAsAction</sender>
+   <signal>activated()</signal>
+   <receiver>TableBuilder</receiver>
+   <slot>fileSaveAsAction_activated()</slot>
+   <hints>
+    <hint type="sourcelabel">
+     <x>-1</x>
+     <y>-1</y>
+    </hint>
+    <hint type="destinationlabel">
+     <x>20</x>
+     <y>20</y>
+    </hint>
+   </hints>
+  </connection>
+ </connections>
+</ui>
--- src/video/openglhq/test.c
+++ src/video/openglhq/test.c
@@ -0,0 +1,77 @@
+#include <stdlib.h>
+#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;
