clipper.c 8.97 KB
Newer Older
1
/* DirectDrawClipper implementation
2
 *
3 4
 * Copyright 2000 (c) Marcus Meissner
 * Copyright 2000 (c) TransGaming Technologies Inc.
5
 * Copyright 2006 (c) Stefan Dösinger
6 7 8 9 10 11 12 13 14 15 16 17 18
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * 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 26
#include "ddraw_private.h"

27
WINE_DEFAULT_DEBUG_CHANNEL(ddraw);
28

29
static inline struct ddraw_clipper *impl_from_IDirectDrawClipper(IDirectDrawClipper *iface)
30
{
31
    return CONTAINING_RECORD(iface, struct ddraw_clipper, IDirectDrawClipper_iface);
32
}
33

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 41
    if (IsEqualGUID(&IID_IDirectDrawClipper, iid)
            || IsEqualGUID(&IID_IUnknown, iid))
42
    {
43 44
        IDirectDrawClipper_AddRef(&clipper->IDirectDrawClipper_iface);
        *object = &clipper->IDirectDrawClipper_iface;
45
        return S_OK;
46
    }
47

48 49 50
    WARN("%s not implemented, returning E_NOINTERFACE.\n", debugstr_guid(iid));
    *object = NULL;

51
    return E_NOINTERFACE;
52
}
53

54
static ULONG WINAPI ddraw_clipper_AddRef(IDirectDrawClipper *iface)
55
{
56 57
    struct ddraw_clipper *clipper = impl_from_IDirectDrawClipper(iface);
    ULONG refcount = InterlockedIncrement(&clipper->ref);
58

59
    TRACE("%p increasing refcount to %u.\n", clipper, refcount);
60

61
    return refcount;
62 63
}

64
static ULONG WINAPI ddraw_clipper_Release(IDirectDrawClipper *iface)
65
{
66 67
    struct ddraw_clipper *clipper = impl_from_IDirectDrawClipper(iface);
    ULONG refcount = InterlockedDecrement(&clipper->ref);
68

69
    TRACE("%p decreasing refcount to %u.\n", clipper, refcount);
70

71
    if (!refcount)
72 73 74
    {
        if (clipper->region)
            DeleteObject(clipper->region);
75
        HeapFree(GetProcessHeap(), 0, clipper);
76
    }
77

78 79
    return refcount;
}
80

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 86 87 88 89 90 91
    TRACE("iface %p, flags %#x, window %p.\n", iface, flags, window);

    if (flags)
    {
        FIXME("flags %#x, not supported.\n", flags);
        return DDERR_INVALIDPARAMS;
    }
92

93
    wined3d_mutex_lock();
94
    clipper->window = window;
95 96
    wined3d_mutex_unlock();

97
    return DD_OK;
98 99
}

100 101
static HRGN get_window_region(HWND window)
{
102 103 104
    POINT origin;
    HRGN rgn;
    HDC dc;
105

106
    if (!(dc = GetDC(window)))
107
    {
108
        WARN("Failed to get dc.\n");
109 110 111
        return NULL;
    }

112
    if (!(rgn = CreateRectRgn(0, 0, 0, 0)))
113
    {
114 115
        ERR("Failed to create region.\n");
        ReleaseDC(window, dc);
116 117 118
        return NULL;
    }

119
    if (GetRandomRgn(dc, rgn, SYSRGN) != 1)
120
    {
121 122 123
        ERR("Failed to get window region.\n");
        DeleteObject(rgn);
        ReleaseDC(window, dc);
124 125 126
        return NULL;
    }

127 128 129 130 131 132
    if (GetVersion() & 0x80000000)
    {
        GetDCOrgEx(dc, &origin);
        OffsetRgn(rgn, origin.x, origin.y);
    }

133
    ReleaseDC(window, dc);
134
    return rgn;
135 136
}

137 138 139 140 141 142
/*****************************************************************************
 * IDirectDrawClipper::GetClipList
 *
 * Retrieve a copy of the clip list
 *
 * Arguments:
143 144 145 146 147 148 149 150
 *  rect: Rectangle to be used to clip the clip list or NULL for the
 *      entire clip list.
 *  clip_list: structure for the resulting copy of the clip list.
 *      If NULL, fills Size up to the number of bytes necessary to hold
 *      the entire clip.
 *  clip_list_size: Size of resulting clip list; size of the buffer at clip_list
 *      or, if clip_list is NULL, receives the required size of the buffer
 *      in bytes.
151 152 153 154
 *
 * RETURNS
 *  Either DD_OK or DDERR_*
 ************************************************************************/
155 156
static HRESULT WINAPI ddraw_clipper_GetClipList(IDirectDrawClipper *iface, RECT *rect,
        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 165
    wined3d_mutex_lock();

166 167
    if (clipper->window)
    {
168 169 170
        if (!(region = get_window_region(clipper->window)))
        {
            wined3d_mutex_unlock();
171
            WARN("Failed to get window region.\n");
172 173
            return E_FAIL;
        }
174 175 176 177
    }
    else
    {
        if (!(region = clipper->region))
178
        {
179 180 181 182 183
            wined3d_mutex_unlock();
            WARN("No clip list set.\n");
            return DDERR_NOCLIPLIST;
        }
    }
184

185 186 187 188 189 190 191 192 193
    if (rect)
    {
        HRGN clip_region;

        if (!(clip_region = CreateRectRgnIndirect(rect)))
        {
            wined3d_mutex_unlock();
            ERR("Failed to create region.\n");
            if (clipper->window)
194
                DeleteObject(region);
195 196
            return E_FAIL;
        }
197

198 199 200 201
        if (CombineRgn(clip_region, region, clip_region, RGN_AND) == ERROR)
        {
            wined3d_mutex_unlock();
            ERR("Failed to combine regions.\n");
202
            DeleteObject(clip_region);
203
            if (clipper->window)
204
                DeleteObject(region);
205
            return E_FAIL;
206 207
        }

208 209
        if (clipper->window)
            DeleteObject(region);
210
        region = clip_region;
211 212
    }

213 214 215
    *clip_list_size = GetRegionData(region, *clip_list_size, clip_list);
    if (rect || clipper->window)
        DeleteObject(region);
216 217

    wined3d_mutex_unlock();
218
    return DD_OK;
219 220
}

221 222 223
/*****************************************************************************
 * IDirectDrawClipper::SetClipList
 *
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 228 229
 * happy.
 *
 * PARAMS
230 231
 *  region  Pointer to a LRGNDATA structure or NULL
 *  flags   not used, must be 0
232 233 234
 * RETURNS
 *  Either DD_OK or DDERR_*
 *****************************************************************************/
235
static HRESULT WINAPI ddraw_clipper_SetClipList(IDirectDrawClipper *iface, RGNDATA *region, DWORD flags)
236
{
237 238
    struct ddraw_clipper *clipper = impl_from_IDirectDrawClipper(iface);

239 240 241
    TRACE("iface %p, region %p, flags %#x.\n", iface, region, flags);

    wined3d_mutex_lock();
242

243
    if (clipper->window)
244 245
    {
        wined3d_mutex_unlock();
246
        return DDERR_CLIPPERISUSINGHWND;
247 248 249 250
    }

    if (clipper->region)
        DeleteObject(clipper->region);
251 252 253
    if (!region)
        clipper->region = NULL;
    else if (!(clipper->region = ExtCreateRegion(NULL, 0, region)))
254 255
    {
        wined3d_mutex_unlock();
256
        ERR("Failed to create region.\n");
257 258 259 260
        return E_FAIL;
    }

    wined3d_mutex_unlock();
261

262
    return DD_OK;
263 264
}

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 274
    wined3d_mutex_unlock();

275
    return DD_OK;
276 277
}

278 279
static HRESULT WINAPI ddraw_clipper_Initialize(IDirectDrawClipper *iface,
        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 290
        return DDERR_ALREADYINITIALIZED;
    }
291

292
    clipper->initialized = TRUE;
293
    wined3d_mutex_unlock();
294

295 296 297
    return DD_OK;
}

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 306 307
    return DD_OK;
}

308
static const struct IDirectDrawClipperVtbl ddraw_clipper_vtbl =
309
{
310 311 312 313 314 315 316 317 318
    ddraw_clipper_QueryInterface,
    ddraw_clipper_AddRef,
    ddraw_clipper_Release,
    ddraw_clipper_GetClipList,
    ddraw_clipper_GetHWnd,
    ddraw_clipper_Initialize,
    ddraw_clipper_IsClipListChanged,
    ddraw_clipper_SetClipList,
    ddraw_clipper_SetHWnd,
319
};
320

321
HRESULT ddraw_clipper_init(struct ddraw_clipper *clipper)
322
{
323
    clipper->IDirectDrawClipper_iface.lpVtbl = &ddraw_clipper_vtbl;
324 325 326 327
    clipper->ref = 1;

    return DD_OK;
}
328

329
struct ddraw_clipper *unsafe_impl_from_IDirectDrawClipper(IDirectDrawClipper *iface)
330 331 332 333 334 335 336
{
    if (!iface)
        return NULL;
    assert(iface->lpVtbl == &ddraw_clipper_vtbl);

    return impl_from_IDirectDrawClipper(iface);
}