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