src/video/windx5/SDL_dx5video.c
author Sam Lantinga <slouken@libsdl.org>
Mon, 30 Jan 2006 06:56:10 +0000
changeset 1295 c3e36ac8a94c
parent 1291 31331c444ea2
child 1312 c9b51268668f
permissions -rw-r--r--
Date: Sun, 6 Mar 2005 17:06:20 +0100
From: Per Inge Mathisen
Subject: [SDL] Fullscreen refresh on win32

Windows has a terrible default for fullscreen 3D apps of 60mhz refresh
rate. This can be fixed by the user by going into his driver's
control panel and forcing the refresh rate higher. However, this not a
very user friendly way about it, and in any case SDL contains no code
that could figure out this that condition has afflicted the user.

So the question is, could SDL fix this for the user? It is possible
under Windows to request a higher refresh rate. The danger is of
course that if the user has an old monitor, and you request a too high
refresh rate, the monitor could be damaged. However, I believe there
might be a way around that: Check before switching what refresh rate
the user's desktop runs in, and if our fullscreen dimensions are equal
or less than those of the desktop, use the higher refresh rate of 60
and the desktop rate.

Since most users run their desktops in the same or higher resolution
something sane, this should fix this problem for most users.

Thoughts?

An alternative is to add an SDL_GL_GetAttribute(SDL_GL_REFRESH_RATE)
option so that programs can bitch at their users at their own
convenience.

- Per
     1 /*
     2     SDL - Simple DirectMedia Layer
     3     Copyright (C) 1997-2004 Sam Lantinga
     4 
     5     This library is free software; you can redistribute it and/or
     6     modify it under the terms of the GNU Library General Public
     7     License as published by the Free Software Foundation; either
     8     version 2 of the License, or (at your option) any later version.
     9 
    10     This library is distributed in the hope that it will be useful,
    11     but WITHOUT ANY WARRANTY; without even the implied warranty of
    12     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
    13     Library General Public License for more details.
    14 
    15     You should have received a copy of the GNU Library General Public
    16     License along with this library; if not, write to the Free
    17     Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
    18 
    19     Sam Lantinga
    20     slouken@libsdl.org
    21 */
    22 
    23 #ifdef SAVE_RCSID
    24 static char rcsid =
    25  "@(#) $Id$";
    26 #endif
    27 
    28 #include <stdio.h>
    29 #include <stdlib.h>
    30 #include <malloc.h>
    31 #include <windows.h>
    32 #include "directx.h"
    33 
    34 /* Not yet in the mingw32 cross-compile headers */
    35 #ifndef CDS_FULLSCREEN
    36 #define CDS_FULLSCREEN	4
    37 #endif
    38 
    39 #include "SDL_error.h"
    40 #include "SDL_timer.h"
    41 #include "SDL_events.h"
    42 #include "SDL_syswm.h"
    43 #include "SDL_sysvideo.h"
    44 #include "SDL_blit.h"
    45 #include "SDL_pixels_c.h"
    46 #include "SDL_dx5video.h"
    47 #include "SDL_syswm_c.h"
    48 #include "SDL_sysmouse_c.h"
    49 #include "SDL_dx5events_c.h"
    50 #include "SDL_dx5yuv_c.h"
    51 #include "SDL_wingl_c.h"
    52 
    53 #ifdef _WIN32_WCE
    54 #define NO_CHANGEDISPLAYSETTINGS
    55 #endif
    56 #ifndef WS_MAXIMIZE
    57 #define WS_MAXIMIZE		0
    58 #endif
    59 #ifndef SWP_NOCOPYBITS
    60 #define SWP_NOCOPYBITS	0
    61 #endif
    62 #ifndef PC_NOCOLLAPSE
    63 #define PC_NOCOLLAPSE	0
    64 #endif
    65 
    66 
    67 /* DirectX function pointers for video and events */
    68 HRESULT (WINAPI *DDrawCreate)( GUID FAR *lpGUID, LPDIRECTDRAW FAR *lplpDD, IUnknown FAR *pUnkOuter );
    69 HRESULT (WINAPI *DInputCreate)(HINSTANCE hinst, DWORD dwVersion, LPDIRECTINPUT *ppDI, LPUNKNOWN punkOuter);
    70 
    71 /* This is the rect EnumModes2 uses */
    72 struct DX5EnumRect {
    73 	SDL_Rect r;
    74 	int refreshRate;
    75 	struct DX5EnumRect* next;
    76 };
    77 static struct DX5EnumRect *enumlists[NUM_MODELISTS];
    78 
    79 /*
    80  * Experimentally determined values for c_cfDI* constants used in DirectX 5.0
    81  */
    82 
    83 /* Keyboard */
    84 
    85 static DIOBJECTDATAFORMAT KBD_fmt[] = {
    86 	{ &GUID_Key, 0, 0x8000000C, 0x00000000 },
    87 	{ &GUID_Key, 1, 0x8000010C, 0x00000000 },
    88 	{ &GUID_Key, 2, 0x8000020C, 0x00000000 },
    89 	{ &GUID_Key, 3, 0x8000030C, 0x00000000 },
    90 	{ &GUID_Key, 4, 0x8000040C, 0x00000000 },
    91 	{ &GUID_Key, 5, 0x8000050C, 0x00000000 },
    92 	{ &GUID_Key, 6, 0x8000060C, 0x00000000 },
    93 	{ &GUID_Key, 7, 0x8000070C, 0x00000000 },
    94 	{ &GUID_Key, 8, 0x8000080C, 0x00000000 },
    95 	{ &GUID_Key, 9, 0x8000090C, 0x00000000 },
    96 	{ &GUID_Key, 10, 0x80000A0C, 0x00000000 },
    97 	{ &GUID_Key, 11, 0x80000B0C, 0x00000000 },
    98 	{ &GUID_Key, 12, 0x80000C0C, 0x00000000 },
    99 	{ &GUID_Key, 13, 0x80000D0C, 0x00000000 },
   100 	{ &GUID_Key, 14, 0x80000E0C, 0x00000000 },
   101 	{ &GUID_Key, 15, 0x80000F0C, 0x00000000 },
   102 	{ &GUID_Key, 16, 0x8000100C, 0x00000000 },
   103 	{ &GUID_Key, 17, 0x8000110C, 0x00000000 },
   104 	{ &GUID_Key, 18, 0x8000120C, 0x00000000 },
   105 	{ &GUID_Key, 19, 0x8000130C, 0x00000000 },
   106 	{ &GUID_Key, 20, 0x8000140C, 0x00000000 },
   107 	{ &GUID_Key, 21, 0x8000150C, 0x00000000 },
   108 	{ &GUID_Key, 22, 0x8000160C, 0x00000000 },
   109 	{ &GUID_Key, 23, 0x8000170C, 0x00000000 },
   110 	{ &GUID_Key, 24, 0x8000180C, 0x00000000 },
   111 	{ &GUID_Key, 25, 0x8000190C, 0x00000000 },
   112 	{ &GUID_Key, 26, 0x80001A0C, 0x00000000 },
   113 	{ &GUID_Key, 27, 0x80001B0C, 0x00000000 },
   114 	{ &GUID_Key, 28, 0x80001C0C, 0x00000000 },
   115 	{ &GUID_Key, 29, 0x80001D0C, 0x00000000 },
   116 	{ &GUID_Key, 30, 0x80001E0C, 0x00000000 },
   117 	{ &GUID_Key, 31, 0x80001F0C, 0x00000000 },
   118 	{ &GUID_Key, 32, 0x8000200C, 0x00000000 },
   119 	{ &GUID_Key, 33, 0x8000210C, 0x00000000 },
   120 	{ &GUID_Key, 34, 0x8000220C, 0x00000000 },
   121 	{ &GUID_Key, 35, 0x8000230C, 0x00000000 },
   122 	{ &GUID_Key, 36, 0x8000240C, 0x00000000 },
   123 	{ &GUID_Key, 37, 0x8000250C, 0x00000000 },
   124 	{ &GUID_Key, 38, 0x8000260C, 0x00000000 },
   125 	{ &GUID_Key, 39, 0x8000270C, 0x00000000 },
   126 	{ &GUID_Key, 40, 0x8000280C, 0x00000000 },
   127 	{ &GUID_Key, 41, 0x8000290C, 0x00000000 },
   128 	{ &GUID_Key, 42, 0x80002A0C, 0x00000000 },
   129 	{ &GUID_Key, 43, 0x80002B0C, 0x00000000 },
   130 	{ &GUID_Key, 44, 0x80002C0C, 0x00000000 },
   131 	{ &GUID_Key, 45, 0x80002D0C, 0x00000000 },
   132 	{ &GUID_Key, 46, 0x80002E0C, 0x00000000 },
   133 	{ &GUID_Key, 47, 0x80002F0C, 0x00000000 },
   134 	{ &GUID_Key, 48, 0x8000300C, 0x00000000 },
   135 	{ &GUID_Key, 49, 0x8000310C, 0x00000000 },
   136 	{ &GUID_Key, 50, 0x8000320C, 0x00000000 },
   137 	{ &GUID_Key, 51, 0x8000330C, 0x00000000 },
   138 	{ &GUID_Key, 52, 0x8000340C, 0x00000000 },
   139 	{ &GUID_Key, 53, 0x8000350C, 0x00000000 },
   140 	{ &GUID_Key, 54, 0x8000360C, 0x00000000 },
   141 	{ &GUID_Key, 55, 0x8000370C, 0x00000000 },
   142 	{ &GUID_Key, 56, 0x8000380C, 0x00000000 },
   143 	{ &GUID_Key, 57, 0x8000390C, 0x00000000 },
   144 	{ &GUID_Key, 58, 0x80003A0C, 0x00000000 },
   145 	{ &GUID_Key, 59, 0x80003B0C, 0x00000000 },
   146 	{ &GUID_Key, 60, 0x80003C0C, 0x00000000 },
   147 	{ &GUID_Key, 61, 0x80003D0C, 0x00000000 },
   148 	{ &GUID_Key, 62, 0x80003E0C, 0x00000000 },
   149 	{ &GUID_Key, 63, 0x80003F0C, 0x00000000 },
   150 	{ &GUID_Key, 64, 0x8000400C, 0x00000000 },
   151 	{ &GUID_Key, 65, 0x8000410C, 0x00000000 },
   152 	{ &GUID_Key, 66, 0x8000420C, 0x00000000 },
   153 	{ &GUID_Key, 67, 0x8000430C, 0x00000000 },
   154 	{ &GUID_Key, 68, 0x8000440C, 0x00000000 },
   155 	{ &GUID_Key, 69, 0x8000450C, 0x00000000 },
   156 	{ &GUID_Key, 70, 0x8000460C, 0x00000000 },
   157 	{ &GUID_Key, 71, 0x8000470C, 0x00000000 },
   158 	{ &GUID_Key, 72, 0x8000480C, 0x00000000 },
   159 	{ &GUID_Key, 73, 0x8000490C, 0x00000000 },
   160 	{ &GUID_Key, 74, 0x80004A0C, 0x00000000 },
   161 	{ &GUID_Key, 75, 0x80004B0C, 0x00000000 },
   162 	{ &GUID_Key, 76, 0x80004C0C, 0x00000000 },
   163 	{ &GUID_Key, 77, 0x80004D0C, 0x00000000 },
   164 	{ &GUID_Key, 78, 0x80004E0C, 0x00000000 },
   165 	{ &GUID_Key, 79, 0x80004F0C, 0x00000000 },
   166 	{ &GUID_Key, 80, 0x8000500C, 0x00000000 },
   167 	{ &GUID_Key, 81, 0x8000510C, 0x00000000 },
   168 	{ &GUID_Key, 82, 0x8000520C, 0x00000000 },
   169 	{ &GUID_Key, 83, 0x8000530C, 0x00000000 },
   170 	{ &GUID_Key, 84, 0x8000540C, 0x00000000 },
   171 	{ &GUID_Key, 85, 0x8000550C, 0x00000000 },
   172 	{ &GUID_Key, 86, 0x8000560C, 0x00000000 },
   173 	{ &GUID_Key, 87, 0x8000570C, 0x00000000 },
   174 	{ &GUID_Key, 88, 0x8000580C, 0x00000000 },
   175 	{ &GUID_Key, 89, 0x8000590C, 0x00000000 },
   176 	{ &GUID_Key, 90, 0x80005A0C, 0x00000000 },
   177 	{ &GUID_Key, 91, 0x80005B0C, 0x00000000 },
   178 	{ &GUID_Key, 92, 0x80005C0C, 0x00000000 },
   179 	{ &GUID_Key, 93, 0x80005D0C, 0x00000000 },
   180 	{ &GUID_Key, 94, 0x80005E0C, 0x00000000 },
   181 	{ &GUID_Key, 95, 0x80005F0C, 0x00000000 },
   182 	{ &GUID_Key, 96, 0x8000600C, 0x00000000 },
   183 	{ &GUID_Key, 97, 0x8000610C, 0x00000000 },
   184 	{ &GUID_Key, 98, 0x8000620C, 0x00000000 },
   185 	{ &GUID_Key, 99, 0x8000630C, 0x00000000 },
   186 	{ &GUID_Key, 100, 0x8000640C, 0x00000000 },
   187 	{ &GUID_Key, 101, 0x8000650C, 0x00000000 },
   188 	{ &GUID_Key, 102, 0x8000660C, 0x00000000 },
   189 	{ &GUID_Key, 103, 0x8000670C, 0x00000000 },
   190 	{ &GUID_Key, 104, 0x8000680C, 0x00000000 },
   191 	{ &GUID_Key, 105, 0x8000690C, 0x00000000 },
   192 	{ &GUID_Key, 106, 0x80006A0C, 0x00000000 },
   193 	{ &GUID_Key, 107, 0x80006B0C, 0x00000000 },
   194 	{ &GUID_Key, 108, 0x80006C0C, 0x00000000 },
   195 	{ &GUID_Key, 109, 0x80006D0C, 0x00000000 },
   196 	{ &GUID_Key, 110, 0x80006E0C, 0x00000000 },
   197 	{ &GUID_Key, 111, 0x80006F0C, 0x00000000 },
   198 	{ &GUID_Key, 112, 0x8000700C, 0x00000000 },
   199 	{ &GUID_Key, 113, 0x8000710C, 0x00000000 },
   200 	{ &GUID_Key, 114, 0x8000720C, 0x00000000 },
   201 	{ &GUID_Key, 115, 0x8000730C, 0x00000000 },
   202 	{ &GUID_Key, 116, 0x8000740C, 0x00000000 },
   203 	{ &GUID_Key, 117, 0x8000750C, 0x00000000 },
   204 	{ &GUID_Key, 118, 0x8000760C, 0x00000000 },
   205 	{ &GUID_Key, 119, 0x8000770C, 0x00000000 },
   206 	{ &GUID_Key, 120, 0x8000780C, 0x00000000 },
   207 	{ &GUID_Key, 121, 0x8000790C, 0x00000000 },
   208 	{ &GUID_Key, 122, 0x80007A0C, 0x00000000 },
   209 	{ &GUID_Key, 123, 0x80007B0C, 0x00000000 },
   210 	{ &GUID_Key, 124, 0x80007C0C, 0x00000000 },
   211 	{ &GUID_Key, 125, 0x80007D0C, 0x00000000 },
   212 	{ &GUID_Key, 126, 0x80007E0C, 0x00000000 },
   213 	{ &GUID_Key, 127, 0x80007F0C, 0x00000000 },
   214 	{ &GUID_Key, 128, 0x8000800C, 0x00000000 },
   215 	{ &GUID_Key, 129, 0x8000810C, 0x00000000 },
   216 	{ &GUID_Key, 130, 0x8000820C, 0x00000000 },
   217 	{ &GUID_Key, 131, 0x8000830C, 0x00000000 },
   218 	{ &GUID_Key, 132, 0x8000840C, 0x00000000 },
   219 	{ &GUID_Key, 133, 0x8000850C, 0x00000000 },
   220 	{ &GUID_Key, 134, 0x8000860C, 0x00000000 },
   221 	{ &GUID_Key, 135, 0x8000870C, 0x00000000 },
   222 	{ &GUID_Key, 136, 0x8000880C, 0x00000000 },
   223 	{ &GUID_Key, 137, 0x8000890C, 0x00000000 },
   224 	{ &GUID_Key, 138, 0x80008A0C, 0x00000000 },
   225 	{ &GUID_Key, 139, 0x80008B0C, 0x00000000 },
   226 	{ &GUID_Key, 140, 0x80008C0C, 0x00000000 },
   227 	{ &GUID_Key, 141, 0x80008D0C, 0x00000000 },
   228 	{ &GUID_Key, 142, 0x80008E0C, 0x00000000 },
   229 	{ &GUID_Key, 143, 0x80008F0C, 0x00000000 },
   230 	{ &GUID_Key, 144, 0x8000900C, 0x00000000 },
   231 	{ &GUID_Key, 145, 0x8000910C, 0x00000000 },
   232 	{ &GUID_Key, 146, 0x8000920C, 0x00000000 },
   233 	{ &GUID_Key, 147, 0x8000930C, 0x00000000 },
   234 	{ &GUID_Key, 148, 0x8000940C, 0x00000000 },
   235 	{ &GUID_Key, 149, 0x8000950C, 0x00000000 },
   236 	{ &GUID_Key, 150, 0x8000960C, 0x00000000 },
   237 	{ &GUID_Key, 151, 0x8000970C, 0x00000000 },
   238 	{ &GUID_Key, 152, 0x8000980C, 0x00000000 },
   239 	{ &GUID_Key, 153, 0x8000990C, 0x00000000 },
   240 	{ &GUID_Key, 154, 0x80009A0C, 0x00000000 },
   241 	{ &GUID_Key, 155, 0x80009B0C, 0x00000000 },
   242 	{ &GUID_Key, 156, 0x80009C0C, 0x00000000 },
   243 	{ &GUID_Key, 157, 0x80009D0C, 0x00000000 },
   244 	{ &GUID_Key, 158, 0x80009E0C, 0x00000000 },
   245 	{ &GUID_Key, 159, 0x80009F0C, 0x00000000 },
   246 	{ &GUID_Key, 160, 0x8000A00C, 0x00000000 },
   247 	{ &GUID_Key, 161, 0x8000A10C, 0x00000000 },
   248 	{ &GUID_Key, 162, 0x8000A20C, 0x00000000 },
   249 	{ &GUID_Key, 163, 0x8000A30C, 0x00000000 },
   250 	{ &GUID_Key, 164, 0x8000A40C, 0x00000000 },
   251 	{ &GUID_Key, 165, 0x8000A50C, 0x00000000 },
   252 	{ &GUID_Key, 166, 0x8000A60C, 0x00000000 },
   253 	{ &GUID_Key, 167, 0x8000A70C, 0x00000000 },
   254 	{ &GUID_Key, 168, 0x8000A80C, 0x00000000 },
   255 	{ &GUID_Key, 169, 0x8000A90C, 0x00000000 },
   256 	{ &GUID_Key, 170, 0x8000AA0C, 0x00000000 },
   257 	{ &GUID_Key, 171, 0x8000AB0C, 0x00000000 },
   258 	{ &GUID_Key, 172, 0x8000AC0C, 0x00000000 },
   259 	{ &GUID_Key, 173, 0x8000AD0C, 0x00000000 },
   260 	{ &GUID_Key, 174, 0x8000AE0C, 0x00000000 },
   261 	{ &GUID_Key, 175, 0x8000AF0C, 0x00000000 },
   262 	{ &GUID_Key, 176, 0x8000B00C, 0x00000000 },
   263 	{ &GUID_Key, 177, 0x8000B10C, 0x00000000 },
   264 	{ &GUID_Key, 178, 0x8000B20C, 0x00000000 },
   265 	{ &GUID_Key, 179, 0x8000B30C, 0x00000000 },
   266 	{ &GUID_Key, 180, 0x8000B40C, 0x00000000 },
   267 	{ &GUID_Key, 181, 0x8000B50C, 0x00000000 },
   268 	{ &GUID_Key, 182, 0x8000B60C, 0x00000000 },
   269 	{ &GUID_Key, 183, 0x8000B70C, 0x00000000 },
   270 	{ &GUID_Key, 184, 0x8000B80C, 0x00000000 },
   271 	{ &GUID_Key, 185, 0x8000B90C, 0x00000000 },
   272 	{ &GUID_Key, 186, 0x8000BA0C, 0x00000000 },
   273 	{ &GUID_Key, 187, 0x8000BB0C, 0x00000000 },
   274 	{ &GUID_Key, 188, 0x8000BC0C, 0x00000000 },
   275 	{ &GUID_Key, 189, 0x8000BD0C, 0x00000000 },
   276 	{ &GUID_Key, 190, 0x8000BE0C, 0x00000000 },
   277 	{ &GUID_Key, 191, 0x8000BF0C, 0x00000000 },
   278 	{ &GUID_Key, 192, 0x8000C00C, 0x00000000 },
   279 	{ &GUID_Key, 193, 0x8000C10C, 0x00000000 },
   280 	{ &GUID_Key, 194, 0x8000C20C, 0x00000000 },
   281 	{ &GUID_Key, 195, 0x8000C30C, 0x00000000 },
   282 	{ &GUID_Key, 196, 0x8000C40C, 0x00000000 },
   283 	{ &GUID_Key, 197, 0x8000C50C, 0x00000000 },
   284 	{ &GUID_Key, 198, 0x8000C60C, 0x00000000 },
   285 	{ &GUID_Key, 199, 0x8000C70C, 0x00000000 },
   286 	{ &GUID_Key, 200, 0x8000C80C, 0x00000000 },
   287 	{ &GUID_Key, 201, 0x8000C90C, 0x00000000 },
   288 	{ &GUID_Key, 202, 0x8000CA0C, 0x00000000 },
   289 	{ &GUID_Key, 203, 0x8000CB0C, 0x00000000 },
   290 	{ &GUID_Key, 204, 0x8000CC0C, 0x00000000 },
   291 	{ &GUID_Key, 205, 0x8000CD0C, 0x00000000 },
   292 	{ &GUID_Key, 206, 0x8000CE0C, 0x00000000 },
   293 	{ &GUID_Key, 207, 0x8000CF0C, 0x00000000 },
   294 	{ &GUID_Key, 208, 0x8000D00C, 0x00000000 },
   295 	{ &GUID_Key, 209, 0x8000D10C, 0x00000000 },
   296 	{ &GUID_Key, 210, 0x8000D20C, 0x00000000 },
   297 	{ &GUID_Key, 211, 0x8000D30C, 0x00000000 },
   298 	{ &GUID_Key, 212, 0x8000D40C, 0x00000000 },
   299 	{ &GUID_Key, 213, 0x8000D50C, 0x00000000 },
   300 	{ &GUID_Key, 214, 0x8000D60C, 0x00000000 },
   301 	{ &GUID_Key, 215, 0x8000D70C, 0x00000000 },
   302 	{ &GUID_Key, 216, 0x8000D80C, 0x00000000 },
   303 	{ &GUID_Key, 217, 0x8000D90C, 0x00000000 },
   304 	{ &GUID_Key, 218, 0x8000DA0C, 0x00000000 },
   305 	{ &GUID_Key, 219, 0x8000DB0C, 0x00000000 },
   306 	{ &GUID_Key, 220, 0x8000DC0C, 0x00000000 },
   307 	{ &GUID_Key, 221, 0x8000DD0C, 0x00000000 },
   308 	{ &GUID_Key, 222, 0x8000DE0C, 0x00000000 },
   309 	{ &GUID_Key, 223, 0x8000DF0C, 0x00000000 },
   310 	{ &GUID_Key, 224, 0x8000E00C, 0x00000000 },
   311 	{ &GUID_Key, 225, 0x8000E10C, 0x00000000 },
   312 	{ &GUID_Key, 226, 0x8000E20C, 0x00000000 },
   313 	{ &GUID_Key, 227, 0x8000E30C, 0x00000000 },
   314 	{ &GUID_Key, 228, 0x8000E40C, 0x00000000 },
   315 	{ &GUID_Key, 229, 0x8000E50C, 0x00000000 },
   316 	{ &GUID_Key, 230, 0x8000E60C, 0x00000000 },
   317 	{ &GUID_Key, 231, 0x8000E70C, 0x00000000 },
   318 	{ &GUID_Key, 232, 0x8000E80C, 0x00000000 },
   319 	{ &GUID_Key, 233, 0x8000E90C, 0x00000000 },
   320 	{ &GUID_Key, 234, 0x8000EA0C, 0x00000000 },
   321 	{ &GUID_Key, 235, 0x8000EB0C, 0x00000000 },
   322 	{ &GUID_Key, 236, 0x8000EC0C, 0x00000000 },
   323 	{ &GUID_Key, 237, 0x8000ED0C, 0x00000000 },
   324 	{ &GUID_Key, 238, 0x8000EE0C, 0x00000000 },
   325 	{ &GUID_Key, 239, 0x8000EF0C, 0x00000000 },
   326 	{ &GUID_Key, 240, 0x8000F00C, 0x00000000 },
   327 	{ &GUID_Key, 241, 0x8000F10C, 0x00000000 },
   328 	{ &GUID_Key, 242, 0x8000F20C, 0x00000000 },
   329 	{ &GUID_Key, 243, 0x8000F30C, 0x00000000 },
   330 	{ &GUID_Key, 244, 0x8000F40C, 0x00000000 },
   331 	{ &GUID_Key, 245, 0x8000F50C, 0x00000000 },
   332 	{ &GUID_Key, 246, 0x8000F60C, 0x00000000 },
   333 	{ &GUID_Key, 247, 0x8000F70C, 0x00000000 },
   334 	{ &GUID_Key, 248, 0x8000F80C, 0x00000000 },
   335 	{ &GUID_Key, 249, 0x8000F90C, 0x00000000 },
   336 	{ &GUID_Key, 250, 0x8000FA0C, 0x00000000 },
   337 	{ &GUID_Key, 251, 0x8000FB0C, 0x00000000 },
   338 	{ &GUID_Key, 252, 0x8000FC0C, 0x00000000 },
   339 	{ &GUID_Key, 253, 0x8000FD0C, 0x00000000 },
   340 	{ &GUID_Key, 254, 0x8000FE0C, 0x00000000 },
   341 	{ &GUID_Key, 255, 0x8000FF0C, 0x00000000 },
   342 };
   343 
   344 const DIDATAFORMAT c_dfDIKeyboard = { 24, 16, 0x00000002, 256, 256, KBD_fmt };
   345 
   346 
   347 /* Mouse */
   348 
   349 static DIOBJECTDATAFORMAT PTR_fmt[] = {
   350 	{ &GUID_XAxis, 0, 0x00FFFF03, 0x00000000 },
   351 	{ &GUID_YAxis, 4, 0x00FFFF03, 0x00000000 },
   352 	{ &GUID_ZAxis, 8, 0x80FFFF03, 0x00000000 },
   353 	{ NULL, 12, 0x00FFFF0C, 0x00000000 },
   354 	{ NULL, 13, 0x00FFFF0C, 0x00000000 },
   355 	{ NULL, 14, 0x80FFFF0C, 0x00000000 },
   356 	{ NULL, 15, 0x80FFFF0C, 0x00000000 },
   357 };
   358 
   359 const DIDATAFORMAT c_dfDIMouse = { 24, 16, 0x00000002, 16, 7, PTR_fmt };
   360 
   361 
   362 /* Joystick */
   363 
   364 static DIOBJECTDATAFORMAT JOY_fmt[] = {
   365 	{ &GUID_XAxis, 0, 0x80FFFF03, 0x00000100 },
   366 	{ &GUID_YAxis, 4, 0x80FFFF03, 0x00000100 },
   367 	{ &GUID_ZAxis, 8, 0x80FFFF03, 0x00000100 },
   368 	{ &GUID_RxAxis, 12, 0x80FFFF03, 0x00000100 },
   369 	{ &GUID_RyAxis, 16, 0x80FFFF03, 0x00000100 },
   370 	{ &GUID_RzAxis, 20, 0x80FFFF03, 0x00000100 },
   371 	{ &GUID_Slider, 24, 0x80FFFF03, 0x00000100 },
   372 	{ &GUID_Slider, 28, 0x80FFFF03, 0x00000100 },
   373 	{ &GUID_POV, 32, 0x80FFFF10, 0x00000000 },
   374 	{ &GUID_POV, 36, 0x80FFFF10, 0x00000000 },
   375 	{ &GUID_POV, 40, 0x80FFFF10, 0x00000000 },
   376 	{ &GUID_POV, 44, 0x80FFFF10, 0x00000000 },
   377 	{ NULL, 48, 0x80FFFF0C, 0x00000000 },
   378 	{ NULL, 49, 0x80FFFF0C, 0x00000000 },
   379 	{ NULL, 50, 0x80FFFF0C, 0x00000000 },
   380 	{ NULL, 51, 0x80FFFF0C, 0x00000000 },
   381 	{ NULL, 52, 0x80FFFF0C, 0x00000000 },
   382 	{ NULL, 53, 0x80FFFF0C, 0x00000000 },
   383 	{ NULL, 54, 0x80FFFF0C, 0x00000000 },
   384 	{ NULL, 55, 0x80FFFF0C, 0x00000000 },
   385 	{ NULL, 56, 0x80FFFF0C, 0x00000000 },
   386 	{ NULL, 57, 0x80FFFF0C, 0x00000000 },
   387 	{ NULL, 58, 0x80FFFF0C, 0x00000000 },
   388 	{ NULL, 59, 0x80FFFF0C, 0x00000000 },
   389 	{ NULL, 60, 0x80FFFF0C, 0x00000000 },
   390 	{ NULL, 61, 0x80FFFF0C, 0x00000000 },
   391 	{ NULL, 62, 0x80FFFF0C, 0x00000000 },
   392 	{ NULL, 63, 0x80FFFF0C, 0x00000000 },
   393 	{ NULL, 64, 0x80FFFF0C, 0x00000000 },
   394 	{ NULL, 65, 0x80FFFF0C, 0x00000000 },
   395 	{ NULL, 66, 0x80FFFF0C, 0x00000000 },
   396 	{ NULL, 67, 0x80FFFF0C, 0x00000000 },
   397 	{ NULL, 68, 0x80FFFF0C, 0x00000000 },
   398 	{ NULL, 69, 0x80FFFF0C, 0x00000000 },
   399 	{ NULL, 70, 0x80FFFF0C, 0x00000000 },
   400 	{ NULL, 71, 0x80FFFF0C, 0x00000000 },
   401 	{ NULL, 72, 0x80FFFF0C, 0x00000000 },
   402 	{ NULL, 73, 0x80FFFF0C, 0x00000000 },
   403 	{ NULL, 74, 0x80FFFF0C, 0x00000000 },
   404 	{ NULL, 75, 0x80FFFF0C, 0x00000000 },
   405 	{ NULL, 76, 0x80FFFF0C, 0x00000000 },
   406 	{ NULL, 77, 0x80FFFF0C, 0x00000000 },
   407 	{ NULL, 78, 0x80FFFF0C, 0x00000000 },
   408 	{ NULL, 79, 0x80FFFF0C, 0x00000000 },
   409 };
   410 
   411 const DIDATAFORMAT c_dfDIJoystick = { 24, 16, 0x00000001, 80, 44, JOY_fmt };
   412 
   413 
   414 /* Initialization/Query functions */
   415 static int DX5_VideoInit(_THIS, SDL_PixelFormat *vformat);
   416 static SDL_Rect **DX5_ListModes(_THIS, SDL_PixelFormat *format, Uint32 flags);
   417 static SDL_Surface *DX5_SetVideoMode(_THIS, SDL_Surface *current, int width, int height, int bpp, Uint32 flags);
   418 static int DX5_SetColors(_THIS, int firstcolor, int ncolors,
   419 			 SDL_Color *colors);
   420 static int DX5_SetGammaRamp(_THIS, Uint16 *ramp);
   421 static int DX5_GetGammaRamp(_THIS, Uint16 *ramp);
   422 static void DX5_VideoQuit(_THIS);
   423 
   424 /* Hardware surface functions */
   425 static int DX5_AllocHWSurface(_THIS, SDL_Surface *surface);
   426 static int DX5_CheckHWBlit(_THIS, SDL_Surface *src, SDL_Surface *dst);
   427 static int DX5_FillHWRect(_THIS, SDL_Surface *dst, SDL_Rect *dstrect, Uint32 color);
   428 static int DX5_SetHWColorKey(_THIS, SDL_Surface *surface, Uint32 key);
   429 static int DX5_SetHWAlpha(_THIS, SDL_Surface *surface, Uint8 alpha);
   430 static int DX5_LockHWSurface(_THIS, SDL_Surface *surface);
   431 static void DX5_UnlockHWSurface(_THIS, SDL_Surface *surface);
   432 static int DX5_FlipHWSurface(_THIS, SDL_Surface *surface);
   433 static void DX5_FreeHWSurface(_THIS, SDL_Surface *surface);
   434 
   435 static int DX5_AllocDDSurface(_THIS, SDL_Surface *surface, 
   436 				LPDIRECTDRAWSURFACE3 requested, Uint32 flag);
   437 
   438 /* Windows message handling functions */
   439 static void DX5_RealizePalette(_THIS);
   440 static void DX5_PaletteChanged(_THIS, HWND window);
   441 static void DX5_WinPAINT(_THIS, HDC hdc);
   442 
   443 /* WinDIB driver functions for manipulating gamma ramps */
   444 extern int DIB_SetGammaRamp(_THIS, Uint16 *ramp);
   445 extern int DIB_GetGammaRamp(_THIS, Uint16 *ramp);
   446 extern void DIB_QuitGamma(_THIS);
   447 
   448 /* DX5 driver bootstrap functions */
   449 
   450 static int DX5_Available(void)
   451 {
   452 	HINSTANCE DInputDLL;
   453 	HINSTANCE DDrawDLL;
   454 	int dinput_ok;
   455 	int ddraw_ok;
   456 
   457 	/* Version check DINPUT.DLL and DDRAW.DLL (Is DirectX okay?) */
   458 	dinput_ok = 0;
   459 	DInputDLL = LoadLibrary(TEXT("DINPUT.DLL"));
   460 	if ( DInputDLL != NULL ) {
   461 		dinput_ok = 1;
   462 	  	FreeLibrary(DInputDLL);
   463 	}
   464 	ddraw_ok = 0;
   465 	DDrawDLL = LoadLibrary(TEXT("DDRAW.DLL"));
   466 	if ( DDrawDLL != NULL ) {
   467 	  HRESULT (WINAPI *DDrawCreate)(GUID *,LPDIRECTDRAW *,IUnknown *);
   468 	  LPDIRECTDRAW DDraw;
   469 
   470 	  /* Try to create a valid DirectDraw object */
   471 	  DDrawCreate = (void *)GetProcAddress(DDrawDLL, TEXT("DirectDrawCreate"));
   472 	  if ( (DDrawCreate != NULL)
   473 			&& !FAILED(DDrawCreate(NULL, &DDraw, NULL)) ) {
   474 	    if ( !FAILED(IDirectDraw_SetCooperativeLevel(DDraw,
   475 							NULL, DDSCL_NORMAL)) ) {
   476 	      DDSURFACEDESC desc;
   477 	      LPDIRECTDRAWSURFACE  DDrawSurf;
   478 	      LPDIRECTDRAWSURFACE3 DDrawSurf3;
   479 
   480 	      /* Try to create a DirectDrawSurface3 object */
   481 	      memset(&desc, 0, sizeof(desc));
   482 	      desc.dwSize = sizeof(desc);
   483 	      desc.dwFlags = DDSD_CAPS;
   484 	      desc.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE|DDSCAPS_VIDEOMEMORY;
   485 	      if ( !FAILED(IDirectDraw_CreateSurface(DDraw, &desc,
   486 							&DDrawSurf, NULL)) ) {
   487 	        if ( !FAILED(IDirectDrawSurface_QueryInterface(DDrawSurf,
   488 			&IID_IDirectDrawSurface3, (LPVOID *)&DDrawSurf3)) ) {
   489 	          /* Yay! */
   490 		  ddraw_ok = 1;
   491 
   492 	          /* Clean up.. */
   493 	          IDirectDrawSurface3_Release(DDrawSurf3);
   494 	        }
   495 	        IDirectDrawSurface_Release(DDrawSurf);
   496 	      }
   497 	    }
   498 	    IDirectDraw_Release(DDraw);
   499 	  }
   500 	  FreeLibrary(DDrawDLL);
   501 	}
   502 	return(dinput_ok && ddraw_ok);
   503 }
   504 
   505 /* Functions for loading the DirectX functions dynamically */
   506 static HINSTANCE DDrawDLL = NULL;
   507 static HINSTANCE DInputDLL = NULL;
   508 
   509 static void DX5_Unload(void)
   510 {
   511 	if ( DDrawDLL != NULL ) {
   512 		FreeLibrary(DDrawDLL);
   513 		DDrawCreate = NULL;
   514 		DDrawDLL = NULL;
   515 	}
   516 	if ( DInputDLL != NULL ) {
   517 		FreeLibrary(DInputDLL);
   518 		DInputCreate = NULL;
   519 		DInputDLL = NULL;
   520 	}
   521 }
   522 static int DX5_Load(void)
   523 {
   524 	int status;
   525 
   526 	DX5_Unload();
   527 	DDrawDLL = LoadLibrary(TEXT("DDRAW.DLL"));
   528 	if ( DDrawDLL != NULL ) {
   529 		DDrawCreate = (void *)GetProcAddress(DDrawDLL,
   530 					TEXT("DirectDrawCreate"));
   531 	}
   532 	DInputDLL = LoadLibrary(TEXT("DINPUT.DLL"));
   533 	if ( DInputDLL != NULL ) {
   534 		DInputCreate = (void *)GetProcAddress(DInputDLL,
   535 					TEXT("DirectInputCreateA"));
   536 	}
   537 	if ( DDrawDLL && DDrawCreate && DInputDLL && DInputCreate ) {
   538 		status = 0;
   539 	} else {
   540 		DX5_Unload();
   541 		status = -1;
   542 	}
   543 	return status;
   544 }
   545 
   546 static void DX5_DeleteDevice(SDL_VideoDevice *this)
   547 {
   548 	/* Free DirectDraw object */
   549 	if ( ddraw2 != NULL ) {
   550 		IDirectDraw2_Release(ddraw2);
   551 	}
   552 	DX5_Unload();
   553 	if ( this ) {
   554 		if ( this->hidden ) {
   555 			free(this->hidden);
   556 		}
   557 		if ( this->gl_data ) {
   558 			free(this->gl_data);
   559 		}
   560 		free(this);
   561 	}
   562 }
   563 
   564 static SDL_VideoDevice *DX5_CreateDevice(int devindex)
   565 {
   566 	SDL_VideoDevice *device;
   567 
   568 	/* Load DirectX */
   569 	if ( DX5_Load() < 0 ) {
   570 		return(NULL);
   571 	}
   572 
   573 	/* Initialize all variables that we clean on shutdown */
   574 	device = (SDL_VideoDevice *)malloc(sizeof(SDL_VideoDevice));
   575 	if ( device ) {
   576 		memset(device, 0, (sizeof *device));
   577 		device->hidden = (struct SDL_PrivateVideoData *)
   578 				malloc((sizeof *device->hidden));
   579 		device->gl_data = (struct SDL_PrivateGLData *)
   580 				malloc((sizeof *device->gl_data));
   581 	}
   582 	if ( (device == NULL) || (device->hidden == NULL) ||
   583 		                 (device->gl_data == NULL) ) {
   584 		SDL_OutOfMemory();
   585 		DX5_DeleteDevice(device);
   586 		return(NULL);
   587 	}
   588 	memset(device->hidden, 0, (sizeof *device->hidden));
   589 	memset(device->gl_data, 0, (sizeof *device->gl_data));
   590 
   591 	/* Set the function pointers */
   592 	device->VideoInit = DX5_VideoInit;
   593 	device->ListModes = DX5_ListModes;
   594 	device->SetVideoMode = DX5_SetVideoMode;
   595 	device->UpdateMouse = WIN_UpdateMouse;
   596 	device->CreateYUVOverlay = DX5_CreateYUVOverlay;
   597 	device->SetColors = DX5_SetColors;
   598 	device->UpdateRects = NULL;
   599 	device->VideoQuit = DX5_VideoQuit;
   600 	device->AllocHWSurface = DX5_AllocHWSurface;
   601 	device->CheckHWBlit = DX5_CheckHWBlit;
   602 	device->FillHWRect = DX5_FillHWRect;
   603 	device->SetHWColorKey = DX5_SetHWColorKey;
   604 	device->SetHWAlpha = DX5_SetHWAlpha;
   605 	device->LockHWSurface = DX5_LockHWSurface;
   606 	device->UnlockHWSurface = DX5_UnlockHWSurface;
   607 	device->FlipHWSurface = DX5_FlipHWSurface;
   608 	device->FreeHWSurface = DX5_FreeHWSurface;
   609 	device->SetGammaRamp = DX5_SetGammaRamp;
   610 	device->GetGammaRamp = DX5_GetGammaRamp;
   611 #ifdef HAVE_OPENGL
   612 	device->GL_LoadLibrary = WIN_GL_LoadLibrary;
   613 	device->GL_GetProcAddress = WIN_GL_GetProcAddress;
   614 	device->GL_GetAttribute = WIN_GL_GetAttribute;
   615 	device->GL_MakeCurrent = WIN_GL_MakeCurrent;
   616 	device->GL_SwapBuffers = WIN_GL_SwapBuffers;
   617 #endif
   618 	device->SetCaption = WIN_SetWMCaption;
   619 	device->SetIcon = WIN_SetWMIcon;
   620 	device->IconifyWindow = WIN_IconifyWindow;
   621 	device->GrabInput = WIN_GrabInput;
   622 	device->GetWMInfo = WIN_GetWMInfo;
   623 	device->FreeWMCursor = WIN_FreeWMCursor;
   624 	device->CreateWMCursor = WIN_CreateWMCursor;
   625 	device->ShowWMCursor = WIN_ShowWMCursor;
   626 	device->WarpWMCursor = WIN_WarpWMCursor;
   627 	device->CheckMouseMode = WIN_CheckMouseMode;
   628 	device->InitOSKeymap = DX5_InitOSKeymap;
   629 	device->PumpEvents = DX5_PumpEvents;
   630 
   631 	/* Set up the windows message handling functions */
   632 	WIN_RealizePalette = DX5_RealizePalette;
   633 	WIN_PaletteChanged = DX5_PaletteChanged;
   634 	WIN_WinPAINT = DX5_WinPAINT;
   635 	HandleMessage = DX5_HandleMessage;
   636 
   637 	device->free = DX5_DeleteDevice;
   638 
   639 	/* We're finally ready */
   640 	return device;
   641 }
   642 
   643 VideoBootStrap DIRECTX_bootstrap = {
   644 	"directx", "Win95/98/2000 DirectX",
   645 	DX5_Available, DX5_CreateDevice
   646 };
   647 
   648 static HRESULT WINAPI EnumModes2(DDSURFACEDESC *desc, VOID *udata)
   649 {
   650 	SDL_VideoDevice *this = (SDL_VideoDevice *)udata;
   651 	struct DX5EnumRect *enumrect;
   652 #if defined(NONAMELESSUNION)
   653 	int bpp = desc->ddpfPixelFormat.u1.dwRGBBitCount;
   654 	int refreshRate = desc->u2.dwRefreshRate;
   655 #else
   656 	int bpp = desc->ddpfPixelFormat.dwRGBBitCount;
   657 	int refreshRate = desc->dwRefreshRate;
   658 #endif
   659 	int maxRefreshRate;
   660 
   661 	if ( desc->dwWidth <= SDL_desktop_mode.dmPelsWidth &&
   662 	     desc->dwHeight <= SDL_desktop_mode.dmPelsHeight ) {
   663 		maxRefreshRate = SDL_desktop_mode.dmDisplayFrequency;
   664 	} else {
   665 		maxRefreshRate = 85;	/* safe value? */
   666 	}
   667 
   668 	switch (bpp)  {
   669 		case 8:
   670 		case 16:
   671 		case 24:
   672 		case 32:
   673 			bpp /= 8; --bpp;
   674 			if ( enumlists[bpp] &&
   675 			     enumlists[bpp]->r.w == (Uint16)desc->dwWidth &&
   676 			     enumlists[bpp]->r.h == (Uint16)desc->dwHeight ) {
   677 				if ( refreshRate > enumlists[bpp]->refreshRate &&
   678 				     refreshRate <= maxRefreshRate ) {
   679 					enumlists[bpp]->refreshRate = refreshRate;
   680 #ifdef DDRAW_DEBUG
   681  fprintf(stderr, "New refresh rate for %d bpp: %dx%d at %d Hz\n", (bpp+1)*8, (int)desc->dwWidth, (int)desc->dwHeight, refreshRate);
   682 #endif
   683 				}
   684 				break;
   685 			}
   686 			++SDL_nummodes[bpp];
   687 			enumrect = (struct DX5EnumRect*)malloc(sizeof(struct DX5EnumRect));
   688 			if ( !enumrect ) {
   689 				SDL_OutOfMemory();
   690 				return(DDENUMRET_CANCEL);
   691 			}
   692 			enumrect->refreshRate = refreshRate;
   693 			enumrect->r.x = 0;
   694 			enumrect->r.y = 0;
   695 			enumrect->r.w = (Uint16)desc->dwWidth;
   696 			enumrect->r.h = (Uint16)desc->dwHeight;
   697 			enumrect->next = enumlists[bpp];
   698 			enumlists[bpp] = enumrect;
   699 #ifdef DDRAW_DEBUG
   700  fprintf(stderr, "New mode for %d bpp: %dx%d at %d Hz\n", (bpp+1)*8, (int)desc->dwWidth, (int)desc->dwHeight, refreshRate);
   701 #endif
   702 			break;
   703 	}
   704 
   705 	return(DDENUMRET_OK);
   706 }
   707 
   708 void SetDDerror(const char *function, int code)
   709 {
   710 	static char *error;
   711 	static char  errbuf[1024];
   712 
   713 	errbuf[0] = 0;
   714 	switch (code) {
   715 		case DDERR_GENERIC:
   716 			error = "Undefined error!";
   717 			break;
   718 		case DDERR_EXCEPTION:
   719 			error = "Exception encountered";
   720 			break;
   721 		case DDERR_INVALIDOBJECT:
   722 			error = "Invalid object";
   723 			break;
   724 		case DDERR_INVALIDPARAMS:
   725 			error = "Invalid parameters";
   726 			break;
   727 		case DDERR_NOTFOUND:
   728 			error = "Object not found";
   729 			break;
   730 		case DDERR_INVALIDRECT:
   731 			error = "Invalid rectangle";
   732 			break;
   733 		case DDERR_INVALIDCAPS:
   734 			error = "Invalid caps member";
   735 			break;
   736 		case DDERR_INVALIDPIXELFORMAT:
   737 			error = "Invalid pixel format";
   738 			break;
   739 		case DDERR_OUTOFMEMORY:
   740 			error = "Out of memory";
   741 			break;
   742 		case DDERR_OUTOFVIDEOMEMORY:
   743 			error = "Out of video memory";
   744 			break;
   745 		case DDERR_SURFACEBUSY:
   746 			error = "Surface busy";
   747 			break;
   748 		case DDERR_SURFACELOST:
   749 			error = "Surface was lost";
   750 			break;
   751 		case DDERR_WASSTILLDRAWING:
   752 			error = "DirectDraw is still drawing";
   753 			break;
   754 		case DDERR_INVALIDSURFACETYPE:
   755 			error = "Invalid surface type";
   756 			break;
   757 		case DDERR_NOEXCLUSIVEMODE:
   758 			error = "Not in exclusive access mode";
   759 			break;
   760 		case DDERR_NOPALETTEATTACHED:
   761 			error = "No palette attached";
   762 			break;
   763 		case DDERR_NOPALETTEHW:
   764 			error = "No palette hardware";
   765 			break;
   766 		case DDERR_NOT8BITCOLOR:
   767 			error = "Not 8-bit color";
   768 			break;
   769 		case DDERR_EXCLUSIVEMODEALREADYSET:
   770 			error = "Exclusive mode was already set";
   771 			break;
   772 		case DDERR_HWNDALREADYSET:
   773 			error = "Window handle already set";
   774 			break;
   775 		case DDERR_HWNDSUBCLASSED:
   776 			error = "Window handle is subclassed";
   777 			break;
   778 		case DDERR_NOBLTHW:
   779 			error = "No blit hardware";
   780 			break;
   781 		case DDERR_IMPLICITLYCREATED:
   782 			error = "Surface was implicitly created";
   783 			break;
   784 		case DDERR_INCOMPATIBLEPRIMARY:
   785 			error = "Incompatible primary surface";
   786 			break;
   787 		case DDERR_NOCOOPERATIVELEVELSET:
   788 			error = "No cooperative level set";
   789 			break;
   790 		case DDERR_NODIRECTDRAWHW:
   791 			error = "No DirectDraw hardware";
   792 			break;
   793 		case DDERR_NOEMULATION:
   794 			error = "No emulation available";
   795 			break;
   796 		case DDERR_NOFLIPHW:
   797 			error = "No flip hardware";
   798 			break;
   799 		case DDERR_NOTFLIPPABLE:
   800 			error = "Surface not flippable";
   801 			break;
   802 		case DDERR_PRIMARYSURFACEALREADYEXISTS:
   803 			error = "Primary surface already exists";
   804 			break;
   805 		case DDERR_UNSUPPORTEDMODE:
   806 			error = "Unsupported mode";
   807 			break;
   808 		case DDERR_WRONGMODE:
   809 			error = "Surface created in different mode";
   810 			break;
   811 		case DDERR_UNSUPPORTED:
   812 			error = "Operation not supported";
   813 			break;
   814 		case E_NOINTERFACE:
   815 			error = "Interface not present";
   816 			break;
   817 		default:
   818 			sprintf(errbuf, "%s: Unknown DirectDraw error: 0x%x",
   819 								function, code);
   820 			break;
   821 	}
   822 	if ( ! errbuf[0] ) {
   823 		sprintf(errbuf, "%s: %s", function, error);
   824 	}
   825 	SDL_SetError("%s", errbuf);
   826 	return;
   827 }
   828 
   829 
   830 static int DX5_UpdateVideoInfo(_THIS)
   831 {
   832 	/* This needs to be DDCAPS_DX5 for the DirectDraw2 interface */
   833 #if DIRECTDRAW_VERSION <= 0x300
   834 #error Your version of DirectX must be greater than or equal to 5.0
   835 #endif
   836 #ifndef IDirectDrawGammaControl_SetGammaRamp
   837 	/*if gamma is undefined then we really have directx <= 0x500*/
   838 	DDCAPS DDCaps;
   839 #else
   840 	DDCAPS_DX5 DDCaps;
   841 #endif
   842 	HRESULT result;
   843 
   844 	/* Fill in our hardware acceleration capabilities */
   845 	memset(&DDCaps, 0, sizeof(DDCaps));
   846 	DDCaps.dwSize = sizeof(DDCaps);
   847 	result = IDirectDraw2_GetCaps(ddraw2, (DDCAPS *)&DDCaps, NULL);
   848 	if ( result != DD_OK ) {
   849 		SetDDerror("DirectDraw2::GetCaps", result);
   850 		return(-1);
   851 	}
   852 	this->info.hw_available = 1;
   853 	if ( (DDCaps.dwCaps & DDCAPS_BLT) == DDCAPS_BLT ) {
   854 		this->info.blit_hw = 1;
   855 	}
   856 	if ( ((DDCaps.dwCaps & DDCAPS_COLORKEY) == DDCAPS_COLORKEY) &&
   857 	     ((DDCaps.dwCKeyCaps & DDCKEYCAPS_SRCBLT) == DDCKEYCAPS_SRCBLT) ) {
   858 		this->info.blit_hw_CC = 1;
   859 	}
   860 	if ( (DDCaps.dwCaps & DDCAPS_ALPHA) == DDCAPS_ALPHA ) {
   861 		/* This is only for alpha channel, and DirectX 6
   862 		   doesn't support 2D alpha blits yet, so set it 0
   863 		 */
   864 		this->info.blit_hw_A = 0;
   865 	}
   866 	if ( (DDCaps.dwCaps & DDCAPS_CANBLTSYSMEM) == DDCAPS_CANBLTSYSMEM ) {
   867 		this->info.blit_sw = 1;
   868 		/* This isn't necessarily true, but the HEL will cover us */
   869 		this->info.blit_sw_CC = this->info.blit_hw_CC;
   870 		this->info.blit_sw_A = this->info.blit_hw_A;
   871 	}
   872 	if ( (DDCaps.dwCaps & DDCAPS_BLTCOLORFILL) == DDCAPS_BLTCOLORFILL ) {
   873 		this->info.blit_fill = 1;
   874 	}
   875 
   876 	/* Find out how much video memory is available */
   877 	{ DDSCAPS ddsCaps;
   878 	  DWORD total_mem;
   879 		ddsCaps.dwCaps = DDSCAPS_VIDEOMEMORY;
   880 		result = IDirectDraw2_GetAvailableVidMem(ddraw2,
   881 						&ddsCaps, &total_mem, NULL);
   882 		if ( result != DD_OK ) {
   883 			total_mem = DDCaps.dwVidMemTotal; 
   884 		}
   885 		this->info.video_mem = total_mem/1024;
   886 	}
   887 	return(0);
   888 }
   889 
   890 int DX5_VideoInit(_THIS, SDL_PixelFormat *vformat)
   891 {
   892 	HRESULT result;
   893 	LPDIRECTDRAW ddraw;
   894 	int i, j;
   895 	HDC hdc;
   896 
   897 	/* Intialize everything */
   898 	ddraw2 = NULL;
   899 	SDL_primary = NULL;
   900 	SDL_clipper = NULL;
   901 	SDL_palette = NULL;
   902 	for ( i=0; i<NUM_MODELISTS; ++i ) {
   903 		SDL_nummodes[i] = 0;
   904 		SDL_modelist[i] = NULL;
   905 		SDL_modeindex[i] = 0;
   906 	}
   907 	colorchange_expected = 0;
   908 
   909 	/* Create the window */
   910 	if ( DX5_CreateWindow(this) < 0 ) {
   911 		return(-1);
   912 	}
   913 #ifndef DISABLE_AUDIO
   914 	DX5_SoundFocus(SDL_Window);
   915 #endif
   916 
   917 	/* Create the DirectDraw object */
   918 	result = DDrawCreate(NULL, &ddraw, NULL);
   919 	if ( result != DD_OK ) {
   920 		SetDDerror("DirectDrawCreate", result);
   921 		return(-1);
   922 	}
   923 	result = IDirectDraw_QueryInterface(ddraw, &IID_IDirectDraw2,
   924 							(LPVOID *)&ddraw2);
   925 	IDirectDraw_Release(ddraw);
   926 	if ( result != DD_OK ) {
   927 		SetDDerror("DirectDraw::QueryInterface", result);
   928 		return(-1);
   929 	}
   930 
   931 	/* Determine the screen depth */
   932 	hdc = GetDC(SDL_Window);
   933 	vformat->BitsPerPixel = GetDeviceCaps(hdc,PLANES) *
   934 					GetDeviceCaps(hdc,BITSPIXEL);
   935 	ReleaseDC(SDL_Window, hdc);
   936 
   937 #ifndef NO_CHANGEDISPLAYSETTINGS
   938 	/* Query for the desktop resolution */
   939 	EnumDisplaySettings(NULL, ENUM_CURRENT_SETTINGS, &SDL_desktop_mode);
   940 #endif
   941 
   942 	/* Enumerate the available fullscreen modes */
   943 	for ( i=0; i<NUM_MODELISTS; ++i )
   944 		enumlists[i] = NULL;
   945 
   946 	result = IDirectDraw2_EnumDisplayModes(ddraw2,DDEDM_REFRESHRATES,NULL,this,EnumModes2);
   947 	if ( result != DD_OK ) {
   948 		SetDDerror("DirectDraw2::EnumDisplayModes", result);
   949 		return(-1);
   950 	}
   951 	for ( i=0; i<NUM_MODELISTS; ++i ) {
   952 		struct DX5EnumRect *rect;
   953 		SDL_modelist[i] = (SDL_Rect **)
   954 				malloc((SDL_nummodes[i]+1)*sizeof(SDL_Rect *));
   955 		if ( SDL_modelist[i] == NULL ) {
   956 			SDL_OutOfMemory();
   957 			return(-1);
   958 		}
   959 		for ( j = 0, rect = enumlists[i]; rect; ++j, rect = rect->next ) {
   960 			SDL_modelist[i][j] = &rect->r;
   961 		}
   962 		SDL_modelist[i][j] = NULL;
   963 	}
   964 	
   965 	/* Fill in some window manager capabilities */
   966 	this->info.wm_available = 1;
   967 
   968 	/* Fill in the video hardware capabilities */
   969 	DX5_UpdateVideoInfo(this);
   970 
   971 	return(0);
   972 }
   973 
   974 SDL_Rect **DX5_ListModes(_THIS, SDL_PixelFormat *format, Uint32 flags)
   975 {
   976 	int bpp;
   977 
   978 	bpp = format->BitsPerPixel;
   979 	if ( (flags & SDL_FULLSCREEN) == SDL_FULLSCREEN ) {
   980 		/* FIXME:  No support for 1 bpp or 4 bpp formats */
   981 		switch (bpp) {  /* Does windows support other BPP? */
   982 			case 8:
   983 			case 16:
   984 			case 24:
   985 			case 32:
   986 				bpp = (bpp/8)-1;
   987 				if ( SDL_nummodes[bpp] > 0 )
   988 					return(SDL_modelist[bpp]);
   989 				/* Fall through */
   990 			default:
   991 				return((SDL_Rect **)0);
   992 		}
   993 	} else {
   994 		if ( this->screen->format->BitsPerPixel == bpp ) {
   995 			return((SDL_Rect **)-1);
   996 		} else {
   997 			return((SDL_Rect **)0);
   998 		}
   999 	}
  1000 }
  1001 
  1002 /* Various screen update functions available */
  1003 static void DX5_WindowUpdate(_THIS, int numrects, SDL_Rect *rects);
  1004 static void DX5_DirectUpdate(_THIS, int numrects, SDL_Rect *rects);
  1005 
  1006 SDL_Surface *DX5_SetVideoMode(_THIS, SDL_Surface *current,
  1007 				int width, int height, int bpp, Uint32 flags)
  1008 {
  1009 	SDL_Surface *video;
  1010 	HRESULT result;
  1011 	DWORD sharemode;
  1012 	DWORD style;
  1013 	const DWORD directstyle =
  1014 			(WS_POPUP);
  1015 	const DWORD windowstyle = 
  1016 			(WS_OVERLAPPED|WS_CAPTION|WS_SYSMENU|WS_MINIMIZEBOX);
  1017 	const DWORD resizestyle =
  1018 			(WS_THICKFRAME|WS_MAXIMIZEBOX);
  1019 	DDSURFACEDESC ddsd;
  1020 	LPDIRECTDRAWSURFACE  dd_surface1;
  1021 	LPDIRECTDRAWSURFACE3 dd_surface3;
  1022 
  1023 	SDL_resizing = 1;
  1024 #ifdef DDRAW_DEBUG
  1025  fprintf(stderr, "Setting %dx%dx%d video mode\n", width, height, bpp);
  1026 #endif
  1027 	/* Clean up any previous DirectDraw surfaces */
  1028 	if ( current->hwdata ) {
  1029 		this->FreeHWSurface(this, current);
  1030 		current->hwdata = NULL;
  1031 	}
  1032 	if ( SDL_primary != NULL ) {
  1033 		IDirectDrawSurface3_Release(SDL_primary);
  1034 		SDL_primary = NULL;
  1035 	}
  1036 
  1037 #ifndef NO_CHANGEDISPLAYSETTINGS
  1038 	/* Unset any previous OpenGL fullscreen mode */
  1039 	if ( (current->flags & (SDL_OPENGL|SDL_FULLSCREEN)) ==
  1040 	                       (SDL_OPENGL|SDL_FULLSCREEN) ) {
  1041 		ChangeDisplaySettings(NULL, 0);
  1042 	}
  1043 #endif
  1044 
  1045 	/* Clean up any GL context that may be hanging around */
  1046 	if ( current->flags & SDL_OPENGL ) {
  1047 		WIN_GL_ShutDown(this);
  1048 	}
  1049 
  1050 	/* If we are setting a GL mode, use GDI, not DirectX (yuck) */
  1051 	if ( flags & SDL_OPENGL ) {
  1052 		Uint32 Rmask, Gmask, Bmask;
  1053 
  1054 		/* Recalculate the bitmasks if necessary */
  1055 		if ( bpp == current->format->BitsPerPixel ) {
  1056 			video = current;
  1057 		} else {
  1058 			switch (bpp) {
  1059 			    case 15:
  1060 			    case 16:
  1061 				if ( 0 /*DIB_SussScreenDepth() == 15*/ ) {
  1062 					/* 5-5-5 */
  1063 					Rmask = 0x00007c00;
  1064 					Gmask = 0x000003e0;
  1065 					Bmask = 0x0000001f;
  1066 				} else {
  1067 					/* 5-6-5 */
  1068 					Rmask = 0x0000f800;
  1069 					Gmask = 0x000007e0;
  1070 					Bmask = 0x0000001f;
  1071 				}
  1072 				break;
  1073 			    case 24:
  1074 			    case 32:
  1075 				/* GDI defined as 8-8-8 */
  1076 				Rmask = 0x00ff0000;
  1077 				Gmask = 0x0000ff00;
  1078 				Bmask = 0x000000ff;
  1079 				break;
  1080 			    default:
  1081 				Rmask = 0x00000000;
  1082 				Gmask = 0x00000000;
  1083 				Bmask = 0x00000000;
  1084 				break;
  1085 			}
  1086 			video = SDL_CreateRGBSurface(SDL_SWSURFACE, 0, 0, bpp,
  1087 			                             Rmask, Gmask, Bmask, 0);
  1088 			if ( video == NULL ) {
  1089 				SDL_OutOfMemory();
  1090 				return(NULL);
  1091 			}
  1092 		}
  1093 
  1094 		/* Fill in part of the video surface */
  1095 		video->flags = 0;	/* Clear flags */
  1096 		video->w = width;
  1097 		video->h = height;
  1098 		video->pitch = SDL_CalculatePitch(video);
  1099 
  1100 #ifndef NO_CHANGEDISPLAYSETTINGS
  1101 		/* Set fullscreen mode if appropriate.
  1102 		   Ugh, since our list of valid video modes comes from
  1103 		   the DirectX driver, we may not actually be able to
  1104 		   change to the desired resolution here.
  1105 		   FIXME: Should we do a closest match?
  1106 		 */
  1107 		if ( (flags & SDL_FULLSCREEN) == SDL_FULLSCREEN ) {
  1108 			DEVMODE settings;
  1109 			BOOL changed;
  1110 
  1111 			memset(&settings, 0, sizeof(DEVMODE));
  1112 			settings.dmSize = sizeof(DEVMODE);
  1113 			settings.dmBitsPerPel = video->format->BitsPerPixel;
  1114 			settings.dmPelsWidth = width;
  1115 			settings.dmPelsHeight = height;
  1116 			settings.dmFields = DM_PELSWIDTH | DM_PELSHEIGHT | DM_BITSPERPEL;
  1117 			if ( width <= SDL_desktop_mode.dmPelsWidth && height <= SDL_desktop_mode.dmPelsHeight ) {
  1118 				settings.dmDisplayFrequency = SDL_desktop_mode.dmDisplayFrequency;
  1119 				settings.dmFields |= DM_DISPLAYFREQUENCY;
  1120 			}
  1121 			changed = (ChangeDisplaySettings(&settings, CDS_FULLSCREEN) == DISP_CHANGE_SUCCESSFUL);
  1122 			if ( ! changed && (settings.dmFields & DM_DISPLAYFREQUENCY) ) {
  1123 				settings.dmFields &= ~DM_DISPLAYFREQUENCY;
  1124 				changed = (ChangeDisplaySettings(&settings, CDS_FULLSCREEN) == DISP_CHANGE_SUCCESSFUL);
  1125 			}
  1126 			if ( changed ) {
  1127 				video->flags |= SDL_FULLSCREEN;
  1128 				SDL_fullscreen_mode = settings;
  1129 			}
  1130 		}
  1131 #endif /* !NO_CHANGEDISPLAYSETTINGS */
  1132 
  1133 		style = GetWindowLong(SDL_Window, GWL_STYLE);
  1134 		style &= ~(resizestyle|WS_MAXIMIZE);
  1135 		if ( video->flags & SDL_FULLSCREEN ) {
  1136 			style &= ~windowstyle;
  1137 			style |= directstyle;
  1138 		} else {
  1139 			if ( flags & SDL_NOFRAME ) {
  1140 				style &= ~windowstyle;
  1141 				style |= directstyle;
  1142 				video->flags |= SDL_NOFRAME;
  1143 			} else {
  1144 				style &= ~directstyle;
  1145 				style |= windowstyle;
  1146 				if ( flags & SDL_RESIZABLE ) {
  1147 					style |= resizestyle;
  1148 					video->flags |= SDL_RESIZABLE;
  1149 				}
  1150 			}
  1151 #if WS_MAXIMIZE
  1152 			if (IsZoomed(SDL_Window)) style |= WS_MAXIMIZE;
  1153 #endif
  1154 		}
  1155 
  1156 		/* DJM: Don't piss of anyone who has setup his own window */
  1157 		if ( !SDL_windowid )
  1158 			SetWindowLong(SDL_Window, GWL_STYLE, style);
  1159 
  1160 		/* Resize the window (copied from SDL WinDIB driver) */
  1161 		if ( !SDL_windowid && !IsZoomed(SDL_Window) ) {
  1162 			RECT bounds;
  1163 			int x, y;
  1164 			HWND top;
  1165 			UINT swp_flags;
  1166 			const char *window = NULL;
  1167 			const char *center = NULL;
  1168 
  1169 			if ( !SDL_windowX && !SDL_windowY ) {
  1170 				window = getenv("SDL_VIDEO_WINDOW_POS");
  1171 				center = getenv("SDL_VIDEO_CENTERED");
  1172 				if ( window ) {
  1173 					if ( sscanf(window, "%d,%d", &x, &y) == 2 ) {
  1174 						SDL_windowX = x;
  1175 						SDL_windowY = y;
  1176 					}
  1177 					if ( strcmp(window, "center") == 0 ) {
  1178 						center = window;
  1179 					}
  1180 				}
  1181 			}
  1182 			swp_flags = (SWP_NOCOPYBITS | SWP_SHOWWINDOW);
  1183 
  1184 			bounds.left = SDL_windowX;
  1185 			bounds.top = SDL_windowY;
  1186 			bounds.right = SDL_windowX+video->w;
  1187 			bounds.bottom = SDL_windowY+video->h;
  1188 			AdjustWindowRectEx(&bounds, GetWindowLong(SDL_Window, GWL_STYLE), FALSE, 0);
  1189 			width = bounds.right-bounds.left;
  1190 			height = bounds.bottom-bounds.top;
  1191 			if ( (flags & SDL_FULLSCREEN) ) {
  1192 				x = (GetSystemMetrics(SM_CXSCREEN)-width)/2;
  1193 				y = (GetSystemMetrics(SM_CYSCREEN)-height)/2;
  1194 			} else if ( center ) {
  1195 				x = (GetSystemMetrics(SM_CXSCREEN)-width)/2;
  1196 				y = (GetSystemMetrics(SM_CYSCREEN)-height)/2;
  1197 			} else if ( SDL_windowX || SDL_windowY || window ) {
  1198 				x = bounds.left;
  1199 				y = bounds.top;
  1200 			} else {
  1201 				x = y = -1;
  1202 				swp_flags |= SWP_NOMOVE;
  1203 			}
  1204 			if ( flags & SDL_FULLSCREEN ) {
  1205 				top = HWND_TOPMOST;
  1206 			} else {
  1207 				top = HWND_NOTOPMOST;
  1208 			}
  1209 			SetWindowPos(SDL_Window, top, x, y, width, height, swp_flags);
  1210 			if ( !(flags & SDL_FULLSCREEN) ) {
  1211 				SDL_windowX = SDL_bounds.left;
  1212 				SDL_windowY = SDL_bounds.top;
  1213 			}
  1214 			SetForegroundWindow(SDL_Window);
  1215 		}
  1216 		SDL_resizing = 0;
  1217 
  1218 		/* Set up for OpenGL */
  1219 		if ( WIN_GL_SetupWindow(this) < 0 ) {
  1220 			return(NULL);
  1221 		}
  1222 		video->flags |= SDL_OPENGL;
  1223 		return(video);
  1224 	}
  1225 
  1226 	/* Set the appropriate window style */
  1227 	style = GetWindowLong(SDL_Window, GWL_STYLE);
  1228 	style &= ~(resizestyle|WS_MAXIMIZE);
  1229 	if ( (flags & SDL_FULLSCREEN) == SDL_FULLSCREEN ) {
  1230 		style &= ~windowstyle;
  1231 		style |= directstyle;
  1232 	} else {
  1233 		if ( flags & SDL_NOFRAME ) {
  1234 			style &= ~windowstyle;
  1235 			style |= directstyle;
  1236 		} else {
  1237 			style &= ~directstyle;
  1238 			style |= windowstyle;
  1239 			if ( flags & SDL_RESIZABLE ) {
  1240 				style |= resizestyle;
  1241 			}
  1242 		}
  1243 #if WS_MAXIMIZE
  1244 		if (IsZoomed(SDL_Window)) style |= WS_MAXIMIZE;
  1245 #endif
  1246 	}
  1247 	/* DJM: Don't piss of anyone who has setup his own window */
  1248 	if ( !SDL_windowid )
  1249 		SetWindowLong(SDL_Window, GWL_STYLE, style);
  1250 
  1251 	/* Set DirectDraw sharing mode.. exclusive when fullscreen */
  1252 	if ( (flags & SDL_FULLSCREEN) == SDL_FULLSCREEN ) {
  1253 		sharemode = DDSCL_FULLSCREEN|DDSCL_EXCLUSIVE|DDSCL_ALLOWREBOOT;
  1254 	} else {
  1255 		sharemode = DDSCL_NORMAL;
  1256 	}
  1257 	result = IDirectDraw2_SetCooperativeLevel(ddraw2,SDL_Window,sharemode);
  1258 	if ( result != DD_OK ) {
  1259 		SetDDerror("DirectDraw2::SetCooperativeLevel", result);
  1260 		return(NULL);
  1261 	}
  1262 
  1263 	/* Set the display mode, if we are in fullscreen mode */
  1264 	if ( (flags & SDL_FULLSCREEN) == SDL_FULLSCREEN ) {
  1265 		RECT bounds;
  1266 		struct DX5EnumRect *rect;
  1267 		int maxRefreshRate;
  1268 
  1269 		/* Cover up desktop during mode change */
  1270 		bounds.left = 0;
  1271 		bounds.top = 0;
  1272 		bounds.right = GetSystemMetrics(SM_CXSCREEN);
  1273 		bounds.bottom = GetSystemMetrics(SM_CYSCREEN);
  1274 		AdjustWindowRectEx(&bounds, GetWindowLong(SDL_Window, GWL_STYLE), FALSE, 0);
  1275 		SetWindowPos(SDL_Window, HWND_TOPMOST,
  1276 			bounds.left, bounds.top, 
  1277 			bounds.right - bounds.left,
  1278 			bounds.bottom - bounds.top, SWP_NOCOPYBITS);
  1279 		ShowWindow(SDL_Window, SW_SHOW);
  1280 		while ( GetForegroundWindow() != SDL_Window ) {
  1281 			SetForegroundWindow(SDL_Window);
  1282 			SDL_Delay(100);
  1283 		}
  1284 
  1285 		/* find maximum monitor refresh rate for this resolution */
  1286 		/* Dmitry Yakimov ftech@tula.net */
  1287 		maxRefreshRate = 0; /* system default */
  1288 		for ( rect = enumlists[bpp / 8 - 1]; rect; rect = rect->next ) {
  1289 			if ( (width == rect->r.w) && (height == rect->r.h) ) {
  1290 				maxRefreshRate = rect->refreshRate;
  1291 				break;
  1292 			}
  1293 		}
  1294 #ifdef DDRAW_DEBUG
  1295  fprintf(stderr, "refresh rate = %d Hz\n", maxRefreshRate);
  1296 #endif
  1297 
  1298 		result = IDirectDraw2_SetDisplayMode(ddraw2, width, height, bpp, maxRefreshRate, 0);
  1299 		if ( result != DD_OK ) {
  1300 			result = IDirectDraw2_SetDisplayMode(ddraw2, width, height, bpp, 0, 0);
  1301 			if ( result != DD_OK ) {
  1302 				/* We couldn't set fullscreen mode, try window */
  1303 				return(DX5_SetVideoMode(this, current, width, height, bpp, flags & ~SDL_FULLSCREEN)); 
  1304 			}
  1305 		}
  1306 		DX5_DInputReset(this, 1);
  1307 	} else {
  1308 		DX5_DInputReset(this, 0);
  1309 	}
  1310 	DX5_UpdateVideoInfo(this);
  1311 
  1312 	/* Create a primary DirectDraw surface */
  1313 	memset(&ddsd, 0, sizeof(ddsd));
  1314 	ddsd.dwSize = sizeof(ddsd);
  1315 	ddsd.dwFlags = DDSD_CAPS;
  1316 	ddsd.ddsCaps.dwCaps = (DDSCAPS_PRIMARYSURFACE|DDSCAPS_VIDEOMEMORY);
  1317 	if ( (flags & SDL_FULLSCREEN) != SDL_FULLSCREEN ) {
  1318 		/* There's no windowed double-buffering */
  1319 		flags &= ~SDL_DOUBLEBUF;
  1320 	}
  1321 	if ( (flags & SDL_DOUBLEBUF) == SDL_DOUBLEBUF ) {
  1322 		ddsd.dwFlags |= DDSD_BACKBUFFERCOUNT;
  1323 		ddsd.ddsCaps.dwCaps |= (DDSCAPS_COMPLEX|DDSCAPS_FLIP);
  1324 		ddsd.dwBackBufferCount = 1;
  1325 	}
  1326 	result = IDirectDraw2_CreateSurface(ddraw2, &ddsd, &dd_surface1, NULL); 
  1327 	if ( (result != DD_OK) && ((flags & SDL_DOUBLEBUF) == SDL_DOUBLEBUF) ) {
  1328 		ddsd.dwFlags &= ~DDSD_BACKBUFFERCOUNT;
  1329 		ddsd.ddsCaps.dwCaps &= ~(DDSCAPS_COMPLEX|DDSCAPS_FLIP);
  1330 		ddsd.dwBackBufferCount = 0;
  1331 		result = IDirectDraw2_CreateSurface(ddraw2,
  1332 						&ddsd, &dd_surface1, NULL); 
  1333 	}
  1334 	if ( result != DD_OK ) {
  1335 		SetDDerror("DirectDraw2::CreateSurface(PRIMARY)", result);
  1336 		return(NULL);
  1337 	}
  1338 	result = IDirectDrawSurface_QueryInterface(dd_surface1,
  1339 			&IID_IDirectDrawSurface3, (LPVOID *)&SDL_primary);
  1340 	if ( result != DD_OK ) {
  1341 		SetDDerror("DirectDrawSurface::QueryInterface", result);
  1342 		return(NULL);
  1343 	}
  1344 	IDirectDrawSurface_Release(dd_surface1);
  1345 
  1346 	/* Get the format of the primary DirectDraw surface */
  1347 	memset(&ddsd, 0, sizeof(ddsd));
  1348 	ddsd.dwSize = sizeof(ddsd);
  1349 	ddsd.dwFlags = DDSD_PIXELFORMAT|DDSD_CAPS;
  1350 	result = IDirectDrawSurface3_GetSurfaceDesc(SDL_primary, &ddsd);
  1351 	if ( result != DD_OK ) {
  1352 		SetDDerror("DirectDrawSurface::GetSurfaceDesc", result);
  1353 		return(NULL);
  1354 	}
  1355 	if ( ! (ddsd.ddpfPixelFormat.dwFlags&DDPF_RGB) ) {
  1356 		SDL_SetError("Primary DDRAW surface is not RGB format");
  1357 		return(NULL);
  1358 	}
  1359 
  1360 	/* Free old palette and create a new one if we're in 8-bit mode */
  1361 	if ( SDL_palette != NULL ) {
  1362 		IDirectDrawPalette_Release(SDL_palette);
  1363 		SDL_palette = NULL;
  1364 	}
  1365 #if defined(NONAMELESSUNION)
  1366 	if ( ddsd.ddpfPixelFormat.u1.dwRGBBitCount == 8 ) {
  1367 #else
  1368 	if ( ddsd.ddpfPixelFormat.dwRGBBitCount == 8 ) {
  1369 #endif
  1370 		int i;
  1371 
  1372 		if ( (flags & SDL_FULLSCREEN) == SDL_FULLSCREEN ) {
  1373 			/* We have access to the entire palette */
  1374 			for ( i=0; i<256; ++i ) {
  1375 				SDL_colors[i].peFlags =
  1376 						(PC_NOCOLLAPSE|PC_RESERVED);
  1377 				SDL_colors[i].peRed = 0;
  1378 				SDL_colors[i].peGreen = 0;
  1379 				SDL_colors[i].peBlue = 0;
  1380 			}
  1381 		} else {
  1382 			/* First 10 colors are reserved by Windows */
  1383 			for ( i=0; i<10; ++i ) {
  1384 				SDL_colors[i].peFlags = PC_EXPLICIT;
  1385 				SDL_colors[i].peRed = i;
  1386 				SDL_colors[i].peGreen = 0;
  1387 				SDL_colors[i].peBlue = 0;
  1388 			}
  1389 			for ( i=10; i<(10+236); ++i ) {
  1390 				SDL_colors[i].peFlags = PC_NOCOLLAPSE;
  1391 				SDL_colors[i].peRed = 0;
  1392 				SDL_colors[i].peGreen = 0;
  1393 				SDL_colors[i].peBlue = 0;
  1394 			}
  1395 			/* Last 10 colors are reserved by Windows */
  1396 			for ( i=246; i<256; ++i ) {
  1397 				SDL_colors[i].peFlags = PC_EXPLICIT;
  1398 				SDL_colors[i].peRed = i;
  1399 				SDL_colors[i].peGreen = 0;
  1400 				SDL_colors[i].peBlue = 0;
  1401 			}
  1402 		}
  1403 		result = IDirectDraw2_CreatePalette(ddraw2,
  1404 		     			(DDPCAPS_8BIT|DDPCAPS_ALLOW256),
  1405 						SDL_colors, &SDL_palette, NULL);
  1406 		if ( result != DD_OK ) {
  1407 			SetDDerror("DirectDraw2::CreatePalette", result);
  1408 			return(NULL);
  1409 		}
  1410 		result = IDirectDrawSurface3_SetPalette(SDL_primary,
  1411 								SDL_palette);
  1412 		if ( result != DD_OK ) {
  1413 			SetDDerror("DirectDrawSurface3::SetPalette", result);
  1414 			return(NULL);
  1415 		}
  1416 	}
  1417 
  1418 	/* Create our video surface using the same pixel format */
  1419 	video = current;
  1420 	if ( (width != video->w) || (height != video->h)
  1421 			|| (video->format->BitsPerPixel != 
  1422 #if defined(NONAMELESSUNION)
  1423 				ddsd.ddpfPixelFormat.u1.dwRGBBitCount) ) {
  1424 #else
  1425 				ddsd.ddpfPixelFormat.dwRGBBitCount) ) {
  1426 #endif
  1427 		SDL_FreeSurface(video);
  1428 		video = SDL_CreateRGBSurface(SDL_SWSURFACE, 0, 0,
  1429 #if defined(NONAMELESSUNION)
  1430 				ddsd.ddpfPixelFormat.u1.dwRGBBitCount,
  1431 					ddsd.ddpfPixelFormat.u2.dwRBitMask,
  1432 					ddsd.ddpfPixelFormat.u3.dwGBitMask,
  1433 					ddsd.ddpfPixelFormat.u4.dwBBitMask,
  1434 #else
  1435 				ddsd.ddpfPixelFormat.dwRGBBitCount,
  1436 					ddsd.ddpfPixelFormat.dwRBitMask,
  1437 					ddsd.ddpfPixelFormat.dwGBitMask,
  1438 					ddsd.ddpfPixelFormat.dwBBitMask,
  1439 #endif
  1440 								0);
  1441 		if ( video == NULL ) {
  1442 			SDL_OutOfMemory();
  1443 			return(NULL);
  1444 		}
  1445 		video->w = width;
  1446 		video->h = height;
  1447 		video->pitch = 0;
  1448 	}
  1449 	video->flags = 0;	/* Clear flags */
  1450 
  1451 	/* If not fullscreen, locking is possible, but it doesn't do what 
  1452 	   the caller really expects -- if the locked surface is written to,
  1453 	   the appropriate portion of the entire screen is modified, not 
  1454 	   the application window, as we would like.
  1455 	   Note that it is still possible to write directly to display
  1456 	   memory, but the application must respect the clip list of
  1457 	   the surface.  There might be some odd timing interactions
  1458 	   involving clip list updates and background refreshing as
  1459 	   Windows moves other windows across our window.
  1460 	   We currently don't support this, even though it might be a
  1461 	   good idea since BeOS has an implementation of BDirectWindow
  1462 	   that does the same thing.  This would be most useful for
  1463 	   applications that do complete screen updates every frame.
  1464 	    -- Fixme?
  1465 	*/
  1466 	if ( (flags & SDL_FULLSCREEN) != SDL_FULLSCREEN ) {
  1467 		/* Necessary if we're going from fullscreen to window */
  1468 		if ( video->pixels == NULL ) {
  1469 			video->pitch = (width*video->format->BytesPerPixel);
  1470 			/* Pitch needs to be QWORD (8-byte) aligned */
  1471 			video->pitch = (video->pitch + 7) & ~7;
  1472 			video->pixels = (void *)malloc(video->h*video->pitch);
  1473 			if ( video->pixels == NULL ) {
  1474 				if ( video != current ) {
  1475 					SDL_FreeSurface(video);
  1476 				}
  1477 				SDL_OutOfMemory();
  1478 				return(NULL);
  1479 			}
  1480 		}
  1481 		dd_surface3 = NULL;
  1482 #if 0 /* FIXME: enable this when SDL consistently reports lost surfaces */
  1483 		if ( (flags & SDL_HWSURFACE) == SDL_HWSURFACE ) {
  1484 			video->flags |= SDL_HWSURFACE;
  1485 		} else {
  1486 			video->flags |= SDL_SWSURFACE;
  1487 		}
  1488 #else
  1489 		video->flags |= SDL_SWSURFACE;
  1490 #endif
  1491 		if ( (flags & SDL_RESIZABLE) && !(flags & SDL_NOFRAME) ) {
  1492 			video->flags |= SDL_RESIZABLE;
  1493 		}
  1494 		if ( flags & SDL_NOFRAME ) {
  1495 			video->flags |= SDL_NOFRAME;
  1496 		}
  1497 	} else {
  1498 		/* Necessary if we're going from window to fullscreen */
  1499 		if ( video->pixels != NULL ) {
  1500 			free(video->pixels);
  1501 			video->pixels = NULL;
  1502 		}
  1503 		dd_surface3 = SDL_primary;
  1504 		video->flags |= SDL_HWSURFACE;
  1505 	}
  1506 
  1507 	/* See if the primary surface has double-buffering enabled */
  1508 	if ( (ddsd.ddsCaps.dwCaps & DDSCAPS_FLIP) == DDSCAPS_FLIP ) {
  1509 		video->flags |= SDL_DOUBLEBUF;
  1510 	}
  1511 
  1512 	/* Allocate the SDL surface associated with the primary surface */
  1513 	if ( DX5_AllocDDSurface(this, video, dd_surface3,
  1514 	                        video->flags&SDL_HWSURFACE) < 0 ) {
  1515 		if ( video != current ) {
  1516 			SDL_FreeSurface(video);
  1517 		}
  1518 		return(NULL);
  1519 	}
  1520 
  1521 	/* Use the appropriate blitting function */
  1522 	if ( (flags & SDL_FULLSCREEN) == SDL_FULLSCREEN ) {
  1523 		video->flags |= SDL_FULLSCREEN;
  1524 		if ( video->format->palette != NULL ) {
  1525 			video->flags |= SDL_HWPALETTE;
  1526 		}
  1527 		this->UpdateRects = DX5_DirectUpdate;
  1528 	} else {
  1529 		this->UpdateRects = DX5_WindowUpdate;
  1530 	}
  1531 
  1532 	/* Make our window the proper size, set the clipper, then show it */
  1533 	if ( (flags & SDL_FULLSCREEN) != SDL_FULLSCREEN ) {
  1534 		/* Create and set a clipper on our primary surface */
  1535 		if ( SDL_clipper == NULL ) {
  1536 			result = IDirectDraw2_CreateClipper(ddraw2,
  1537 							0, &SDL_clipper, NULL);
  1538 			if ( result != DD_OK ) {
  1539 				if ( video != current ) {
  1540 					SDL_FreeSurface(video);
  1541 				}
  1542 				SetDDerror("DirectDraw2::CreateClipper",result);
  1543 				return(NULL);
  1544 			}
  1545 		}
  1546 		result = IDirectDrawClipper_SetHWnd(SDL_clipper, 0, SDL_Window);
  1547 		if ( result != DD_OK ) {
  1548 			if ( video != current ) {
  1549 				SDL_FreeSurface(video);
  1550 			}
  1551 			SetDDerror("DirectDrawClipper::SetHWnd", result);
  1552 			return(NULL);
  1553 		}
  1554 		result = IDirectDrawSurface3_SetClipper(SDL_primary,
  1555 								SDL_clipper);
  1556 		if ( result != DD_OK ) {
  1557 			if ( video != current ) {
  1558 				SDL_FreeSurface(video);
  1559 			}
  1560 			SetDDerror("DirectDrawSurface3::SetClipper", result);
  1561 			return(NULL);
  1562 		}
  1563 
  1564 		/* Resize the window (copied from SDL WinDIB driver) */
  1565 		if ( !SDL_windowid && !IsZoomed(SDL_Window) ) {
  1566 			RECT bounds;
  1567 			int  x, y;
  1568 			UINT swp_flags;
  1569 			const char *window = NULL;
  1570 			const char *center = NULL;
  1571 
  1572 			if ( !SDL_windowX && !SDL_windowY ) {
  1573 				window = getenv("SDL_VIDEO_WINDOW_POS");
  1574 				center = getenv("SDL_VIDEO_CENTERED");
  1575 				if ( window ) {
  1576 					if ( sscanf(window, "%d,%d", &x, &y) == 2 ) {
  1577 						SDL_windowX = x;
  1578 						SDL_windowY = y;
  1579 					}
  1580 					if ( strcmp(window, "center") == 0 ) {
  1581 						center = window;
  1582 					}
  1583 				}
  1584 			}
  1585 			swp_flags = SWP_NOCOPYBITS;
  1586 
  1587 			bounds.left = SDL_windowX;
  1588 			bounds.top = SDL_windowY;
  1589 			bounds.right = SDL_windowX+video->w;
  1590 			bounds.bottom = SDL_windowY+video->h;
  1591 			AdjustWindowRectEx(&bounds, GetWindowLong(SDL_Window, GWL_STYLE), FALSE, 0);
  1592 			width = bounds.right-bounds.left;
  1593 			height = bounds.bottom-bounds.top;
  1594 			if ( center ) {
  1595 				x = (GetSystemMetrics(SM_CXSCREEN)-width)/2;
  1596 				y = (GetSystemMetrics(SM_CYSCREEN)-height)/2;
  1597 			} else if ( SDL_windowX || SDL_windowY || window ) {
  1598 				x = bounds.left;
  1599 				y = bounds.top;
  1600 			} else {
  1601 				x = y = -1;
  1602 				swp_flags |= SWP_NOMOVE;
  1603 			}
  1604 			SetWindowPos(SDL_Window, HWND_NOTOPMOST, x, y, width, height, swp_flags);
  1605 			SDL_windowX = SDL_bounds.left;
  1606 			SDL_windowY = SDL_bounds.top;
  1607 		}
  1608 
  1609 	}
  1610 	ShowWindow(SDL_Window, SW_SHOW);
  1611 	SetForegroundWindow(SDL_Window);
  1612 	SDL_resizing = 0;
  1613 
  1614 	/* We're live! */
  1615 	return(video);
  1616 }
  1617 
  1618 struct private_hwdata {
  1619 	LPDIRECTDRAWSURFACE3 dd_surface;
  1620 	LPDIRECTDRAWSURFACE3 dd_writebuf;
  1621 };
  1622 
  1623 static int DX5_AllocDDSurface(_THIS, SDL_Surface *surface, 
  1624 				LPDIRECTDRAWSURFACE3 requested, Uint32 flag)
  1625 {
  1626 	LPDIRECTDRAWSURFACE  dd_surface1;
  1627 	LPDIRECTDRAWSURFACE3 dd_surface3;
  1628 	DDSURFACEDESC ddsd;
  1629 	HRESULT result;
  1630 
  1631 	/* Clear the hardware flag, in case we fail */
  1632 	surface->flags &= ~flag;
  1633 
  1634 	/* Allocate the hardware acceleration data */
  1635 	surface->hwdata = (struct private_hwdata *)
  1636 					malloc(sizeof(*surface->hwdata));
  1637 	if ( surface->hwdata == NULL ) {
  1638 		SDL_OutOfMemory();
  1639 		return(-1);
  1640 	}
  1641 	dd_surface3 = NULL;
  1642 
  1643 	/* Set up the surface description */
  1644 	memset(&ddsd, 0, sizeof(ddsd));
  1645 	ddsd.dwSize = sizeof(ddsd);
  1646 	ddsd.dwFlags = (DDSD_WIDTH|DDSD_HEIGHT|DDSD_CAPS|
  1647 					DDSD_PITCH|DDSD_PIXELFORMAT);
  1648 	ddsd.dwWidth = surface->w;
  1649 	ddsd.dwHeight= surface->h;
  1650 #if defined(NONAMELESSUNION)
  1651 	ddsd.u1.lPitch = surface->pitch;
  1652 #else
  1653 	ddsd.lPitch = surface->pitch;
  1654 #endif
  1655 	if ( (flag & SDL_HWSURFACE) == SDL_HWSURFACE ) {
  1656 		ddsd.ddsCaps.dwCaps =
  1657 				(DDSCAPS_OFFSCREENPLAIN|DDSCAPS_VIDEOMEMORY);
  1658 	} else {
  1659 		ddsd.ddsCaps.dwCaps =
  1660 				(DDSCAPS_OFFSCREENPLAIN|DDSCAPS_SYSTEMMEMORY);
  1661 	}
  1662 	ddsd.ddpfPixelFormat.dwSize = sizeof(ddsd.ddpfPixelFormat);
  1663 	ddsd.ddpfPixelFormat.dwFlags = DDPF_RGB;
  1664 	if ( surface->format->palette ) {
  1665 		ddsd.ddpfPixelFormat.dwFlags |= DDPF_PALETTEINDEXED8;
  1666 	}
  1667 #if defined(NONAMELESSUNION)
  1668 	ddsd.ddpfPixelFormat.u1.dwRGBBitCount = surface->format->BitsPerPixel;
  1669 	ddsd.ddpfPixelFormat.u2.dwRBitMask = surface->format->Rmask;
  1670 	ddsd.ddpfPixelFormat.u3.dwGBitMask = surface->format->Gmask;
  1671 	ddsd.ddpfPixelFormat.u4.dwBBitMask = surface->format->Bmask;
  1672 #else
  1673 	ddsd.ddpfPixelFormat.dwRGBBitCount = surface->format->BitsPerPixel;
  1674 	ddsd.ddpfPixelFormat.dwRBitMask = surface->format->Rmask;
  1675 	ddsd.ddpfPixelFormat.dwGBitMask = surface->format->Gmask;
  1676 	ddsd.ddpfPixelFormat.dwBBitMask = surface->format->Bmask;
  1677 #endif
  1678 
  1679 	/* Create the DirectDraw video surface */
  1680 	if ( requested != NULL ) {
  1681 		dd_surface3 = requested;
  1682 	} else {
  1683 		result = IDirectDraw2_CreateSurface(ddraw2,
  1684 						&ddsd, &dd_surface1, NULL); 
  1685 		if ( result != DD_OK ) {
  1686 			SetDDerror("DirectDraw2::CreateSurface", result);
  1687 			goto error_end;
  1688 		}
  1689 		result = IDirectDrawSurface_QueryInterface(dd_surface1,
  1690 			&IID_IDirectDrawSurface3, (LPVOID *)&dd_surface3);
  1691 		IDirectDrawSurface_Release(dd_surface1);
  1692 		if ( result != DD_OK ) {
  1693 			SetDDerror("DirectDrawSurface::QueryInterface", result);
  1694 			goto error_end;
  1695 		}
  1696 	}
  1697 
  1698 	if ( (flag & SDL_HWSURFACE) == SDL_HWSURFACE ) {
  1699 		/* Check to see whether the surface actually ended up
  1700 		   in video memory, and fail if not.  We expect the
  1701 		   surfaces we create here to actually be in hardware!
  1702 		*/
  1703 		result = IDirectDrawSurface3_GetCaps(dd_surface3,&ddsd.ddsCaps);
  1704 		if ( result != DD_OK ) {
  1705 			SetDDerror("DirectDrawSurface3::GetCaps", result);
  1706 			goto error_end;
  1707 		}
  1708 		if ( (ddsd.ddsCaps.dwCaps&DDSCAPS_VIDEOMEMORY) !=
  1709 							DDSCAPS_VIDEOMEMORY ) {
  1710 			SDL_SetError("No room in video memory");
  1711 			goto error_end;
  1712 		}
  1713 	} else {
  1714 		/* Try to hook our surface memory */
  1715 		ddsd.dwFlags = DDSD_LPSURFACE;
  1716 		ddsd.lpSurface = surface->pixels;
  1717 		result = IDirectDrawSurface3_SetSurfaceDesc(dd_surface3,
  1718 								&ddsd, 0);
  1719 		if ( result != DD_OK ) {
  1720 			SetDDerror("DirectDraw2::SetSurfaceDesc", result);
  1721 			goto error_end;
  1722 		}
  1723 	
  1724 	}
  1725 
  1726 	/* Make sure the surface format was set properly */
  1727 	memset(&ddsd, 0, sizeof(ddsd));
  1728 	ddsd.dwSize = sizeof(ddsd);
  1729 	result = IDirectDrawSurface3_Lock(dd_surface3, NULL,
  1730 		&ddsd, (DDLOCK_NOSYSLOCK|DDLOCK_WAIT), NULL);
  1731 	if ( result != DD_OK ) {
  1732 		SetDDerror("DirectDrawSurface3::Lock", result);
  1733 		goto error_end;
  1734 	}
  1735 	IDirectDrawSurface3_Unlock(dd_surface3, NULL);
  1736 
  1737 	if ( (flag & SDL_HWSURFACE) == SDL_SWSURFACE ) {
  1738 		if ( ddsd.lpSurface != surface->pixels ) {
  1739 			SDL_SetError("DDraw didn't use SDL surface memory");
  1740 			goto error_end;
  1741 		}
  1742 		if (
  1743 #if defined(NONAMELESSUNION)
  1744 			ddsd.u1.lPitch
  1745 #else
  1746 			ddsd.lPitch
  1747 #endif
  1748 				 != (LONG)surface->pitch ) {
  1749 			SDL_SetError("DDraw created surface with wrong pitch");
  1750 			goto error_end;
  1751 		}
  1752 	} else {
  1753 #if defined(NONAMELESSUNION)
  1754 		surface->pitch = (Uint16)ddsd.u1.lPitch;
  1755 #else
  1756 		surface->pitch = (Uint16)ddsd.lPitch;
  1757 #endif
  1758 	}
  1759 #if defined(NONAMELESSUNION)
  1760 	if ( (ddsd.ddpfPixelFormat.u1.dwRGBBitCount != 
  1761 					surface->format->BitsPerPixel) ||
  1762 	     (ddsd.ddpfPixelFormat.u2.dwRBitMask != surface->format->Rmask) ||
  1763 	     (ddsd.ddpfPixelFormat.u3.dwGBitMask != surface->format->Gmask) ||
  1764 	     (ddsd.ddpfPixelFormat.u4.dwBBitMask != surface->format->Bmask) ){
  1765 #else
  1766 	if ( (ddsd.ddpfPixelFormat.dwRGBBitCount != 
  1767 					surface->format->BitsPerPixel) ||
  1768 	     (ddsd.ddpfPixelFormat.dwRBitMask != surface->format->Rmask) ||
  1769 	     (ddsd.ddpfPixelFormat.dwGBitMask != surface->format->Gmask) ||
  1770 	     (ddsd.ddpfPixelFormat.dwBBitMask != surface->format->Bmask) ){
  1771 #endif
  1772 		SDL_SetError("DDraw didn't use SDL surface description");
  1773 		goto error_end;
  1774 	}
  1775 	if ( (ddsd.dwWidth != (DWORD)surface->w) ||
  1776 		(ddsd.dwHeight != (DWORD)surface->h) ) {
  1777 		SDL_SetError("DDraw created surface with wrong size");
  1778 		goto error_end;
  1779 	}
  1780 
  1781 	/* Set the surface private data */
  1782 	surface->flags |= flag;
  1783 	surface->hwdata->dd_surface = dd_surface3;
  1784 	if ( (surface->flags & SDL_DOUBLEBUF) == SDL_DOUBLEBUF ) {
  1785 		LPDIRECTDRAWSURFACE3 dd_writebuf;
  1786 
  1787 		ddsd.ddsCaps.dwCaps = DDSCAPS_BACKBUFFER;
  1788 		result = IDirectDrawSurface3_GetAttachedSurface(dd_surface3,
  1789 						&ddsd.ddsCaps, &dd_writebuf);
  1790 		if ( result != DD_OK ) {
  1791 			SetDDerror("DirectDrawSurface3::GetAttachedSurface",
  1792 								result);
  1793 		} else {
  1794 			dd_surface3 = dd_writebuf;
  1795 		}
  1796 	}
  1797 	surface->hwdata->dd_writebuf = dd_surface3;
  1798 
  1799 	/* We're ready to go! */
  1800 	return(0);
  1801 
  1802 	/* Okay, so goto's are cheesy, but there are so many possible
  1803 	   errors in this function, and the cleanup is the same in 
  1804 	   every single case.  Is there a better way, other than deeply
  1805 	   nesting the code?
  1806 	*/
  1807 error_end:
  1808 	if ( (dd_surface3 != NULL) && (dd_surface3 != requested) ) {
  1809 		IDirectDrawSurface_Release(dd_surface3);
  1810 	}
  1811 	free(surface->hwdata);
  1812 	surface->hwdata = NULL;
  1813 	return(-1);
  1814 }
  1815 
  1816 static int DX5_AllocHWSurface(_THIS, SDL_Surface *surface)
  1817 {
  1818 	/* DDraw limitation -- you need to set cooperative level first */
  1819 	if ( SDL_primary == NULL ) {
  1820 		SDL_SetError("You must set a non-GL video mode first");
  1821 		return(-1);
  1822 	}
  1823 	return(DX5_AllocDDSurface(this, surface, NULL, SDL_HWSURFACE));
  1824 }
  1825 
  1826 #ifdef DDRAW_DEBUG
  1827 void PrintSurface(char *title, LPDIRECTDRAWSURFACE3 surface, Uint32 flags)
  1828 {
  1829 	DDSURFACEDESC ddsd;
  1830 
  1831 	/* Lock and load! */
  1832 	memset(&ddsd, 0, sizeof(ddsd));
  1833 	ddsd.dwSize = sizeof(ddsd);
  1834 	if ( IDirectDrawSurface3_Lock(surface, NULL, &ddsd,
  1835 			(DDLOCK_NOSYSLOCK|DDLOCK_WAIT), NULL) != DD_OK ) {
  1836 		return;
  1837 	}
  1838 	IDirectDrawSurface3_Unlock(surface, NULL);
  1839 	
  1840 	fprintf(stderr, "%s:\n", title);
  1841 	fprintf(stderr, "\tSize: %dx%d in %s at %ld bpp (pitch = %ld)\n",
  1842 		ddsd.dwWidth, ddsd.dwHeight,
  1843 		(flags & SDL_HWSURFACE) ? "hardware" : "software",
  1844 #if defined(NONAMELESSUNION)
  1845 		ddsd.ddpfPixelFormat.u1.dwRGBBitCount, ddsd.u1.lPitch);
  1846 #else
  1847 		ddsd.ddpfPixelFormat.dwRGBBitCount, ddsd.lPitch);
  1848 #endif
  1849 	fprintf(stderr, "\tR = 0x%X, G = 0x%X, B = 0x%X\n", 
  1850 #if defined(NONAMELESSUNION)
  1851 	     		ddsd.ddpfPixelFormat.u2.dwRBitMask,
  1852 	     		ddsd.ddpfPixelFormat.u3.dwGBitMask,
  1853 	     		ddsd.ddpfPixelFormat.u4.dwBBitMask);
  1854 #else
  1855 	     		ddsd.ddpfPixelFormat.dwRBitMask,
  1856 	     		ddsd.ddpfPixelFormat.dwGBitMask,
  1857 	     		ddsd.ddpfPixelFormat.dwBBitMask);
  1858 #endif
  1859 }
  1860 #endif /* DDRAW_DEBUG */
  1861 
  1862 static int DX5_HWAccelBlit(SDL_Surface *src, SDL_Rect *srcrect,
  1863 					SDL_Surface *dst, SDL_Rect *dstrect)
  1864 {
  1865 	LPDIRECTDRAWSURFACE3 src_surface;
  1866 	LPDIRECTDRAWSURFACE3 dst_surface;
  1867 	DWORD flags;
  1868 	RECT rect;
  1869 	HRESULT result;
  1870 
  1871 	/* Set it up.. the desination must have a DDRAW surface */
  1872 	src_surface = src->hwdata->dd_writebuf;
  1873 	dst_surface = dst->hwdata->dd_writebuf;
  1874 	rect.top    = (LONG)srcrect->y;
  1875 	rect.bottom = (LONG)srcrect->y+srcrect->h;
  1876 	rect.left   = (LONG)srcrect->x;
  1877 	rect.right  = (LONG)srcrect->x+srcrect->w;
  1878 	if ( (src->flags & SDL_SRCCOLORKEY) == SDL_SRCCOLORKEY )
  1879 		flags = DDBLTFAST_SRCCOLORKEY;
  1880 	else
  1881 		flags = DDBLTFAST_NOCOLORKEY;
  1882 	/* FIXME:  We can remove this flag for _really_ fast blit queuing,
  1883 	           but it will affect the return values of locks and flips.
  1884 	 */
  1885 	flags |= DDBLTFAST_WAIT;
  1886 
  1887 	/* Do the blit! */
  1888 	result = IDirectDrawSurface3_BltFast(dst_surface,
  1889 			dstrect->x, dstrect->y, src_surface, &rect, flags);
  1890 	if ( result != DD_OK ) {
  1891 		if ( result == DDERR_SURFACELOST ) {
  1892 			result = IDirectDrawSurface3_Restore(src_surface);
  1893 			result = IDirectDrawSurface3_Restore(dst_surface);
  1894 			/* The surfaces need to be reloaded with artwork */
  1895 			SDL_SetError("Blit surfaces were lost, reload them");
  1896 			return(-2);
  1897 		}
  1898 		SetDDerror("IDirectDrawSurface3::BltFast", result);
  1899 #ifdef DDRAW_DEBUG
  1900  fprintf(stderr, "Original dest rect: %dx%d at %d,%d\n", dstrect->w, dstrect->h, dstrect->x, dstrect->y);
  1901  fprintf(stderr, "HW accelerated %sblit to from 0x%p to 0x%p at (%d,%d)\n",
  1902 		(src->flags & SDL_SRCCOLORKEY) ? "colorkey " : "", src, dst,
  1903 					dstrect->x, dstrect->y);
  1904   PrintSurface("SRC", src_surface, src->flags);
  1905   PrintSurface("DST", dst_surface, dst->flags);
  1906  fprintf(stderr, "Source rectangle: (%d,%d) - (%d,%d)\n",
  1907 		rect.left, rect.top, rect.right, rect.bottom);
  1908 #endif
  1909 		/* Unexpected error, fall back to software blit */
  1910 		return(src->map->sw_blit(src, srcrect, dst, dstrect));
  1911 	}
  1912 	return(0);
  1913 }
  1914 
  1915 static int DX5_CheckHWBlit(_THIS, SDL_Surface *src, SDL_Surface *dst)
  1916 {
  1917 	int accelerated;
  1918 
  1919 	/* We need to have a DDraw surface for HW blits */
  1920 	if ( (src->flags & SDL_HWSURFACE) == SDL_SWSURFACE ) {
  1921 		/* Allocate a DDraw surface for the blit */
  1922 		if ( src->hwdata == NULL ) {
  1923 			DX5_AllocDDSurface(this, src, NULL, SDL_SWSURFACE);
  1924 		}
  1925 	}
  1926 	if ( src->hwdata == NULL ) {
  1927 		return(0);
  1928 	}
  1929 
  1930 	/* Set initial acceleration on */
  1931 	src->flags |= SDL_HWACCEL;
  1932 
  1933 	/* Set the surface attributes */
  1934 	if ( (src->flags & SDL_SRCCOLORKEY) == SDL_SRCCOLORKEY ) {
  1935 		if ( DX5_SetHWColorKey(this, src, src->format->colorkey) < 0 ) {
  1936 			src->flags &= ~SDL_HWACCEL;
  1937 		}
  1938 	}
  1939 	if ( (src->flags & SDL_SRCALPHA) == SDL_SRCALPHA ) {
  1940 		if ( DX5_SetHWAlpha(this, src, src->format->alpha) < 0 ) {
  1941 			src->flags &= ~SDL_HWACCEL;
  1942 		}
  1943 	}
  1944 
  1945 	/* Check to see if final surface blit is accelerated */
  1946 	accelerated = !!(src->flags & SDL_HWACCEL);
  1947 	if ( accelerated ) {
  1948 #ifdef DDRAW_DEBUG
  1949   fprintf(stderr, "Setting accelerated blit on 0x%p\n", src);
  1950 #endif
  1951 		src->map->hw_blit = DX5_HWAccelBlit;
  1952 	}
  1953 	return(accelerated);
  1954 }
  1955 
  1956 static int DX5_FillHWRect(_THIS, SDL_Surface *dst, SDL_Rect *dstrect, Uint32 color)
  1957 {
  1958 	LPDIRECTDRAWSURFACE3 dst_surface;
  1959 	RECT area;
  1960 	DDBLTFX bltfx;
  1961 	HRESULT result;
  1962 
  1963 #ifdef DDRAW_DEBUG
  1964  fprintf(stderr, "HW accelerated fill at (%d,%d)\n", dstrect->x, dstrect->y);
  1965 #endif
  1966 	dst_surface = dst->hwdata->dd_writebuf;
  1967 	area.top    = (LONG)dstrect->y;
  1968 	area.bottom = (LONG)dstrect->y+dstrect->h;
  1969 	area.left   = (LONG)dstrect->x;
  1970 	area.right  = (LONG)dstrect->x+dstrect->w;
  1971 	bltfx.dwSize = sizeof(bltfx);
  1972 #if defined(NONAMELESSUNION)
  1973 	bltfx.u5.dwFillColor = color;
  1974 #else
  1975 	bltfx.dwFillColor = color;
  1976 #endif
  1977 	result = IDirectDrawSurface3_Blt(dst_surface,
  1978 			&area, NULL, NULL, DDBLT_COLORFILL|DDBLT_WAIT, &bltfx);
  1979 	if ( result == DDERR_SURFACELOST ) {
  1980 		IDirectDrawSurface3_Restore(dst_surface);
  1981 		result = IDirectDrawSurface3_Blt(dst_surface,
  1982 			&area, NULL, NULL, DDBLT_COLORFILL|DDBLT_WAIT, &bltfx);
  1983 	}
  1984 	if ( result != DD_OK ) {
  1985 		SetDDerror("IDirectDrawSurface3::Blt", result);
  1986 		return(-1);
  1987 	}
  1988 	return(0);
  1989 }
  1990 
  1991 static int DX5_SetHWColorKey(_THIS, SDL_Surface *surface, Uint32 key)
  1992 {
  1993 	DDCOLORKEY colorkey;
  1994 	HRESULT result;
  1995 
  1996 	/* Set the surface colorkey */
  1997 	colorkey.dwColorSpaceLowValue = key;
  1998 	colorkey.dwColorSpaceHighValue = key;
  1999 	result = IDirectDrawSurface3_SetColorKey(
  2000 			surface->hwdata->dd_surface, DDCKEY_SRCBLT, &colorkey);
  2001 	if ( result != DD_OK ) {
  2002 		SetDDerror("IDirectDrawSurface3::SetColorKey", result);
  2003 		return(-1);
  2004 	}
  2005 	return(0);
  2006 }
  2007 static int DX5_SetHWAlpha(_THIS, SDL_Surface *surface, Uint8 alpha)
  2008 {
  2009 	return(-1);
  2010 }
  2011 
  2012 static int DX5_LockHWSurface(_THIS, SDL_Surface *surface)
  2013 {
  2014 	HRESULT result;
  2015 	LPDIRECTDRAWSURFACE3 dd_surface;
  2016 	DDSURFACEDESC ddsd;
  2017 
  2018 	/* Lock and load! */
  2019 	dd_surface = surface->hwdata->dd_writebuf;
  2020 	memset(&ddsd, 0, sizeof(ddsd));
  2021 	ddsd.dwSize = sizeof(ddsd);
  2022 	result = IDirectDrawSurface3_Lock(dd_surface, NULL, &ddsd,
  2023 					(DDLOCK_NOSYSLOCK|DDLOCK_WAIT), NULL);
  2024 	if ( result == DDERR_SURFACELOST ) {
  2025 		result = IDirectDrawSurface3_Restore(
  2026 						surface->hwdata->dd_surface);
  2027 		result = IDirectDrawSurface3_Lock(dd_surface, NULL, &ddsd, 
  2028 					(DDLOCK_NOSYSLOCK|DDLOCK_WAIT), NULL);
  2029 	}
  2030 	if ( result != DD_OK ) {
  2031 		SetDDerror("DirectDrawSurface3::Lock", result);
  2032 		return(-1);
  2033 	}
  2034 	/* Pitch might have changed -- recalculate pitch and offset */
  2035 #if defined(NONAMELESSUNION)
  2036 	if ( surface->pitch != ddsd.u1.lPitch ) {
  2037 		surface->pitch = ddsd.u1.lPitch;
  2038 #else
  2039 	if ( surface->pitch != ddsd.lPitch ) {
  2040 		surface->pitch = (Uint16)ddsd.lPitch;
  2041 #endif
  2042 		surface->offset =
  2043 			((ddsd.dwHeight-surface->h)/2)*surface->pitch +
  2044 			((ddsd.dwWidth-surface->w)/2)*
  2045 					surface->format->BytesPerPixel;
  2046 	}
  2047 	surface->pixels = ddsd.lpSurface;
  2048 	return(0);
  2049 }
  2050 
  2051 static void DX5_UnlockHWSurface(_THIS, SDL_Surface *surface)
  2052 {
  2053 	IDirectDrawSurface3_Unlock(surface->hwdata->dd_writebuf, NULL);
  2054 	surface->pixels = NULL;
  2055 }
  2056 
  2057 static int DX5_FlipHWSurface(_THIS, SDL_Surface *surface)
  2058 {
  2059 	HRESULT result;
  2060 	LPDIRECTDRAWSURFACE3 dd_surface;
  2061 
  2062 	dd_surface = surface->hwdata->dd_surface;
  2063 
  2064 	/* to prevent big slowdown on fast computers, wait here instead of driver ring 0 code */
  2065 	/* Dmitry Yakimov (ftech@tula.net) */
  2066 	while(IDirectDrawSurface3_GetFlipStatus(dd_surface, DDGBS_ISBLTDONE) == DDERR_WASSTILLDRAWING);
  2067 
  2068 	result = IDirectDrawSurface3_Flip(dd_surface, NULL, DDFLIP_WAIT);
  2069 	if ( result == DDERR_SURFACELOST ) {
  2070 		result = IDirectDrawSurface3_Restore(
  2071 						surface->hwdata->dd_surface);
  2072 		while(IDirectDrawSurface3_GetFlipStatus(dd_surface, DDGBS_ISBLTDONE) == DDERR_WASSTILLDRAWING);
  2073 		result = IDirectDrawSurface3_Flip(dd_surface, NULL, DDFLIP_WAIT);
  2074 	}
  2075 	if ( result != DD_OK ) {
  2076 		SetDDerror("DirectDrawSurface3::Flip", result);
  2077 		return(-1);
  2078 	}
  2079 	return(0);
  2080 }
  2081 
  2082 static void DX5_FreeHWSurface(_THIS, SDL_Surface *surface)
  2083 {
  2084 	if ( surface->hwdata ) {
  2085 		if ( surface->hwdata->dd_surface != SDL_primary ) {
  2086 			IDirectDrawSurface3_Release(surface->hwdata->dd_surface);
  2087 		}
  2088 		free(surface->hwdata);
  2089 		surface->hwdata = NULL;
  2090 	}
  2091 }
  2092 
  2093 void DX5_WindowUpdate(_THIS, int numrects, SDL_Rect *rects)
  2094 {
  2095 	HRESULT result;
  2096 	int i;
  2097 	RECT src, dst;
  2098 
  2099 	for ( i=0; i<numrects; ++i ) {
  2100 		src.top    = (LONG)rects[i].y;
  2101 		src.bottom = (LONG)rects[i].y+rects[i].h;
  2102 		src.left   = (LONG)rects[i].x;
  2103 		src.right  = (LONG)rects[i].x+rects[i].w;
  2104 		dst.top    = SDL_bounds.top+src.top;
  2105 		dst.left   = SDL_bounds.left+src.left;
  2106 		dst.bottom = SDL_bounds.top+src.bottom;
  2107 		dst.right  = SDL_bounds.left+src.right;
  2108 		result = IDirectDrawSurface3_Blt(SDL_primary, &dst, 
  2109 					this->screen->hwdata->dd_surface, &src,
  2110 							DDBLT_WAIT, NULL);
  2111 		/* Doh!  Check for lost surface and restore it */
  2112 		if ( result == DDERR_SURFACELOST ) {
  2113 			IDirectDrawSurface3_Restore(SDL_primary);
  2114 			IDirectDrawSurface3_Blt(SDL_primary, &dst, 
  2115 					this->screen->hwdata->dd_surface, &src,
  2116 							DDBLT_WAIT, NULL);
  2117 		}
  2118 	}
  2119 }
  2120 
  2121 void DX5_DirectUpdate(_THIS, int numrects, SDL_Rect *rects)
  2122 {
  2123 }
  2124 
  2125 /* Compress a full palette into the limited number of colors given to us
  2126    by windows.
  2127 
  2128    The "best" way to do this is to sort the colors by diversity and place
  2129    the most diverse colors into the limited palette.  Unfortunately this
  2130    results in widely varying colors being displayed in the interval during
  2131    which the windows palette has been set, and the mapping of the shadow
  2132    surface to the new palette.  This is especially noticeable during fades.
  2133 
  2134    To deal with this problem, we can copy a predetermined portion of the
  2135    full palette, and use that as the limited palette.  This allows colors
  2136    to fade smoothly as the remapping is very similar on each palette change.
  2137    Unfortunately, this breaks applications which partition the palette into
  2138    distinct and widely varying areas, expecting all colors to be available.
  2139 
  2140    I'm making them both available, chosen at compile time.
  2141    If you want the chunk-o-palette algorithm, define SIMPLE_COMPRESSION,
  2142    otherwise the sort-by-diversity algorithm will be used.
  2143 */
  2144 #define SIMPLE_COMPRESSION
  2145 #define CS_CS_DIST(A, B) ({						\
  2146 	int r = (A.r - B.r);						\
  2147 	int g = (A.g - B.g);						\
  2148 	int b = (A.b - B.b);						\
  2149 	(r*r + g*g + b*b);						\
  2150 })
  2151 static void DX5_CompressPalette(_THIS, SDL_Color *colors, int ncolors, int maxcolors)
  2152 {
  2153 #ifdef SIMPLE_COMPRESSION
  2154 	int i, j;
  2155 #else
  2156 	static SDL_Color zero = { 0, 0, 0, 0 };
  2157 	int i, j;
  2158 	int max, dist;
  2159 	int prev, next;
  2160 	int *pool;
  2161 	int *seen, *order;
  2162 #endif
  2163 
  2164 	/* Does this happen? */
  2165 	if ( maxcolors > ncolors ) {
  2166 		maxcolors = ncolors;
  2167 	}
  2168 
  2169 #ifdef SIMPLE_COMPRESSION
  2170 	/* Just copy the first "maxcolors" colors */
  2171 	for ( j=10, i=0; i<maxcolors; ++i, ++j ) {
  2172 		SDL_colors[j].peRed = colors[i].r;
  2173 		SDL_colors[j].peGreen = colors[i].g;
  2174 		SDL_colors[j].peBlue = colors[i].b;
  2175 	}
  2176 #else
  2177 	/* Allocate memory for the arrays we use */
  2178 	pool = (int *)alloca(2*ncolors*sizeof(int));
  2179 	if ( pool == NULL ) {
  2180 		/* No worries, just return */;
  2181 		return;
  2182 	}
  2183 	seen = pool;
  2184 	memset(seen, 0, ncolors*sizeof(int));
  2185 	order = pool+ncolors;
  2186 
  2187 	/* Start with the brightest color */
  2188 	max = 0;
  2189 	for ( i=0; i<ncolors; ++i ) {
  2190 		dist = CS_CS_DIST(zero, colors[i]);
  2191 		if ( dist >= max ) {
  2192 			max = dist;
  2193 			next = i;
  2194 		}
  2195 	}
  2196 	j = 0;
  2197 	order[j++] = next;
  2198 	seen[next] = 1;
  2199 	prev = next;
  2200 
  2201 	/* Keep going through all the colors */
  2202 	while ( j < maxcolors ) {
  2203 		max = 0;
  2204 		for ( i=0; i<ncolors; ++i ) {
  2205 			if ( seen[i] ) {
  2206 				continue;
  2207 			}
  2208 			dist = CS_CS_DIST(colors[i], colors[prev]);
  2209 			if ( dist >= max ) {
  2210 				max = dist;
  2211 				next = i;
  2212 			}
  2213 		}
  2214 		order[j++] = next;
  2215 		seen[next] = 1;
  2216 		prev = next;
  2217 	}
  2218 
  2219 	/* Compress the colors to the palette */
  2220 	for ( j=10, i=0; i<maxcolors; ++i, ++j ) {
  2221 		SDL_colors[j].peRed = colors[order[i]].r;
  2222 		SDL_colors[j].peGreen = colors[order[i]].g;
  2223 		SDL_colors[j].peBlue = colors[order[i]].b;
  2224 	}
  2225 #endif /* SIMPLE_COMPRESSION */
  2226 }
  2227 
  2228 /* Set the system colormap in both fullscreen and windowed modes */
  2229 int DX5_SetColors(_THIS, int firstcolor, int ncolors, SDL_Color *colors)
  2230 {
  2231 	int i;
  2232 	int alloct_all;
  2233 
  2234 	/* Copy palette colors into display palette */
  2235 	alloct_all = 0;
  2236 	if ( SDL_palette != NULL ) {
  2237 		if ( (this->screen->flags&SDL_FULLSCREEN) == SDL_FULLSCREEN ) {
  2238 			/* We can set all entries explicitly */
  2239 			for ( i=0; i< ncolors; ++i ) {
  2240 			        int j = firstcolor + i;
  2241 				SDL_colors[j].peRed = colors[i].r;
  2242 				SDL_colors[j].peGreen = colors[i].g;
  2243 				SDL_colors[j].peBlue = colors[i].b;
  2244 			}
  2245 			IDirectDrawPalette_SetEntries(SDL_palette, 0,
  2246 				firstcolor, ncolors, &SDL_colors[firstcolor]);
  2247 			alloct_all = 1;
  2248 		} else {
  2249 			/* Grab the 236 most diverse colors in the palette */
  2250 			DX5_CompressPalette(this, colors, ncolors, 236);
  2251 			/* This sends an WM_PALETTECHANGED message to us */
  2252 			colorchange_expected = 1;
  2253 			IDirectDrawPalette_SetEntries(SDL_palette, 0,
  2254 							0, 256, SDL_colors);
  2255 		}
  2256 	}
  2257 	return(alloct_all);
  2258 }
  2259 
  2260 /* Gamma code is only available on DirectX 7 and newer */
  2261 static int DX5_SetGammaRamp(_THIS, Uint16 *ramp)
  2262 {
  2263 #ifdef IDirectDrawGammaControl_SetGammaRamp
  2264 	LPDIRECTDRAWGAMMACONTROL gamma;
  2265 	DDGAMMARAMP gamma_ramp;
  2266 	HRESULT result;
  2267 #endif
  2268 
  2269 	/* In windowed or OpenGL mode, use windib gamma code */
  2270 	if ( ! DDRAW_FULLSCREEN() ) {
  2271 		return DIB_SetGammaRamp(this, ramp);
  2272 	}
  2273 
  2274 #ifndef IDirectDrawGammaControl_SetGammaRamp
  2275 	SDL_SetError("SDL compiled without DirectX gamma ramp support");
  2276 	return -1;
  2277 #else
  2278 	/* Check for a video mode! */
  2279 	if ( ! SDL_primary ) {
  2280 		SDL_SetError("A video mode must be set for gamma correction");
  2281 		return(-1);
  2282 	}
  2283 
  2284 	/* Get the gamma control object */
  2285 	result = IDirectDrawSurface3_QueryInterface(SDL_primary,
  2286 			&IID_IDirectDrawGammaControl, (LPVOID *)&gamma);
  2287 	if ( result != DD_OK ) {
  2288 		SetDDerror("DirectDrawSurface3::QueryInterface(GAMMA)", result);
  2289 		return(-1);
  2290 	}
  2291 
  2292 	/* Set up the gamma ramp */
  2293 	memcpy(gamma_ramp.red, &ramp[0*256], 256*sizeof(*ramp));
  2294 	memcpy(gamma_ramp.green, &ramp[1*256], 256*sizeof(*ramp));
  2295 	memcpy(gamma_ramp.blue, &ramp[2*256], 256*sizeof(*ramp));
  2296 	result = IDirectDrawGammaControl_SetGammaRamp(gamma, 0, &gamma_ramp);
  2297 	if ( result != DD_OK ) {
  2298 		SetDDerror("DirectDrawGammaControl::SetGammaRamp()", result);
  2299 	}
  2300 
  2301 	/* Release the interface and return */
  2302 	IDirectDrawGammaControl_Release(gamma);
  2303 	return (result == DD_OK) ? 0 : -1;
  2304 #endif /* !IDirectDrawGammaControl_SetGammaRamp */
  2305 }
  2306 
  2307 static int DX5_GetGammaRamp(_THIS, Uint16 *ramp)
  2308 {
  2309 #ifdef IDirectDrawGammaControl_SetGammaRamp
  2310 	LPDIRECTDRAWGAMMACONTROL gamma;
  2311 	DDGAMMARAMP gamma_ramp;
  2312 	HRESULT result;
  2313 #endif
  2314 
  2315 	/* In windowed or OpenGL mode, use windib gamma code */
  2316 	if ( ! DDRAW_FULLSCREEN() ) {
  2317 		return DIB_GetGammaRamp(this, ramp);
  2318 	}
  2319 
  2320 #ifndef IDirectDrawGammaControl_SetGammaRamp
  2321 	SDL_SetError("SDL compiled without DirectX gamma ramp support");
  2322 	return -1;
  2323 #else
  2324 	/* Check for a video mode! */
  2325 	if ( ! SDL_primary ) {
  2326 		SDL_SetError("A video mode must be set for gamma correction");
  2327 		return(-1);
  2328 	}
  2329 
  2330 	/* Get the gamma control object */
  2331 	result = IDirectDrawSurface3_QueryInterface(SDL_primary,
  2332 			&IID_IDirectDrawGammaControl, (LPVOID *)&gamma);
  2333 	if ( result != DD_OK ) {
  2334 		SetDDerror("DirectDrawSurface3::QueryInterface(GAMMA)", result);
  2335 		return(-1);
  2336 	}
  2337 
  2338 	/* Set up the gamma ramp */
  2339 	result = IDirectDrawGammaControl_GetGammaRamp(gamma, 0, &gamma_ramp);
  2340 	if ( result == DD_OK ) {
  2341 		memcpy(&ramp[0*256], gamma_ramp.red, 256*sizeof(*ramp));
  2342 		memcpy(&ramp[1*256], gamma_ramp.green, 256*sizeof(*ramp));
  2343 		memcpy(&ramp[2*256], gamma_ramp.blue, 256*sizeof(*ramp));
  2344 	} else {
  2345 		SetDDerror("DirectDrawGammaControl::GetGammaRamp()", result);
  2346 	}
  2347 
  2348 	/* Release the interface and return */
  2349 	IDirectDrawGammaControl_Release(gamma);
  2350 	return (result == DD_OK) ? 0 : -1;
  2351 #endif /* !IDirectDrawGammaControl_SetGammaRamp */
  2352 }
  2353 
  2354 static void FlushMessageQueue()
  2355 {
  2356 	MSG  msg;
  2357 	while ( PeekMessage(&msg, NULL, 0, 0, PM_REMOVE) ) {
  2358 		if ( msg.message == WM_QUIT ) break;
  2359 		TranslateMessage( &msg );
  2360 		DispatchMessage( &msg );
  2361 	}
  2362 }
  2363 
  2364 void DX5_VideoQuit(_THIS)
  2365 {
  2366 	int i, j;
  2367 
  2368 	/* If we're fullscreen GL, we need to reset the display */
  2369 	if ( this->screen != NULL ) {
  2370 #ifndef NO_CHANGEDISPLAYSETTINGS
  2371 		if ( (this->screen->flags & (SDL_OPENGL|SDL_FULLSCREEN)) ==
  2372 		                            (SDL_OPENGL|SDL_FULLSCREEN) ) {
  2373 			ChangeDisplaySettings(NULL, 0);
  2374 			ShowWindow(SDL_Window, SW_HIDE);
  2375 		}
  2376 #endif
  2377 		if ( this->screen->flags & SDL_OPENGL ) {
  2378 			WIN_GL_ShutDown(this);
  2379 		}
  2380 	}
  2381 
  2382 	/* Free any palettes we used */
  2383 	if ( SDL_palette != NULL ) {
  2384 		IDirectDrawPalette_Release(SDL_palette);
  2385 		SDL_palette = NULL;
  2386 	}
  2387 
  2388 	/* Allow the primary surface to be freed */
  2389 	if ( SDL_primary != NULL ) {
  2390 		SDL_primary = NULL;
  2391 	}
  2392 
  2393 	/* Free video mode lists */
  2394 	for ( i=0; i<NUM_MODELISTS; ++i ) {
  2395 		if ( SDL_modelist[i] != NULL ) {
  2396 			for ( j=0; SDL_modelist[i][j]; ++j )
  2397 				free(SDL_modelist[i][j]);
  2398 			free(SDL_modelist[i]);
  2399 			SDL_modelist[i] = NULL;
  2400 		}
  2401 	}
  2402 
  2403 	/* Free the window */
  2404 	DIB_QuitGamma(this);
  2405 	if ( SDL_Window ) {
  2406 		DX5_DestroyWindow(this);
  2407 		FlushMessageQueue();
  2408 	}
  2409 
  2410 	/* Free our window icon */
  2411 	if ( screen_icn ) {
  2412 		DestroyIcon(screen_icn);
  2413 		screen_icn = NULL;
  2414 	}
  2415 }
  2416 
  2417 /* Exported for the windows message loop only */
  2418 void DX5_RealizePalette(_THIS)
  2419 {
  2420 	if ( SDL_palette ) {
  2421 		IDirectDrawSurface3_SetPalette(SDL_primary, SDL_palette);
  2422 	}
  2423 }
  2424 static void DX5_Recolor8Bit(_THIS, SDL_Surface *surface, Uint8 *mapping)
  2425 {
  2426 	int row, col;
  2427 	Uint8 *pixels;
  2428 
  2429 	if ( surface->w && surface->h ) {
  2430 		if ( (surface->flags & SDL_HWSURFACE) == SDL_HWSURFACE ) {
  2431 			if ( this->LockHWSurface(this, surface) < 0 ) {
  2432 				return;
  2433 			}
  2434 		}
  2435 		for ( row=0; row<surface->h; ++row ) {
  2436 			pixels = (Uint8 *)surface->pixels+row*surface->pitch;
  2437 			for ( col=0; col<surface->w; ++col, ++pixels ) {
  2438 				*pixels = mapping[*pixels];
  2439 			}
  2440 		}
  2441 		if ( (surface->flags & SDL_HWSURFACE) == SDL_HWSURFACE ) {
  2442 			this->UnlockHWSurface(this, surface);
  2443 		}
  2444 		SDL_UpdateRect(surface, 0, 0, 0, 0);
  2445 	}
  2446 }
  2447 void DX5_PaletteChanged(_THIS, HWND window)
  2448 {
  2449 	SDL_Palette *palette;
  2450 	SDL_Color *saved = NULL;
  2451 	HDC hdc;
  2452 	int i;
  2453 	PALETTEENTRY *entries;
  2454 
  2455 	/* This is true when the window is closing */
  2456 	if ( (SDL_primary == NULL) || (SDL_VideoSurface == NULL) )
  2457 		return;
  2458 
  2459 	/* We need to get the colors as they were set */
  2460 	palette = this->physpal;
  2461 	if(!palette)
  2462 	        palette = SDL_VideoSurface->format->palette;
  2463 	if ( palette == NULL ) { /* Sometimes we don't have a palette */
  2464 		return;
  2465 	}
  2466 	entries = (PALETTEENTRY *)alloca(palette->ncolors*sizeof(*entries));
  2467 	hdc = GetDC(window);
  2468 	GetSystemPaletteEntries(hdc, 0, palette->ncolors, entries);
  2469 	ReleaseDC(window, hdc);
  2470 	if ( ! colorchange_expected ) {
  2471 		saved = (SDL_Color *)alloca(palette->ncolors*sizeof(SDL_Color));
  2472 		memcpy(saved, palette->colors, 
  2473 					palette->ncolors*sizeof(SDL_Color));
  2474 	}
  2475 	for ( i=0; i<palette->ncolors; ++i ) {
  2476 		palette->colors[i].r = entries[i].peRed;
  2477 		palette->colors[i].g = entries[i].peGreen;
  2478 		palette->colors[i].b = entries[i].peBlue;
  2479 	}
  2480 	if ( ! colorchange_expected ) {
  2481 		Uint8 mapping[256];
  2482 
  2483 		memset(mapping, 0, sizeof(mapping));
  2484 		for ( i=0; i<palette->ncolors; ++i ) {
  2485 			mapping[i] = SDL_FindColor(palette,
  2486 					saved[i].r, saved[i].g, saved[i].b);
  2487 		}
  2488 		DX5_Recolor8Bit(this, SDL_VideoSurface, mapping);
  2489 	}
  2490 	colorchange_expected = 0;
  2491 
  2492 	/* Notify all mapped surfaces of the change */
  2493 	SDL_FormatChanged(SDL_VideoSurface);
  2494 }
  2495 
  2496 /* Exported for the windows message loop only */
  2497 void DX5_WinPAINT(_THIS, HDC hdc)
  2498 {
  2499 	SDL_UpdateRect(SDL_PublicSurface, 0, 0, 0, 0);
  2500 }