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