1 /* DirectDrawClipper implementation
2 *
3 * Copyright 2000 (c) Marcus Meissner
4 * Copyright 2000 (c) TransGaming Technologies Inc.
5 * Copyright 2006 (c) Stefan Dösinger
6 *
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2.1 of the License, or (at your option) any later version.
11 *
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
16 *
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this library; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
20 */
21
22 #include "config.h"
23 #include "wine/port.h"
24
25 #include "ddraw_private.h"
26
27 WINE_DEFAULT_DEBUG_CHANNEL(ddraw);
28
impl_from_IDirectDrawClipper(IDirectDrawClipper * iface)29 static inline struct ddraw_clipper *impl_from_IDirectDrawClipper(IDirectDrawClipper *iface)
30 {
31 return CONTAINING_RECORD(iface, struct ddraw_clipper, IDirectDrawClipper_iface);
32 }
33
ddraw_clipper_QueryInterface(IDirectDrawClipper * iface,REFIID iid,void ** object)34 static HRESULT WINAPI ddraw_clipper_QueryInterface(IDirectDrawClipper *iface, REFIID iid, void **object)
35 {
36 struct ddraw_clipper *clipper = impl_from_IDirectDrawClipper(iface);
37
38 TRACE("iface %p, iid %s, object %p.\n", iface, debugstr_guid(iid), object);
39
40 if (IsEqualGUID(&IID_IDirectDrawClipper, iid)
41 || IsEqualGUID(&IID_IUnknown, iid))
42 {
43 IDirectDrawClipper_AddRef(&clipper->IDirectDrawClipper_iface);
44 *object = &clipper->IDirectDrawClipper_iface;
45 return S_OK;
46 }
47
48 WARN("%s not implemented, returning E_NOINTERFACE.\n", debugstr_guid(iid));
49 *object = NULL;
50
51 return E_NOINTERFACE;
52 }
53
ddraw_clipper_AddRef(IDirectDrawClipper * iface)54 static ULONG WINAPI ddraw_clipper_AddRef(IDirectDrawClipper *iface)
55 {
56 struct ddraw_clipper *clipper = impl_from_IDirectDrawClipper(iface);
57 ULONG refcount = InterlockedIncrement(&clipper->ref);
58
59 TRACE("%p increasing refcount to %u.\n", clipper, refcount);
60
61 return refcount;
62 }
63
ddraw_clipper_Release(IDirectDrawClipper * iface)64 static ULONG WINAPI ddraw_clipper_Release(IDirectDrawClipper *iface)
65 {
66 struct ddraw_clipper *clipper = impl_from_IDirectDrawClipper(iface);
67 ULONG refcount = InterlockedDecrement(&clipper->ref);
68
69 TRACE("%p decreasing refcount to %u.\n", clipper, refcount);
70
71 if (!refcount)
72 {
73 if (clipper->region)
74 DeleteObject(clipper->region);
75 heap_free(clipper);
76 }
77
78 return refcount;
79 }
80
ddraw_clipper_SetHWnd(IDirectDrawClipper * iface,DWORD flags,HWND window)81 static HRESULT WINAPI ddraw_clipper_SetHWnd(IDirectDrawClipper *iface, DWORD flags, HWND window)
82 {
83 struct ddraw_clipper *clipper = impl_from_IDirectDrawClipper(iface);
84
85 TRACE("iface %p, flags %#x, window %p.\n", iface, flags, window);
86
87 if (flags)
88 {
89 FIXME("flags %#x, not supported.\n", flags);
90 return DDERR_INVALIDPARAMS;
91 }
92
93 wined3d_mutex_lock();
94 clipper->window = window;
95 wined3d_mutex_unlock();
96
97 return DD_OK;
98 }
99
get_window_region(HWND window)100 static HRGN get_window_region(HWND window)
101 {
102 POINT origin;
103 HRGN rgn;
104 HDC dc;
105
106 if (!(dc = GetDC(window)))
107 {
108 WARN("Failed to get dc.\n");
109 return NULL;
110 }
111
112 if (!(rgn = CreateRectRgn(0, 0, 0, 0)))
113 {
114 ERR("Failed to create region.\n");
115 ReleaseDC(window, dc);
116 return NULL;
117 }
118
119 if (GetRandomRgn(dc, rgn, SYSRGN) != 1)
120 {
121 ERR("Failed to get window region.\n");
122 DeleteObject(rgn);
123 ReleaseDC(window, dc);
124 return NULL;
125 }
126
127 if (GetVersion() & 0x80000000)
128 {
129 GetDCOrgEx(dc, &origin);
130 OffsetRgn(rgn, origin.x, origin.y);
131 }
132
133 ReleaseDC(window, dc);
134 return rgn;
135 }
136
137 /*****************************************************************************
138 * IDirectDrawClipper::GetClipList
139 *
140 * Retrieve a copy of the clip list
141 *
142 * Arguments:
143 * rect: Rectangle to be used to clip the clip list or NULL for the
144 * entire clip list.
145 * clip_list: structure for the resulting copy of the clip list.
146 * If NULL, fills Size up to the number of bytes necessary to hold
147 * the entire clip.
148 * clip_list_size: Size of resulting clip list; size of the buffer at clip_list
149 * or, if clip_list is NULL, receives the required size of the buffer
150 * in bytes.
151 *
152 * RETURNS
153 * Either DD_OK or DDERR_*
154 ************************************************************************/
ddraw_clipper_GetClipList(IDirectDrawClipper * iface,RECT * rect,RGNDATA * clip_list,DWORD * clip_list_size)155 static HRESULT WINAPI ddraw_clipper_GetClipList(IDirectDrawClipper *iface, RECT *rect,
156 RGNDATA *clip_list, DWORD *clip_list_size)
157 {
158 struct ddraw_clipper *clipper = impl_from_IDirectDrawClipper(iface);
159 HRGN region;
160
161 TRACE("iface %p, rect %s, clip_list %p, clip_list_size %p.\n",
162 iface, wine_dbgstr_rect(rect), clip_list, clip_list_size);
163
164 wined3d_mutex_lock();
165
166 if (clipper->window)
167 {
168 if (!(region = get_window_region(clipper->window)))
169 {
170 wined3d_mutex_unlock();
171 WARN("Failed to get window region.\n");
172 return E_FAIL;
173 }
174 }
175 else
176 {
177 if (!(region = clipper->region))
178 {
179 wined3d_mutex_unlock();
180 WARN("No clip list set.\n");
181 return DDERR_NOCLIPLIST;
182 }
183 }
184
185 if (rect)
186 {
187 HRGN clip_region;
188
189 if (!(clip_region = CreateRectRgnIndirect(rect)))
190 {
191 wined3d_mutex_unlock();
192 ERR("Failed to create region.\n");
193 if (clipper->window)
194 DeleteObject(region);
195 return E_FAIL;
196 }
197
198 if (CombineRgn(clip_region, region, clip_region, RGN_AND) == ERROR)
199 {
200 wined3d_mutex_unlock();
201 ERR("Failed to combine regions.\n");
202 DeleteObject(clip_region);
203 if (clipper->window)
204 DeleteObject(region);
205 return E_FAIL;
206 }
207
208 if (clipper->window)
209 DeleteObject(region);
210 region = clip_region;
211 }
212
213 *clip_list_size = GetRegionData(region, *clip_list_size, clip_list);
214 if (rect || clipper->window)
215 DeleteObject(region);
216
217 wined3d_mutex_unlock();
218 return DD_OK;
219 }
220
221 /*****************************************************************************
222 * IDirectDrawClipper::SetClipList
223 *
224 * Sets or deletes (if region is NULL) the clip list
225 *
226 * This implementation is a stub and returns DD_OK always to make the app
227 * happy.
228 *
229 * PARAMS
230 * region Pointer to a LRGNDATA structure or NULL
231 * flags not used, must be 0
232 * RETURNS
233 * Either DD_OK or DDERR_*
234 *****************************************************************************/
ddraw_clipper_SetClipList(IDirectDrawClipper * iface,RGNDATA * region,DWORD flags)235 static HRESULT WINAPI ddraw_clipper_SetClipList(IDirectDrawClipper *iface, RGNDATA *region, DWORD flags)
236 {
237 struct ddraw_clipper *clipper = impl_from_IDirectDrawClipper(iface);
238
239 TRACE("iface %p, region %p, flags %#x.\n", iface, region, flags);
240
241 wined3d_mutex_lock();
242
243 if (clipper->window)
244 {
245 wined3d_mutex_unlock();
246 return DDERR_CLIPPERISUSINGHWND;
247 }
248
249 if (clipper->region)
250 DeleteObject(clipper->region);
251 if (!region)
252 clipper->region = NULL;
253 else if (!(clipper->region = ExtCreateRegion(NULL, 0, region)))
254 {
255 wined3d_mutex_unlock();
256 ERR("Failed to create region.\n");
257 return E_FAIL;
258 }
259
260 wined3d_mutex_unlock();
261
262 return DD_OK;
263 }
264
ddraw_clipper_GetHWnd(IDirectDrawClipper * iface,HWND * window)265 static HRESULT WINAPI ddraw_clipper_GetHWnd(IDirectDrawClipper *iface, HWND *window)
266 {
267 struct ddraw_clipper *clipper = impl_from_IDirectDrawClipper(iface);
268
269 TRACE("iface %p, window %p.\n", iface, window);
270
271 wined3d_mutex_lock();
272 *window = clipper->window;
273 wined3d_mutex_unlock();
274
275 return DD_OK;
276 }
277
ddraw_clipper_Initialize(IDirectDrawClipper * iface,IDirectDraw * ddraw,DWORD flags)278 static HRESULT WINAPI ddraw_clipper_Initialize(IDirectDrawClipper *iface,
279 IDirectDraw *ddraw, DWORD flags)
280 {
281 struct ddraw_clipper *clipper = impl_from_IDirectDrawClipper(iface);
282
283 TRACE("iface %p, ddraw %p, flags %#x.\n", iface, ddraw, flags);
284
285 wined3d_mutex_lock();
286 if (clipper->initialized)
287 {
288 wined3d_mutex_unlock();
289 return DDERR_ALREADYINITIALIZED;
290 }
291
292 clipper->initialized = TRUE;
293 wined3d_mutex_unlock();
294
295 return DD_OK;
296 }
297
ddraw_clipper_IsClipListChanged(IDirectDrawClipper * iface,BOOL * changed)298 static HRESULT WINAPI ddraw_clipper_IsClipListChanged(IDirectDrawClipper *iface, BOOL *changed)
299 {
300 FIXME("iface %p, changed %p stub!\n", iface, changed);
301
302 /* XXX What is safest? */
303 *changed = FALSE;
304
305 return DD_OK;
306 }
307
308 static const struct IDirectDrawClipperVtbl ddraw_clipper_vtbl =
309 {
310 ddraw_clipper_QueryInterface,
311 ddraw_clipper_AddRef,
312 ddraw_clipper_Release,
313 ddraw_clipper_GetClipList,
314 ddraw_clipper_GetHWnd,
315 ddraw_clipper_Initialize,
316 ddraw_clipper_IsClipListChanged,
317 ddraw_clipper_SetClipList,
318 ddraw_clipper_SetHWnd,
319 };
320
ddraw_clipper_init(struct ddraw_clipper * clipper)321 HRESULT ddraw_clipper_init(struct ddraw_clipper *clipper)
322 {
323 clipper->IDirectDrawClipper_iface.lpVtbl = &ddraw_clipper_vtbl;
324 clipper->ref = 1;
325
326 return DD_OK;
327 }
328
unsafe_impl_from_IDirectDrawClipper(IDirectDrawClipper * iface)329 struct ddraw_clipper *unsafe_impl_from_IDirectDrawClipper(IDirectDrawClipper *iface)
330 {
331 if (!iface)
332 return NULL;
333 assert(iface->lpVtbl == &ddraw_clipper_vtbl);
334
335 return impl_from_IDirectDrawClipper(iface);
336 }
337