device.c 220 KB
Newer Older
1 2 3
/*
 * Copyright (c) 1998-2004 Lionel Ulmer
 * Copyright (c) 2002-2005 Christian Costa
4
 * Copyright (c) 2006 Stefan Dösinger
5
 * Copyright (c) 2008 Alexander Dorofeyev
6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34
 *
 * 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
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
 *
 * IDirect3DDevice implementation, version 1, 2, 3 and 7. Rendering is relayed
 * to WineD3D, some minimal DirectDraw specific management is handled here.
 * The Direct3DDevice is NOT the parent of the WineD3DDevice, because d3d
 * is initialized when DirectDraw creates the primary surface.
 * Some type management is necessary, because some D3D types changed between
 * D3D7 and D3D9.
 *
 */

#include "config.h"
#include "wine/port.h"

#include "ddraw_private.h"

35
WINE_DEFAULT_DEBUG_CHANNEL(ddraw);
36
WINE_DECLARE_DEBUG_CHANNEL(winediag);
37 38 39 40 41 42 43 44 45

/* The device ID */
const GUID IID_D3DDEVICE_WineD3D = {
  0xaef72d43,
  0xb09a,
  0x4b7b,
  { 0xb7,0x98,0xc6,0x8a,0x77,0x2d,0x72,0x2a }
};

46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69
static inline void set_fpu_control_word(WORD fpucw)
{
#if defined(__i386__) && defined(__GNUC__)
    __asm__ volatile ("fldcw %0" : : "m" (fpucw));
#elif defined(__i386__) && defined(_MSC_VER)
    __asm fldcw fpucw;
#endif
}

static inline WORD d3d_fpu_setup(void)
{
    WORD oldcw;

#if defined(__i386__) && defined(__GNUC__)
    __asm__ volatile ("fnstcw %0" : "=m" (oldcw));
#elif defined(__i386__) && defined(_MSC_VER)
    __asm fnstcw oldcw;
#else
    static BOOL warned = FALSE;
    if(!warned)
    {
        FIXME("FPUPRESERVE not implemented for this platform / compiler\n");
        warned = TRUE;
    }
70
    return 0;
71 72 73 74 75 76 77
#endif

    set_fpu_control_word(0x37f);

    return oldcw;
}

78
static inline struct d3d_device *impl_from_IUnknown(IUnknown *iface)
79
{
80
    return CONTAINING_RECORD(iface, struct d3d_device, IUnknown_inner);
81
}
82

83 84
static HRESULT WINAPI d3d_device_inner_QueryInterface(IUnknown *iface, REFIID riid, void **out)
{
85
    struct d3d_device *device = impl_from_IUnknown(iface);
86

87
    TRACE("iface %p, riid %s, out %p.\n", iface, debugstr_guid(riid), out);
88

89 90 91
    if (!riid)
    {
        *out = NULL;
92
        return DDERR_INVALIDPARAMS;
93
    }
94

95
    if (IsEqualGUID(&IID_IUnknown, riid))
96
    {
97 98 99
        IDirect3DDevice7_AddRef(&device->IDirect3DDevice7_iface);
        *out = &device->IDirect3DDevice7_iface;
        return S_OK;
100 101
    }

102
    if (device->version == 7)
103
    {
104 105 106 107 108 109
        if (IsEqualGUID(&IID_IDirect3DDevice7, riid))
        {
            IDirect3DDevice7_AddRef(&device->IDirect3DDevice7_iface);
            *out = &device->IDirect3DDevice7_iface;
            return S_OK;
        }
110 111 112
    }
    else
    {
113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132
        if (IsEqualGUID(&IID_IDirect3DDevice3, riid) && device->version == 3)
        {
            IDirect3DDevice3_AddRef(&device->IDirect3DDevice3_iface);
            *out = &device->IDirect3DDevice3_iface;
            return S_OK;
        }

        if (IsEqualGUID(&IID_IDirect3DDevice2, riid) && device->version >= 2)
        {
            IDirect3DDevice2_AddRef(&device->IDirect3DDevice2_iface);
            *out = &device->IDirect3DDevice2_iface;
            return S_OK;
        }

        if (IsEqualGUID(&IID_IDirect3DDevice, riid))
        {
            IDirect3DDevice_AddRef(&device->IDirect3DDevice_iface);
            *out = &device->IDirect3DDevice_iface;
            return S_OK;
        }
133 134
    }

135 136 137 138
    WARN("%s not implemented, returning E_NOINTERFACE.\n", debugstr_guid(riid));

    *out = NULL;
    return E_NOINTERFACE;
139 140
}

141
static HRESULT WINAPI d3d_device7_QueryInterface(IDirect3DDevice7 *iface, REFIID riid, void **out)
142
{
143
    struct d3d_device *device = impl_from_IDirect3DDevice7(iface);
144

145 146 147
    TRACE("iface %p, riid %s, out %p.\n", iface, debugstr_guid(riid), out);

    return IUnknown_QueryInterface(device->outer_unknown, riid, out);
148 149
}

150
static HRESULT WINAPI d3d_device3_QueryInterface(IDirect3DDevice3 *iface, REFIID riid, void **out)
151
{
152
    struct d3d_device *device = impl_from_IDirect3DDevice3(iface);
153

154 155 156
    TRACE("iface %p, riid %s, out %p.\n", iface, debugstr_guid(riid), out);

    return IUnknown_QueryInterface(device->outer_unknown, riid, out);
157 158
}

159
static HRESULT WINAPI d3d_device2_QueryInterface(IDirect3DDevice2 *iface, REFIID riid, void **out)
160
{
161
    struct d3d_device *device = impl_from_IDirect3DDevice2(iface);
162 163

    TRACE("iface %p, riid %s, out %p.\n", iface, debugstr_guid(riid), out);
164

165
    return IUnknown_QueryInterface(device->outer_unknown, riid, out);
166 167
}

168
static HRESULT WINAPI d3d_device1_QueryInterface(IDirect3DDevice *iface, REFIID riid, void **out)
169
{
170
    struct d3d_device *device = impl_from_IDirect3DDevice(iface);
171

172 173 174 175 176 177 178
    TRACE("iface %p, riid %s, out %p.\n", iface, debugstr_guid(riid), out);

    return IUnknown_QueryInterface(device->outer_unknown, riid, out);
}

static ULONG WINAPI d3d_device_inner_AddRef(IUnknown *iface)
{
179
    struct d3d_device *device = impl_from_IUnknown(iface);
180 181 182
    ULONG ref = InterlockedIncrement(&device->ref);

    TRACE("%p increasing refcount to %u.\n", device, ref);
183 184 185 186

    return ref;
}

187
static ULONG WINAPI d3d_device7_AddRef(IDirect3DDevice7 *iface)
188
{
189
    struct d3d_device *device = impl_from_IDirect3DDevice7(iface);
190 191 192 193 194 195

    TRACE("iface %p.\n", iface);

    return IUnknown_AddRef(device->outer_unknown);
}

196
static ULONG WINAPI d3d_device3_AddRef(IDirect3DDevice3 *iface)
197
{
198
    struct d3d_device *device = impl_from_IDirect3DDevice3(iface);
199

200 201
    TRACE("iface %p.\n", iface);

202
    return IUnknown_AddRef(device->outer_unknown);
203 204
}

205
static ULONG WINAPI d3d_device2_AddRef(IDirect3DDevice2 *iface)
206
{
207
    struct d3d_device *device = impl_from_IDirect3DDevice2(iface);
208

209 210
    TRACE("iface %p.\n", iface);

211
    return IUnknown_AddRef(device->outer_unknown);
212 213
}

214
static ULONG WINAPI d3d_device1_AddRef(IDirect3DDevice *iface)
215
{
216
    struct d3d_device *device = impl_from_IDirect3DDevice(iface);
217

218 219
    TRACE("iface %p.\n", iface);

220
    return IUnknown_AddRef(device->outer_unknown);
221 222
}

223
static ULONG WINAPI d3d_device_inner_Release(IUnknown *iface)
224
{
225
    struct d3d_device *This = impl_from_IUnknown(iface);
226 227
    ULONG ref = InterlockedDecrement(&This->ref);

228
    TRACE("%p decreasing refcount to %u.\n", This, ref);
229

230 231 232 233
    /* This method doesn't destroy the wined3d device, because it's still in
     * use for 2D rendering. IDirectDrawSurface7::Release will destroy the
     * wined3d device when the render target is released. */
    if (!ref)
234
    {
235 236
        DWORD i;

237
        wined3d_mutex_lock();
238 239

        /* There is no need to unset any resources here, wined3d will take
240
         * care of that on uninit_3d(). */
241

242
        /* Free the index buffer. */
243
        wined3d_buffer_decref(This->indexbuffer);
244

245 246
        /* Set the device up to render to the front buffer since the back
         * buffer will vanish soon. */
247
        wined3d_device_set_render_target(This->wined3d_device, 0,
248
                This->ddraw->wined3d_frontbuffer, TRUE);
249

250
        /* Release the wined3d device. This won't destroy it. */
251 252
        if (!wined3d_device_decref(This->wined3d_device))
            ERR("The wined3d device (%p) was destroyed unexpectedly.\n", This->wined3d_device);
253

254
        /* The texture handles should be unset by now, but there might be some bits
255
         * missing in our reference counting(needs test). Do a sanity check. */
256 257 258 259 260 261 262 263 264 265 266
        for (i = 0; i < This->handle_table.entry_count; ++i)
        {
            struct ddraw_handle_entry *entry = &This->handle_table.entries[i];

            switch (entry->type)
            {
                case DDRAW_HANDLE_FREE:
                    break;

                case DDRAW_HANDLE_MATERIAL:
                {
267
                    struct d3d_material *m = entry->object;
268 269 270 271 272
                    FIXME("Material handle %#x (%p) not unset properly.\n", i + 1, m);
                    m->Handle = 0;
                    break;
                }

273 274 275 276
                case DDRAW_HANDLE_MATRIX:
                {
                    /* No FIXME here because this might happen because of sloppy applications. */
                    WARN("Leftover matrix handle %#x (%p), deleting.\n", i + 1, entry->object);
277
                    IDirect3DDevice_DeleteMatrix(&This->IDirect3DDevice_iface, i + 1);
278 279 280
                    break;
                }

281 282 283 284
                case DDRAW_HANDLE_STATEBLOCK:
                {
                    /* No FIXME here because this might happen because of sloppy applications. */
                    WARN("Leftover stateblock handle %#x (%p), deleting.\n", i + 1, entry->object);
285
                    IDirect3DDevice7_DeleteStateBlock(&This->IDirect3DDevice7_iface, i + 1);
286 287 288
                    break;
                }

289 290
                case DDRAW_HANDLE_SURFACE:
                {
291
                    struct ddraw_surface *surf = entry->object;
292 293 294 295 296
                    FIXME("Texture handle %#x (%p) not unset properly.\n", i + 1, surf);
                    surf->Handle = 0;
                    break;
                }

297 298 299 300 301 302 303 304
                default:
                    FIXME("Handle %#x (%p) has unknown type %#x.\n", i + 1, entry->object, entry->type);
                    break;
            }
        }

        ddraw_handle_table_destroy(&This->handle_table);

305
        TRACE("Releasing target %p.\n", This->target);
306 307 308
        /* Release the render target. */
        if (This->version != 1)
            IDirectDrawSurface7_Release(&This->target->IDirectDrawSurface7_iface);
309
        TRACE("Target release done\n");
310 311 312 313 314

        This->ddraw->d3ddevice = NULL;

        /* Now free the structure */
        HeapFree(GetProcessHeap(), 0, This);
315
        wined3d_mutex_unlock();
316 317
    }

318
    TRACE("Done\n");
319 320 321
    return ref;
}

322
static ULONG WINAPI d3d_device7_Release(IDirect3DDevice7 *iface)
323
{
324
    struct d3d_device *device = impl_from_IDirect3DDevice7(iface);
325 326 327 328 329 330

    TRACE("iface %p.\n", iface);

    return IUnknown_Release(device->outer_unknown);
}

331
static ULONG WINAPI d3d_device3_Release(IDirect3DDevice3 *iface)
332
{
333
    struct d3d_device *device = impl_from_IDirect3DDevice3(iface);
334

335 336
    TRACE("iface %p.\n", iface);

337
    return IUnknown_Release(device->outer_unknown);
338 339
}

340
static ULONG WINAPI d3d_device2_Release(IDirect3DDevice2 *iface)
341
{
342
    struct d3d_device *device = impl_from_IDirect3DDevice2(iface);
343

344 345
    TRACE("iface %p.\n", iface);

346
    return IUnknown_Release(device->outer_unknown);
347 348
}

349
static ULONG WINAPI d3d_device1_Release(IDirect3DDevice *iface)
350
{
351
    struct d3d_device *device = impl_from_IDirect3DDevice(iface);
352

353 354
    TRACE("iface %p.\n", iface);

355
    return IUnknown_Release(device->outer_unknown);
356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375
}

/*****************************************************************************
 * IDirect3DDevice Methods
 *****************************************************************************/

/*****************************************************************************
 * IDirect3DDevice::Initialize
 *
 * Initializes a Direct3DDevice. This implementation is a no-op, as all
 * initialization is done at create time.
 *
 * Exists in Version 1
 *
 * Parameters:
 *  No idea what they mean, as the MSDN page is gone
 *
 * Returns: DD_OK
 *
 *****************************************************************************/
376 377
static HRESULT WINAPI d3d_device1_Initialize(IDirect3DDevice *iface,
        IDirect3D *d3d, GUID *guid, D3DDEVICEDESC *device_desc)
378 379
{
    /* It shouldn't be crucial, but print a FIXME, I'm interested if
380 381
     * any game calls it and when. */
    FIXME("iface %p, d3d %p, guid %s, device_desc %p nop!\n",
382
            iface, d3d, debugstr_guid(guid), device_desc);
383 384 385 386 387 388 389

    return D3D_OK;
}

/*****************************************************************************
 * IDirect3DDevice7::GetCaps
 *
390
 * Retrieves the device's capabilities
391 392 393 394 395 396 397 398 399 400 401 402
 *
 * This implementation is used for Version 7 only, the older versions have
 * their own implementation.
 *
 * Parameters:
 *  Desc: Pointer to a D3DDEVICEDESC7 structure to fill
 *
 * Returns:
 *  D3D_OK on success
 *  D3DERR_* if a problem occurs. See WineD3D
 *
 *****************************************************************************/
403
static HRESULT d3d_device7_GetCaps(IDirect3DDevice7 *iface, D3DDEVICEDESC7 *Desc)
404
{
405
    struct d3d_device *device = impl_from_IDirect3DDevice7(iface);
406
    D3DDEVICEDESC OldDesc;
407 408

    TRACE("iface %p, device_desc %p.\n", iface, Desc);
409

410 411 412 413 414 415
    if (!Desc)
    {
        WARN("Desc is NULL, returning DDERR_INVALIDPARAMS.\n");
        return DDERR_INVALIDPARAMS;
    }

416
    /* Call the same function used by IDirect3D, this saves code */
417
    return IDirect3DImpl_GetCaps(device->ddraw->wined3d, &OldDesc, Desc);
418 419
}

420
static HRESULT WINAPI d3d_device7_GetCaps_FPUSetup(IDirect3DDevice7 *iface, D3DDEVICEDESC7 *desc)
421
{
422
    return d3d_device7_GetCaps(iface, desc);
423 424
}

425
static HRESULT WINAPI d3d_device7_GetCaps_FPUPreserve(IDirect3DDevice7 *iface, D3DDEVICEDESC7 *desc)
426 427 428 429 430
{
    HRESULT hr;
    WORD old_fpucw;

    old_fpucw = d3d_fpu_setup();
431
    hr = d3d_device7_GetCaps(iface, desc);
432 433 434 435
    set_fpu_control_word(old_fpucw);

    return hr;
}
436 437 438
/*****************************************************************************
 * IDirect3DDevice3::GetCaps
 *
439 440
 * Retrieves the capabilities of the hardware device and the emulation
 * device. For Wine, hardware and emulation are the same (it's all HW).
441 442 443 444 445
 *
 * This implementation is used for Version 1, 2, and 3. Version 7 has its own
 *
 * Parameters:
 *  HWDesc: Structure to fill with the HW caps
Austin English's avatar
Austin English committed
446
 *  HelDesc: Structure to fill with the hardware emulation caps
447 448 449 450 451 452
 *
 * Returns:
 *  D3D_OK on success
 *  D3DERR_* if a problem occurs. See WineD3D
 *
 *****************************************************************************/
453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474

/* There are 3 versions of D3DDEVICEDESC. All 3 share the same name because
 * Microsoft just expanded the existing structure without naming them
 * D3DDEVICEDESC2 and D3DDEVICEDESC3. Which version is used have depends
 * on the version of the DirectX SDK. DirectX 6+ and Wine use the latest
 * one with 252 bytes.
 *
 * All 3 versions are allowed as parameters and only the specified amount of
 * bytes is written.
 *
 * Note that Direct3D7 and earlier are not available in native Win64
 * ddraw.dll builds, so possible size differences between 32 bit and
 * 64 bit are a non-issue.
 */
static inline BOOL check_d3ddevicedesc_size(DWORD size)
{
    if (size == FIELD_OFFSET(D3DDEVICEDESC, dwMinTextureWidth) /* 172 */
            || size == FIELD_OFFSET(D3DDEVICEDESC, dwMaxTextureRepeat) /* 204 */
            || size == sizeof(D3DDEVICEDESC) /* 252 */) return TRUE;
    return FALSE;
}

475 476
static HRESULT WINAPI d3d_device3_GetCaps(IDirect3DDevice3 *iface,
        D3DDEVICEDESC *HWDesc, D3DDEVICEDESC *HelDesc)
477
{
478
    struct d3d_device *device = impl_from_IDirect3DDevice3(iface);
479
    D3DDEVICEDESC oldDesc;
480 481
    D3DDEVICEDESC7 newDesc;
    HRESULT hr;
482 483

    TRACE("iface %p, hw_desc %p, hel_desc %p.\n", iface, HWDesc, HelDesc);
484

485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505
    if (!HWDesc)
    {
        WARN("HWDesc is NULL, returning DDERR_INVALIDPARAMS.\n");
        return DDERR_INVALIDPARAMS;
    }
    if (!check_d3ddevicedesc_size(HWDesc->dwSize))
    {
        WARN("HWDesc->dwSize is %u, returning DDERR_INVALIDPARAMS.\n", HWDesc->dwSize);
        return DDERR_INVALIDPARAMS;
    }
    if (!HelDesc)
    {
        WARN("HelDesc is NULL, returning DDERR_INVALIDPARAMS.\n");
        return DDERR_INVALIDPARAMS;
    }
    if (!check_d3ddevicedesc_size(HelDesc->dwSize))
    {
        WARN("HelDesc->dwSize is %u, returning DDERR_INVALIDPARAMS.\n", HelDesc->dwSize);
        return DDERR_INVALIDPARAMS;
    }

506 507 508
    hr = IDirect3DImpl_GetCaps(device->ddraw->wined3d, &oldDesc, &newDesc);
    if (hr != D3D_OK)
        return hr;
509

510 511
    DD_STRUCT_COPY_BYSIZE(HWDesc, &oldDesc);
    DD_STRUCT_COPY_BYSIZE(HelDesc, &oldDesc);
512 513 514
    return D3D_OK;
}

515 516
static HRESULT WINAPI d3d_device2_GetCaps(IDirect3DDevice2 *iface,
        D3DDEVICEDESC *hw_desc, D3DDEVICEDESC *hel_desc)
517
{
518 519 520 521 522
    struct d3d_device *device = impl_from_IDirect3DDevice2(iface);

    TRACE("iface %p, hw_desc %p, hel_desc %p.\n", iface, hw_desc, hel_desc);

    return d3d_device3_GetCaps(&device->IDirect3DDevice3_iface, hw_desc, hel_desc);
523 524
}

525 526
static HRESULT WINAPI d3d_device1_GetCaps(IDirect3DDevice *iface,
        D3DDEVICEDESC *hw_desc, D3DDEVICEDESC *hel_desc)
527
{
528 529 530 531 532
    struct d3d_device *device = impl_from_IDirect3DDevice(iface);

    TRACE("iface %p, hw_desc %p, hel_desc %p.\n", iface, hw_desc, hel_desc);

    return d3d_device3_GetCaps(&device->IDirect3DDevice3_iface, hw_desc, hel_desc);
533 534 535 536 537 538 539 540 541 542 543 544 545 546
}

/*****************************************************************************
 * IDirect3DDevice2::SwapTextureHandles
 *
 * Swaps the texture handles of 2 Texture interfaces. Version 1 and 2
 *
 * Parameters:
 *  Tex1, Tex2: The 2 Textures to swap
 *
 * Returns:
 *  D3D_OK
 *
 *****************************************************************************/
547 548 549 550 551 552
static HRESULT WINAPI d3d_device2_SwapTextureHandles(IDirect3DDevice2 *iface,
        IDirect3DTexture2 *tex1, IDirect3DTexture2 *tex2)
{
    struct d3d_device *device = impl_from_IDirect3DDevice2(iface);
    struct ddraw_surface *surf1 = unsafe_impl_from_IDirect3DTexture2(tex1);
    struct ddraw_surface *surf2 = unsafe_impl_from_IDirect3DTexture2(tex2);
553 554
    DWORD h1, h2;

555
    TRACE("iface %p, tex1 %p, tex2 %p.\n", iface, tex1, tex2);
556

557
    wined3d_mutex_lock();
558

559 560
    h1 = surf1->Handle - 1;
    h2 = surf2->Handle - 1;
561 562
    device->handle_table.entries[h1].object = surf2;
    device->handle_table.entries[h2].object = surf1;
563 564 565
    surf2->Handle = h1 + 1;
    surf1->Handle = h2 + 1;

566
    wined3d_mutex_unlock();
567 568 569 570

    return D3D_OK;
}

571 572
static HRESULT WINAPI d3d_device1_SwapTextureHandles(IDirect3DDevice *iface,
        IDirect3DTexture *tex1, IDirect3DTexture *tex2)
573
{
574 575 576
    struct d3d_device *device = impl_from_IDirect3DDevice(iface);
    struct ddraw_surface *surf1 = unsafe_impl_from_IDirect3DTexture(tex1);
    struct ddraw_surface *surf2 = unsafe_impl_from_IDirect3DTexture(tex2);
577 578
    IDirect3DTexture2 *t1 = surf1 ? &surf1->IDirect3DTexture2_iface : NULL;
    IDirect3DTexture2 *t2 = surf2 ? &surf2->IDirect3DTexture2_iface : NULL;
579

580
    TRACE("iface %p, tex1 %p, tex2 %p.\n", iface, tex1, tex2);
581

582
    return d3d_device2_SwapTextureHandles(&device->IDirect3DDevice2_iface, t1, t2);
583 584 585 586 587 588 589
}

/*****************************************************************************
 * IDirect3DDevice3::GetStats
 *
 * This method seems to retrieve some stats from the device.
 * The MSDN documentation doesn't exist any more, but the D3DSTATS
590
 * structure suggests that the amount of drawn primitives and processed
591 592 593 594 595 596 597 598 599 600 601 602
 * vertices is returned.
 *
 * Exists in Version 1, 2 and 3
 *
 * Parameters:
 *  Stats: Pointer to a D3DSTATS structure to be filled
 *
 * Returns:
 *  D3D_OK on success
 *  DDERR_INVALIDPARAMS if Stats == NULL
 *
 *****************************************************************************/
603
static HRESULT WINAPI d3d_device3_GetStats(IDirect3DDevice3 *iface, D3DSTATS *Stats)
604
{
605
    FIXME("iface %p, stats %p stub!\n", iface, Stats);
606 607 608 609 610 611 612 613 614 615 616 617 618 619

    if(!Stats)
        return DDERR_INVALIDPARAMS;

    /* Fill the Stats with 0 */
    Stats->dwTrianglesDrawn = 0;
    Stats->dwLinesDrawn = 0;
    Stats->dwPointsDrawn = 0;
    Stats->dwSpansDrawn = 0;
    Stats->dwVerticesProcessed = 0;

    return D3D_OK;
}

620
static HRESULT WINAPI d3d_device2_GetStats(IDirect3DDevice2 *iface, D3DSTATS *stats)
621
{
622
    struct d3d_device *device = impl_from_IDirect3DDevice2(iface);
623

624
    TRACE("iface %p, stats %p.\n", iface, stats);
625

626
    return d3d_device3_GetStats(&device->IDirect3DDevice3_iface, stats);
627 628
}

629
static HRESULT WINAPI d3d_device1_GetStats(IDirect3DDevice *iface, D3DSTATS *stats)
630
{
631
    struct d3d_device *device = impl_from_IDirect3DDevice(iface);
632

633
    TRACE("iface %p, stats %p.\n", iface, stats);
634

635
    return d3d_device3_GetStats(&device->IDirect3DDevice3_iface, stats);
636 637 638 639 640 641 642 643 644 645 646 647 648
}

/*****************************************************************************
 * IDirect3DDevice::CreateExecuteBuffer
 *
 * Creates an IDirect3DExecuteBuffer, used for rendering with a
 * Direct3DDevice.
 *
 * Version 1 only.
 *
 * Params:
 *  Desc: Buffer description
 *  ExecuteBuffer: Address to return the Interface pointer at
649
 *  UnkOuter: Must be NULL. Basically for aggregation, which ddraw doesn't
650 651 652 653 654 655 656 657
 *            support
 *
 * Returns:
 *  CLASS_E_NOAGGREGATION if UnkOuter != NULL
 *  DDERR_OUTOFMEMORY if we ran out of memory
 *  D3D_OK on success
 *
 *****************************************************************************/
658 659
static HRESULT WINAPI d3d_device1_CreateExecuteBuffer(IDirect3DDevice *iface,
        D3DEXECUTEBUFFERDESC *buffer_desc, IDirect3DExecuteBuffer **ExecuteBuffer, IUnknown *outer_unknown)
660
{
661
    struct d3d_device *device = impl_from_IDirect3DDevice(iface);
662
    struct d3d_execute_buffer *object;
663 664
    HRESULT hr;

665
    TRACE("iface %p, buffer_desc %p, buffer %p, outer_unknown %p.\n",
666
            iface, buffer_desc, ExecuteBuffer, outer_unknown);
667

668
    if (outer_unknown)
669 670 671
        return CLASS_E_NOAGGREGATION;

    /* Allocate the new Execute Buffer */
672
    object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
673 674
    if(!object)
    {
675
        ERR("Failed to allocate execute buffer memory.\n");
676 677 678
        return DDERR_OUTOFMEMORY;
    }

679
    hr = d3d_execute_buffer_init(object, device, buffer_desc);
680
    if (FAILED(hr))
681
    {
682 683 684
        WARN("Failed to initialize execute buffer, hr %#x.\n", hr);
        HeapFree(GetProcessHeap(), 0, object);
        return hr;
685 686
    }

687
    *ExecuteBuffer = &object->IDirect3DExecuteBuffer_iface;
688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705

    TRACE(" Returning IDirect3DExecuteBuffer at %p, implementation is at %p\n", *ExecuteBuffer, object);

    return D3D_OK;
}

/*****************************************************************************
 * IDirect3DDevice::Execute
 *
 * Executes all the stuff in an execute buffer.
 *
 * Params:
 *  ExecuteBuffer: The buffer to execute
 *  Viewport: The viewport used for rendering
 *  Flags: Some flags
 *
 * Returns:
 *  DDERR_INVALIDPARAMS if ExecuteBuffer == NULL
706
 *  D3D_OK on success
707 708
 *
 *****************************************************************************/
709 710
static HRESULT WINAPI d3d_device1_Execute(IDirect3DDevice *iface,
        IDirect3DExecuteBuffer *ExecuteBuffer, IDirect3DViewport *viewport, DWORD flags)
711
{
712
    struct d3d_device *device = impl_from_IDirect3DDevice(iface);
713
    struct d3d_execute_buffer *buffer = unsafe_impl_from_IDirect3DExecuteBuffer(ExecuteBuffer);
714
    struct d3d_viewport *viewport_impl = unsafe_impl_from_IDirect3DViewport(viewport);
715
    HRESULT hr;
716

717
    TRACE("iface %p, buffer %p, viewport %p, flags %#x.\n", iface, ExecuteBuffer, viewport, flags);
718

719
    if(!buffer)
720 721 722
        return DDERR_INVALIDPARAMS;

    /* Execute... */
723
    wined3d_mutex_lock();
724
    hr = d3d_execute_buffer_execute(buffer, device, viewport_impl);
725
    wined3d_mutex_unlock();
726

727
    return hr;
728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746
}

/*****************************************************************************
 * IDirect3DDevice3::AddViewport
 *
 * Add a Direct3DViewport to the device's viewport list. These viewports
 * are wrapped to IDirect3DDevice7 viewports in viewport.c
 *
 * Exists in Version 1, 2 and 3. Note that IDirect3DViewport 1, 2 and 3
 * are the same interfaces.
 *
 * Params:
 *  Viewport: The viewport to add
 *
 * Returns:
 *  DDERR_INVALIDPARAMS if Viewport == NULL
 *  D3D_OK on success
 *
 *****************************************************************************/
747
static HRESULT WINAPI d3d_device3_AddViewport(IDirect3DDevice3 *iface, IDirect3DViewport3 *viewport)
748
{
749 750
    struct d3d_device *device = impl_from_IDirect3DDevice3(iface);
    struct d3d_viewport *vp = unsafe_impl_from_IDirect3DViewport3(viewport);
751

752
    TRACE("iface %p, viewport %p.\n", iface, viewport);
753 754 755 756 757

    /* Sanity check */
    if(!vp)
        return DDERR_INVALIDPARAMS;

758
    wined3d_mutex_lock();
759 760 761
    list_add_head(&device->viewport_list, &vp->entry);
    /* Viewport must be usable for Clear() after AddViewport, so set active_device here. */
    vp->active_device = device;
762
    wined3d_mutex_unlock();
763 764 765 766

    return D3D_OK;
}

767 768
static HRESULT WINAPI d3d_device2_AddViewport(IDirect3DDevice2 *iface,
        IDirect3DViewport2 *viewport)
769
{
770 771
    struct d3d_device *device = impl_from_IDirect3DDevice2(iface);
    struct d3d_viewport *vp = unsafe_impl_from_IDirect3DViewport2(viewport);
772

773
    TRACE("iface %p, viewport %p.\n", iface, viewport);
774

775
    return d3d_device3_AddViewport(&device->IDirect3DDevice3_iface, &vp->IDirect3DViewport3_iface);
776 777
}

778
static HRESULT WINAPI d3d_device1_AddViewport(IDirect3DDevice *iface, IDirect3DViewport *viewport)
779
{
780 781
    struct d3d_device *device = impl_from_IDirect3DDevice(iface);
    struct d3d_viewport *vp = unsafe_impl_from_IDirect3DViewport(viewport);
782

783
    TRACE("iface %p, viewport %p.\n", iface, viewport);
784

785
    return d3d_device3_AddViewport(&device->IDirect3DDevice3_iface, &vp->IDirect3DViewport3_iface);
786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803
}

/*****************************************************************************
 * IDirect3DDevice3::DeleteViewport
 *
 * Deletes a Direct3DViewport from the device's viewport list.
 *
 * Exists in Version 1, 2 and 3. Note that all Viewport interface versions
 * are equal.
 *
 * Params:
 *  Viewport: The viewport to delete
 *
 * Returns:
 *  D3D_OK on success
 *  DDERR_INVALIDPARAMS if the viewport wasn't found in the list
 *
 *****************************************************************************/
804
static HRESULT WINAPI d3d_device3_DeleteViewport(IDirect3DDevice3 *iface, IDirect3DViewport3 *viewport)
805
{
806
    struct d3d_device *device = impl_from_IDirect3DDevice3(iface);
807
    struct d3d_viewport *vp = unsafe_impl_from_IDirect3DViewport3(viewport);
808

809
    TRACE("iface %p, viewport %p.\n", iface, viewport);
810

811
    wined3d_mutex_lock();
812

813
    if (vp->active_device != device)
814
    {
815
        WARN("Viewport %p active device is %p.\n", vp, vp->active_device);
816
        wined3d_mutex_unlock();
817
        return DDERR_INVALIDPARAMS;
818 819
    }

820 821 822
    vp->active_device = NULL;
    list_remove(&vp->entry);

823 824
    wined3d_mutex_unlock();

825
    return D3D_OK;
826 827
}

828
static HRESULT WINAPI d3d_device2_DeleteViewport(IDirect3DDevice2 *iface, IDirect3DViewport2 *viewport)
829
{
830 831
    struct d3d_device *device = impl_from_IDirect3DDevice2(iface);
    struct d3d_viewport *vp = unsafe_impl_from_IDirect3DViewport2(viewport);
832

833
    TRACE("iface %p, viewport %p.\n", iface, viewport);
834

835
    return d3d_device3_DeleteViewport(&device->IDirect3DDevice3_iface, &vp->IDirect3DViewport3_iface);
836 837
}

838
static HRESULT WINAPI d3d_device1_DeleteViewport(IDirect3DDevice *iface, IDirect3DViewport *viewport)
839
{
840 841
    struct d3d_device *device = impl_from_IDirect3DDevice(iface);
    struct d3d_viewport *vp = unsafe_impl_from_IDirect3DViewport(viewport);
842

843
    TRACE("iface %p, viewport %p.\n", iface, viewport);
844

845
    return d3d_device3_DeleteViewport(&device->IDirect3DDevice3_iface, &vp->IDirect3DViewport3_iface);
846 847 848 849 850
}

/*****************************************************************************
 * IDirect3DDevice3::NextViewport
 *
851
 * Returns a viewport from the viewport list, depending on the
852 853 854 855 856 857 858 859 860 861 862
 * passed viewport and the flags.
 *
 * Exists in Version 1, 2 and 3. Note that all Viewport interface versions
 * are equal.
 *
 * Params:
 *  Viewport: Viewport to use for beginning the search
 *  Flags: D3DNEXT_NEXT, D3DNEXT_HEAD or D3DNEXT_TAIL
 *
 * Returns:
 *  D3D_OK on success
863
 *  DDERR_INVALIDPARAMS if the flags were wrong, or Viewport was NULL
864 865
 *
 *****************************************************************************/
866 867
static HRESULT WINAPI d3d_device3_NextViewport(IDirect3DDevice3 *iface,
        IDirect3DViewport3 *Viewport3, IDirect3DViewport3 **lplpDirect3DViewport3, DWORD flags)
868
{
869
    struct d3d_device *This = impl_from_IDirect3DDevice3(iface);
870 871
    struct d3d_viewport *vp = unsafe_impl_from_IDirect3DViewport3(Viewport3);
    struct d3d_viewport *next;
872
    struct list *entry;
873

874
    TRACE("iface %p, viewport %p, next %p, flags %#x.\n",
875
            iface, Viewport3, lplpDirect3DViewport3, flags);
876 877 878 879

    if(!vp)
    {
        *lplpDirect3DViewport3 = NULL;
880
        return DDERR_INVALIDPARAMS;
881 882 883
    }


884
    wined3d_mutex_lock();
885
    switch (flags)
886 887
    {
        case D3DNEXT_NEXT:
888 889 890
            entry = list_next(&This->viewport_list, &vp->entry);
            break;

891
        case D3DNEXT_HEAD:
892 893 894
            entry = list_head(&This->viewport_list);
            break;

895
        case D3DNEXT_TAIL:
896 897 898
            entry = list_tail(&This->viewport_list);
            break;

899
        default:
900
            WARN("Invalid flags %#x.\n", flags);
901
            *lplpDirect3DViewport3 = NULL;
902
            wined3d_mutex_unlock();
903 904 905
            return DDERR_INVALIDPARAMS;
    }

906
    if (entry)
907
    {
908
        next = LIST_ENTRY(entry, struct d3d_viewport, entry);
909 910
        *lplpDirect3DViewport3 = &next->IDirect3DViewport3_iface;
    }
911 912 913
    else
        *lplpDirect3DViewport3 = NULL;

914 915
    wined3d_mutex_unlock();

916 917 918
    return D3D_OK;
}

919 920
static HRESULT WINAPI d3d_device2_NextViewport(IDirect3DDevice2 *iface,
        IDirect3DViewport2 *viewport, IDirect3DViewport2 **next, DWORD flags)
921
{
922 923
    struct d3d_device *device = impl_from_IDirect3DDevice2(iface);
    struct d3d_viewport *vp = unsafe_impl_from_IDirect3DViewport2(viewport);
924 925
    IDirect3DViewport3 *res;
    HRESULT hr;
926 927

    TRACE("iface %p, viewport %p, next %p, flags %#x.\n",
928
            iface, viewport, next, flags);
929

930 931 932
    hr = d3d_device3_NextViewport(&device->IDirect3DDevice3_iface,
            &vp->IDirect3DViewport3_iface, &res, flags);
    *next = (IDirect3DViewport2 *)res;
933 934 935
    return hr;
}

936 937
static HRESULT WINAPI d3d_device1_NextViewport(IDirect3DDevice *iface,
        IDirect3DViewport *viewport, IDirect3DViewport **next, DWORD flags)
938
{
939 940
    struct d3d_device *device = impl_from_IDirect3DDevice(iface);
    struct d3d_viewport *vp = unsafe_impl_from_IDirect3DViewport(viewport);
941 942
    IDirect3DViewport3 *res;
    HRESULT hr;
943 944

    TRACE("iface %p, viewport %p, next %p, flags %#x.\n",
945
            iface, viewport, next, flags);
946

947 948 949
    hr = d3d_device3_NextViewport(&device->IDirect3DDevice3_iface,
            &vp->IDirect3DViewport3_iface, &res, flags);
    *next = (IDirect3DViewport *)res;
950 951 952 953 954 955 956 957 958 959 960 961 962 963 964 965 966 967 968 969 970 971 972 973
    return hr;
}

/*****************************************************************************
 * IDirect3DDevice::Pick
 *
 * Executes an execute buffer without performing rendering. Instead, a
 * list of primitives that intersect with (x1,y1) of the passed rectangle
 * is created. IDirect3DDevice::GetPickRecords can be used to retrieve
 * this list.
 *
 * Version 1 only
 *
 * Params:
 *  ExecuteBuffer: Buffer to execute
 *  Viewport: Viewport to use for execution
 *  Flags: None are defined, according to the SDK
 *  Rect: Specifies the coordinates to be picked. Only x1 and y2 are used,
 *        x2 and y2 are ignored.
 *
 * Returns:
 *  D3D_OK because it's a stub
 *
 *****************************************************************************/
974 975
static HRESULT WINAPI d3d_device1_Pick(IDirect3DDevice *iface, IDirect3DExecuteBuffer *buffer,
        IDirect3DViewport *viewport, DWORD flags, D3DRECT *rect)
976
{
977
    FIXME("iface %p, buffer %p, viewport %p, flags %#x, rect %s stub!\n",
978
            iface, buffer, viewport, flags, wine_dbgstr_rect((RECT *)rect));
979 980 981 982 983 984 985 986 987 988 989 990 991 992

    return D3D_OK;
}

/*****************************************************************************
 * IDirect3DDevice::GetPickRecords
 *
 * Retrieves the pick records generated by IDirect3DDevice::GetPickRecords
 *
 * Version 1 only
 *
 * Params:
 *  Count: Pointer to a DWORD containing the numbers of pick records to
 *         retrieve
Austin English's avatar
Austin English committed
993
 *  D3DPickRec: Address to store the resulting D3DPICKRECORD array.
994 995 996 997 998
 *
 * Returns:
 *  D3D_OK, because it's a stub
 *
 *****************************************************************************/
999 1000
static HRESULT WINAPI d3d_device1_GetPickRecords(IDirect3DDevice *iface,
        DWORD *count, D3DPICKRECORD *records)
1001
{
1002
    FIXME("iface %p, count %p, records %p stub!\n", iface, count, records);
1003 1004 1005 1006 1007 1008 1009

    return D3D_OK;
}

/*****************************************************************************
 * IDirect3DDevice7::EnumTextureformats
 *
1010 1011 1012
 * Enumerates the supported texture formats. It has a list of all possible
 * formats and calls IWineD3D::CheckDeviceFormat for each format to see if
 * WineD3D supports it. If so, then it is passed to the app.
1013
 *
1014
 * This is for Version 7 and 3, older versions have a different
1015 1016 1017 1018 1019 1020 1021 1022 1023 1024 1025
 * callback function and their own implementation
 *
 * Params:
 *  Callback: Callback to call for each enumerated format
 *  Arg: Argument to pass to the callback
 *
 * Returns:
 *  D3D_OK on success
 *  DDERR_INVALIDPARAMS if Callback == NULL
 *
 *****************************************************************************/
1026 1027
static HRESULT d3d_device7_EnumTextureFormats(IDirect3DDevice7 *iface,
        LPD3DENUMPIXELFORMATSCALLBACK callback, void *context)
1028
{
1029
    struct d3d_device *device = impl_from_IDirect3DDevice7(iface);
1030
    struct wined3d_display_mode mode;
1031
    HRESULT hr;
1032
    unsigned int i;
1033

1034
    static const enum wined3d_format_id FormatList[] =
1035
    {
1036 1037
        /* 16 bit */
        WINED3DFMT_B5G5R5X1_UNORM,
1038 1039 1040
        WINED3DFMT_B5G5R5A1_UNORM,
        WINED3DFMT_B4G4R4A4_UNORM,
        WINED3DFMT_B5G6R5_UNORM,
1041 1042 1043 1044
        /* 32 bit */
        WINED3DFMT_B8G8R8X8_UNORM,
        WINED3DFMT_B8G8R8A8_UNORM,
        /* 8 bit */
1045 1046
        WINED3DFMT_B2G3R3_UNORM,
        WINED3DFMT_P8_UINT,
1047 1048 1049 1050 1051 1052
        /* FOURCC codes */
        WINED3DFMT_DXT1,
        WINED3DFMT_DXT3,
        WINED3DFMT_DXT5,
    };

1053
    static const enum wined3d_format_id BumpFormatList[] =
1054
    {
1055
        WINED3DFMT_R8G8_SNORM,
1056 1057
        WINED3DFMT_R5G5_SNORM_L6_UNORM,
        WINED3DFMT_R8G8_SNORM_L8X8_UNORM,
1058
        WINED3DFMT_R16G16_SNORM,
1059 1060
        WINED3DFMT_R10G11B11_SNORM,
        WINED3DFMT_R10G10B10_SNORM_A2_UNORM
1061 1062
    };

1063
    TRACE("iface %p, callback %p, context %p.\n", iface, callback, context);
1064

1065
    if (!callback)
1066 1067
        return DDERR_INVALIDPARAMS;

1068
    wined3d_mutex_lock();
1069 1070

    memset(&mode, 0, sizeof(mode));
1071
    if (FAILED(hr = wined3d_get_adapter_display_mode(device->ddraw->wined3d, WINED3DADAPTER_DEFAULT, &mode, NULL)))
1072
    {
1073
        wined3d_mutex_unlock();
1074 1075 1076 1077
        WARN("Cannot get the current adapter format\n");
        return hr;
    }

1078
    for (i = 0; i < sizeof(FormatList) / sizeof(*FormatList); ++i)
1079
    {
1080
        hr = wined3d_check_device_format(device->ddraw->wined3d, WINED3DADAPTER_DEFAULT, WINED3D_DEVICE_TYPE_HAL,
1081
                mode.format_id, 0, WINED3D_RTYPE_TEXTURE, FormatList[i], WINED3D_SURFACE_TYPE_OPENGL);
1082
        if (hr == D3D_OK)
1083 1084 1085 1086 1087 1088 1089 1090
        {
            DDPIXELFORMAT pformat;

            memset(&pformat, 0, sizeof(pformat));
            pformat.dwSize = sizeof(pformat);
            PixelFormat_WineD3DtoDD(&pformat, FormatList[i]);

            TRACE("Enumerating WineD3DFormat %d\n", FormatList[i]);
1091
            hr = callback(&pformat, context);
1092 1093 1094
            if(hr != DDENUMRET_OK)
            {
                TRACE("Format enumeration cancelled by application\n");
1095
                wined3d_mutex_unlock();
1096 1097 1098 1099
                return D3D_OK;
            }
        }
    }
1100

1101
    for (i = 0; i < sizeof(BumpFormatList) / sizeof(*BumpFormatList); ++i)
1102
    {
1103
        hr = wined3d_check_device_format(device->ddraw->wined3d, WINED3DADAPTER_DEFAULT,
1104
                WINED3D_DEVICE_TYPE_HAL, mode.format_id, WINED3DUSAGE_QUERY_LEGACYBUMPMAP,
1105
                WINED3D_RTYPE_TEXTURE, BumpFormatList[i], WINED3D_SURFACE_TYPE_OPENGL);
1106
        if (hr == D3D_OK)
1107 1108 1109 1110 1111 1112 1113 1114
        {
            DDPIXELFORMAT pformat;

            memset(&pformat, 0, sizeof(pformat));
            pformat.dwSize = sizeof(pformat);
            PixelFormat_WineD3DtoDD(&pformat, BumpFormatList[i]);

            TRACE("Enumerating WineD3DFormat %d\n", BumpFormatList[i]);
1115
            hr = callback(&pformat, context);
1116 1117 1118
            if(hr != DDENUMRET_OK)
            {
                TRACE("Format enumeration cancelled by application\n");
1119
                wined3d_mutex_unlock();
1120 1121 1122 1123
                return D3D_OK;
            }
        }
    }
1124
    TRACE("End of enumeration\n");
1125 1126
    wined3d_mutex_unlock();

1127
    return D3D_OK;
1128 1129
}

1130 1131
static HRESULT WINAPI d3d_device7_EnumTextureFormats_FPUSetup(IDirect3DDevice7 *iface,
        LPD3DENUMPIXELFORMATSCALLBACK callback, void *context)
1132
{
1133
    return d3d_device7_EnumTextureFormats(iface, callback, context);
1134 1135
}

1136 1137
static HRESULT WINAPI d3d_device7_EnumTextureFormats_FPUPreserve(IDirect3DDevice7 *iface,
        LPD3DENUMPIXELFORMATSCALLBACK callback, void *context)
1138 1139 1140 1141 1142
{
    HRESULT hr;
    WORD old_fpucw;

    old_fpucw = d3d_fpu_setup();
1143
    hr = d3d_device7_EnumTextureFormats(iface, callback, context);
1144 1145 1146 1147 1148
    set_fpu_control_word(old_fpucw);

    return hr;
}

1149 1150
static HRESULT WINAPI d3d_device3_EnumTextureFormats(IDirect3DDevice3 *iface,
        LPD3DENUMPIXELFORMATSCALLBACK callback, void *context)
1151
{
1152
    struct d3d_device *device = impl_from_IDirect3DDevice3(iface);
1153

1154
    TRACE("iface %p, callback %p, context %p.\n", iface, callback, context);
1155

1156
    return IDirect3DDevice7_EnumTextureFormats(&device->IDirect3DDevice7_iface, callback, context);
1157 1158 1159 1160 1161 1162
}

/*****************************************************************************
 * IDirect3DDevice2::EnumTextureformats
 *
 * EnumTextureFormats for Version 1 and 2, see
1163 1164 1165 1166
 * IDirect3DDevice7::EnumTexureFormats for a more detailed description.
 *
 * This version has a different callback and does not enumerate FourCC
 * formats
1167 1168
 *
 *****************************************************************************/
1169 1170
static HRESULT WINAPI d3d_device2_EnumTextureFormats(IDirect3DDevice2 *iface,
        LPD3DENUMTEXTUREFORMATSCALLBACK callback, void *context)
1171
{
1172
    struct d3d_device *device = impl_from_IDirect3DDevice2(iface);
1173
    struct wined3d_display_mode mode;
1174
    HRESULT hr;
1175
    unsigned int i;
1176

1177
    static const enum wined3d_format_id FormatList[] =
1178
    {
1179 1180
        /* 16 bit */
        WINED3DFMT_B5G5R5X1_UNORM,
1181 1182 1183
        WINED3DFMT_B5G5R5A1_UNORM,
        WINED3DFMT_B4G4R4A4_UNORM,
        WINED3DFMT_B5G6R5_UNORM,
1184 1185 1186 1187
        /* 32 bit */
        WINED3DFMT_B8G8R8X8_UNORM,
        WINED3DFMT_B8G8R8A8_UNORM,
        /* 8 bit */
1188 1189
        WINED3DFMT_B2G3R3_UNORM,
        WINED3DFMT_P8_UINT,
1190 1191 1192
        /* FOURCC codes - Not in this version*/
    };

1193
    TRACE("iface %p, callback %p, context %p.\n", iface, callback, context);
1194

1195
    if (!callback)
1196 1197
        return DDERR_INVALIDPARAMS;

1198
    wined3d_mutex_lock();
1199 1200

    memset(&mode, 0, sizeof(mode));
1201
    if (FAILED(hr = wined3d_get_adapter_display_mode(device->ddraw->wined3d, WINED3DADAPTER_DEFAULT, &mode, NULL)))
1202
    {
1203
        wined3d_mutex_unlock();
1204 1205 1206 1207
        WARN("Cannot get the current adapter format\n");
        return hr;
    }

1208
    for (i = 0; i < sizeof(FormatList) / sizeof(*FormatList); ++i)
1209
    {
1210
        hr = wined3d_check_device_format(device->ddraw->wined3d, 0, WINED3D_DEVICE_TYPE_HAL,
1211
                mode.format_id, 0, WINED3D_RTYPE_TEXTURE, FormatList[i], WINED3D_SURFACE_TYPE_OPENGL);
1212
        if (hr == D3D_OK)
1213 1214 1215 1216 1217 1218 1219
        {
            DDSURFACEDESC sdesc;

            memset(&sdesc, 0, sizeof(sdesc));
            sdesc.dwSize = sizeof(sdesc);
            sdesc.dwFlags = DDSD_PIXELFORMAT | DDSD_CAPS;
            sdesc.ddsCaps.dwCaps = DDSCAPS_TEXTURE;
1220
            sdesc.ddpfPixelFormat.dwSize = sizeof(sdesc.ddpfPixelFormat);
1221 1222 1223
            PixelFormat_WineD3DtoDD(&sdesc.ddpfPixelFormat, FormatList[i]);

            TRACE("Enumerating WineD3DFormat %d\n", FormatList[i]);
1224
            hr = callback(&sdesc, context);
1225 1226 1227
            if(hr != DDENUMRET_OK)
            {
                TRACE("Format enumeration cancelled by application\n");
1228
                wined3d_mutex_unlock();
1229 1230 1231 1232 1233
                return D3D_OK;
            }
        }
    }
    TRACE("End of enumeration\n");
1234 1235
    wined3d_mutex_unlock();

1236
    return D3D_OK;
1237 1238
}

1239 1240
static HRESULT WINAPI d3d_device1_EnumTextureFormats(IDirect3DDevice *iface,
        LPD3DENUMTEXTUREFORMATSCALLBACK callback, void *context)
1241
{
1242
    struct d3d_device *device = impl_from_IDirect3DDevice(iface);
1243

1244
    TRACE("iface %p, callback %p, context %p.\n", iface, callback, context);
1245

1246
    return d3d_device2_EnumTextureFormats(&device->IDirect3DDevice2_iface, callback, context);
1247 1248 1249 1250 1251
}

/*****************************************************************************
 * IDirect3DDevice::CreateMatrix
 *
1252 1253
 * Creates a matrix handle. A handle is created and memory for a D3DMATRIX is
 * allocated for the handle.
1254 1255 1256 1257 1258 1259 1260 1261 1262 1263 1264
 *
 * Version 1 only
 *
 * Params
 *  D3DMatHandle: Address to return the handle at
 *
 * Returns:
 *  D3D_OK on success
 *  DDERR_INVALIDPARAMS if D3DMatHandle = NULL
 *
 *****************************************************************************/
1265
static HRESULT WINAPI d3d_device1_CreateMatrix(IDirect3DDevice *iface, D3DMATRIXHANDLE *D3DMatHandle)
1266
{
1267
    struct d3d_device *device = impl_from_IDirect3DDevice(iface);
1268
    D3DMATRIX *Matrix;
1269 1270
    DWORD h;

1271
    TRACE("iface %p, matrix_handle %p.\n", iface, D3DMatHandle);
1272 1273 1274 1275

    if(!D3DMatHandle)
        return DDERR_INVALIDPARAMS;

1276 1277 1278 1279 1280 1281
    Matrix = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(D3DMATRIX));
    if(!Matrix)
    {
        ERR("Out of memory when allocating a D3DMATRIX\n");
        return DDERR_OUTOFMEMORY;
    }
1282

1283
    wined3d_mutex_lock();
1284

1285
    h = ddraw_allocate_handle(&device->handle_table, Matrix, DDRAW_HANDLE_MATRIX);
1286
    if (h == DDRAW_INVALID_HANDLE)
1287
    {
1288
        ERR("Failed to allocate a matrix handle.\n");
1289
        HeapFree(GetProcessHeap(), 0, Matrix);
1290
        wined3d_mutex_unlock();
1291 1292
        return DDERR_OUTOFMEMORY;
    }
1293 1294 1295

    *D3DMatHandle = h + 1;

1296
    TRACE(" returning matrix handle %d\n", *D3DMatHandle);
1297

1298 1299
    wined3d_mutex_unlock();

1300 1301 1302 1303 1304 1305
    return D3D_OK;
}

/*****************************************************************************
 * IDirect3DDevice::SetMatrix
 *
1306 1307
 * Sets a matrix for a matrix handle. The matrix is copied into the memory
 * allocated for the handle
1308 1309 1310 1311 1312 1313 1314 1315 1316
 *
 * Version 1 only
 *
 * Params:
 *  D3DMatHandle: Handle to set the matrix to
 *  D3DMatrix: Matrix to set
 *
 * Returns:
 *  D3D_OK on success
1317 1318
 *  DDERR_INVALIDPARAMS if the handle of the matrix is invalid or the matrix
 *   to set is NULL
1319 1320
 *
 *****************************************************************************/
1321 1322
static HRESULT WINAPI d3d_device1_SetMatrix(IDirect3DDevice *iface,
        D3DMATRIXHANDLE D3DMatHandle, D3DMATRIX *D3DMatrix)
1323
{
1324
    struct d3d_device *This = impl_from_IDirect3DDevice(iface);
1325 1326
    D3DMATRIX *m;

1327
    TRACE("iface %p, matrix_handle %#x, matrix %p.\n", iface, D3DMatHandle, D3DMatrix);
1328

1329
    if (!D3DMatrix) return DDERR_INVALIDPARAMS;
1330

1331
    wined3d_mutex_lock();
1332 1333 1334

    m = ddraw_get_object(&This->handle_table, D3DMatHandle - 1, DDRAW_HANDLE_MATRIX);
    if (!m)
1335
    {
1336
        WARN("Invalid matrix handle.\n");
1337
        wined3d_mutex_unlock();
1338 1339 1340
        return DDERR_INVALIDPARAMS;
    }

1341
    if (TRACE_ON(ddraw))
1342 1343
        dump_D3DMATRIX(D3DMatrix);

1344
    *m = *D3DMatrix;
1345

1346
    if (D3DMatHandle == This->world)
1347
        wined3d_device_set_transform(This->wined3d_device,
1348
                WINED3D_TS_WORLD_MATRIX(0), (struct wined3d_matrix *)D3DMatrix);
1349 1350

    if (D3DMatHandle == This->view)
1351
        wined3d_device_set_transform(This->wined3d_device,
1352
                WINED3D_TS_VIEW, (struct wined3d_matrix *)D3DMatrix);
1353 1354

    if (D3DMatHandle == This->proj)
1355
        wined3d_device_set_transform(This->wined3d_device,
1356
                WINED3D_TS_PROJECTION, (struct wined3d_matrix *)D3DMatrix);
1357

1358 1359
    wined3d_mutex_unlock();

1360 1361 1362 1363
    return D3D_OK;
}

/*****************************************************************************
1364
 * IDirect3DDevice::GetMatrix
1365 1366 1367 1368 1369 1370 1371 1372 1373 1374 1375
 *
 * Returns the content of a D3DMATRIX handle
 *
 * Version 1 only
 *
 * Params:
 *  D3DMatHandle: Matrix handle to read the content from
 *  D3DMatrix: Address to store the content at
 *
 * Returns:
 *  D3D_OK on success
1376
 *  DDERR_INVALIDPARAMS if D3DMatHandle is invalid or D3DMatrix is NULL
1377 1378
 *
 *****************************************************************************/
1379 1380
static HRESULT WINAPI d3d_device1_GetMatrix(IDirect3DDevice *iface,
        D3DMATRIXHANDLE D3DMatHandle, D3DMATRIX *D3DMatrix)
1381
{
1382
    struct d3d_device *device = impl_from_IDirect3DDevice(iface);
1383 1384
    D3DMATRIX *m;

1385
    TRACE("iface %p, matrix_handle %#x, matrix %p.\n", iface, D3DMatHandle, D3DMatrix);
1386

1387
    if (!D3DMatrix) return DDERR_INVALIDPARAMS;
1388

1389
    wined3d_mutex_lock();
1390

1391
    m = ddraw_get_object(&device->handle_table, D3DMatHandle - 1, DDRAW_HANDLE_MATRIX);
1392
    if (!m)
1393
    {
1394
        WARN("Invalid matrix handle.\n");
1395
        wined3d_mutex_unlock();
1396 1397
        return DDERR_INVALIDPARAMS;
    }
1398

1399
    *D3DMatrix = *m;
1400

1401 1402
    wined3d_mutex_unlock();

1403 1404 1405 1406 1407 1408
    return D3D_OK;
}

/*****************************************************************************
 * IDirect3DDevice::DeleteMatrix
 *
1409
 * Destroys a Matrix handle. Frees the memory and unsets the handle data
1410 1411 1412 1413 1414 1415 1416 1417
 *
 * Version 1 only
 *
 * Params:
 *  D3DMatHandle: Handle to destroy
 *
 * Returns:
 *  D3D_OK on success
1418
 *  DDERR_INVALIDPARAMS if D3DMatHandle is invalid
1419 1420
 *
 *****************************************************************************/
1421
static HRESULT WINAPI d3d_device1_DeleteMatrix(IDirect3DDevice *iface, D3DMATRIXHANDLE D3DMatHandle)
1422
{
1423
    struct d3d_device *device = impl_from_IDirect3DDevice(iface);
1424
    D3DMATRIX *m;
1425

1426
    TRACE("iface %p, matrix_handle %#x.\n", iface, D3DMatHandle);
1427

1428
    wined3d_mutex_lock();
1429

1430
    m = ddraw_free_handle(&device->handle_table, D3DMatHandle - 1, DDRAW_HANDLE_MATRIX);
1431
    if (!m)
1432
    {
1433
        WARN("Invalid matrix handle.\n");
1434
        wined3d_mutex_unlock();
1435 1436
        return DDERR_INVALIDPARAMS;
    }
1437

1438
    wined3d_mutex_unlock();
1439 1440 1441

    HeapFree(GetProcessHeap(), 0, m);

1442 1443 1444 1445 1446 1447 1448 1449 1450 1451 1452 1453
    return D3D_OK;
}

/*****************************************************************************
 * IDirect3DDevice7::BeginScene
 *
 * This method must be called before any rendering is performed.
 * IDirect3DDevice::EndScene has to be called after the scene is complete
 *
 * Version 1, 2, 3 and 7
 *
 * Returns:
1454
 *  D3D_OK on success, for details see IWineD3DDevice::BeginScene
1455 1456
 *  D3DERR_SCENE_IN_SCENE if WineD3D returns an error(Only in case of an already
 *  started scene).
1457 1458
 *
 *****************************************************************************/
1459
static HRESULT d3d_device7_BeginScene(IDirect3DDevice7 *iface)
1460
{
1461
    struct d3d_device *device = impl_from_IDirect3DDevice7(iface);
1462
    HRESULT hr;
1463 1464

    TRACE("iface %p.\n", iface);
1465

1466
    wined3d_mutex_lock();
1467
    hr = wined3d_device_begin_scene(device->wined3d_device);
1468 1469
    wined3d_mutex_unlock();

1470 1471
    if(hr == WINED3D_OK) return D3D_OK;
    else return D3DERR_SCENE_IN_SCENE; /* TODO: Other possible causes of failure */
1472 1473
}

1474
static HRESULT WINAPI d3d_device7_BeginScene_FPUSetup(IDirect3DDevice7 *iface)
1475
{
1476
    return d3d_device7_BeginScene(iface);
1477 1478
}

1479
static HRESULT WINAPI d3d_device7_BeginScene_FPUPreserve(IDirect3DDevice7 *iface)
1480 1481 1482 1483 1484
{
    HRESULT hr;
    WORD old_fpucw;

    old_fpucw = d3d_fpu_setup();
1485
    hr = d3d_device7_BeginScene(iface);
1486 1487 1488 1489 1490
    set_fpu_control_word(old_fpucw);

    return hr;
}

1491
static HRESULT WINAPI d3d_device3_BeginScene(IDirect3DDevice3 *iface)
1492
{
1493 1494
    struct d3d_device *device = impl_from_IDirect3DDevice3(iface);

1495 1496
    TRACE("iface %p.\n", iface);

1497
    return IDirect3DDevice7_BeginScene(&device->IDirect3DDevice7_iface);
1498 1499
}

1500
static HRESULT WINAPI d3d_device2_BeginScene(IDirect3DDevice2 *iface)
1501
{
1502 1503
    struct d3d_device *device = impl_from_IDirect3DDevice2(iface);

1504 1505
    TRACE("iface %p.\n", iface);

1506
    return IDirect3DDevice7_BeginScene(&device->IDirect3DDevice7_iface);
1507 1508
}

1509
static HRESULT WINAPI d3d_device1_BeginScene(IDirect3DDevice *iface)
1510
{
1511 1512
    struct d3d_device *device = impl_from_IDirect3DDevice(iface);

1513 1514
    TRACE("iface %p.\n", iface);

1515
    return IDirect3DDevice7_BeginScene(&device->IDirect3DDevice7_iface);
1516 1517 1518 1519 1520 1521 1522 1523 1524 1525 1526 1527
}

/*****************************************************************************
 * IDirect3DDevice7::EndScene
 *
 * Ends a scene that has been begun with IDirect3DDevice7::BeginScene.
 * This method must be called after rendering is finished.
 *
 * Version 1, 2, 3 and 7
 *
 * Returns:
 *  D3D_OK on success, for details see IWineD3DDevice::EndScene
1528 1529
 *  D3DERR_SCENE_NOT_IN_SCENE is returned if WineD3D returns an error. It does
 *  that only if the scene was already ended.
1530 1531
 *
 *****************************************************************************/
1532
static HRESULT d3d_device7_EndScene(IDirect3DDevice7 *iface)
1533
{
1534
    struct d3d_device *device = impl_from_IDirect3DDevice7(iface);
1535
    HRESULT hr;
1536 1537

    TRACE("iface %p.\n", iface);
1538

1539
    wined3d_mutex_lock();
1540
    hr = wined3d_device_end_scene(device->wined3d_device);
1541 1542
    wined3d_mutex_unlock();

1543 1544
    if(hr == WINED3D_OK) return D3D_OK;
    else return D3DERR_SCENE_NOT_IN_SCENE;
1545 1546
}

1547
static HRESULT WINAPI DECLSPEC_HOTPATCH d3d_device7_EndScene_FPUSetup(IDirect3DDevice7 *iface)
1548
{
1549
    return d3d_device7_EndScene(iface);
1550 1551
}

1552
static HRESULT WINAPI DECLSPEC_HOTPATCH d3d_device7_EndScene_FPUPreserve(IDirect3DDevice7 *iface)
1553 1554 1555 1556 1557
{
    HRESULT hr;
    WORD old_fpucw;

    old_fpucw = d3d_fpu_setup();
1558
    hr = d3d_device7_EndScene(iface);
1559 1560 1561 1562 1563
    set_fpu_control_word(old_fpucw);

    return hr;
}

1564
static HRESULT WINAPI DECLSPEC_HOTPATCH d3d_device3_EndScene(IDirect3DDevice3 *iface)
1565
{
1566 1567
    struct d3d_device *device = impl_from_IDirect3DDevice3(iface);

1568 1569
    TRACE("iface %p.\n", iface);

1570
    return IDirect3DDevice7_EndScene(&device->IDirect3DDevice7_iface);
1571 1572
}

1573
static HRESULT WINAPI DECLSPEC_HOTPATCH d3d_device2_EndScene(IDirect3DDevice2 *iface)
1574
{
1575 1576
    struct d3d_device *device = impl_from_IDirect3DDevice2(iface);

1577 1578
    TRACE("iface %p.\n", iface);

1579
    return IDirect3DDevice7_EndScene(&device->IDirect3DDevice7_iface);
1580 1581
}

1582
static HRESULT WINAPI DECLSPEC_HOTPATCH d3d_device1_EndScene(IDirect3DDevice *iface)
1583
{
1584 1585
    struct d3d_device *device = impl_from_IDirect3DDevice(iface);

1586 1587
    TRACE("iface %p.\n", iface);

1588
    return IDirect3DDevice7_EndScene(&device->IDirect3DDevice7_iface);
1589 1590 1591 1592 1593 1594 1595 1596 1597 1598 1599 1600 1601 1602 1603 1604
}

/*****************************************************************************
 * IDirect3DDevice7::GetDirect3D
 *
 * Returns the IDirect3D(= interface to the DirectDraw object) used to create
 * this device.
 *
 * Params:
 *  Direct3D7: Address to store the interface pointer at
 *
 * Returns:
 *  D3D_OK on success
 *  DDERR_INVALIDPARAMS if Direct3D7 == NULL
 *
 *****************************************************************************/
1605
static HRESULT WINAPI d3d_device7_GetDirect3D(IDirect3DDevice7 *iface, IDirect3D7 **d3d)
1606
{
1607
    struct d3d_device *device = impl_from_IDirect3DDevice7(iface);
1608

1609
    TRACE("iface %p, d3d %p.\n", iface, d3d);
1610

1611
    if (!d3d)
1612 1613
        return DDERR_INVALIDPARAMS;

1614 1615
    *d3d = &device->ddraw->IDirect3D7_iface;
    IDirect3D7_AddRef(*d3d);
1616

1617
    TRACE("Returning interface %p.\n", *d3d);
1618 1619 1620
    return D3D_OK;
}

1621
static HRESULT WINAPI d3d_device3_GetDirect3D(IDirect3DDevice3 *iface, IDirect3D3 **d3d)
1622
{
1623
    struct d3d_device *device = impl_from_IDirect3DDevice3(iface);
1624

1625
    TRACE("iface %p, d3d %p.\n", iface, d3d);
1626

1627
    if (!d3d)
1628 1629
        return DDERR_INVALIDPARAMS;

1630 1631 1632 1633
    *d3d = &device->ddraw->IDirect3D3_iface;
    IDirect3D3_AddRef(*d3d);

    TRACE("Returning interface %p.\n", *d3d);
1634 1635 1636
    return D3D_OK;
}

1637
static HRESULT WINAPI d3d_device2_GetDirect3D(IDirect3DDevice2 *iface, IDirect3D2 **d3d)
1638
{
1639
    struct d3d_device *device = impl_from_IDirect3DDevice2(iface);
1640

1641
    TRACE("iface %p, d3d %p.\n", iface, d3d);
1642

1643
    if (!d3d)
1644 1645
        return DDERR_INVALIDPARAMS;

1646 1647 1648 1649
    *d3d = &device->ddraw->IDirect3D2_iface;
    IDirect3D2_AddRef(*d3d);

    TRACE("Returning interface %p.\n", *d3d);
1650 1651 1652
    return D3D_OK;
}

1653
static HRESULT WINAPI d3d_device1_GetDirect3D(IDirect3DDevice *iface, IDirect3D **d3d)
1654
{
1655
    struct d3d_device *device = impl_from_IDirect3DDevice(iface);
1656

1657
    TRACE("iface %p, d3d %p.\n", iface, d3d);
1658

1659
    if (!d3d)
1660 1661
        return DDERR_INVALIDPARAMS;

1662 1663 1664 1665
    *d3d = &device->ddraw->IDirect3D_iface;
    IDirect3D_AddRef(*d3d);

    TRACE("Returning interface %p.\n", *d3d);
1666 1667 1668 1669 1670 1671 1672 1673 1674 1675 1676 1677 1678 1679 1680 1681 1682 1683 1684
    return D3D_OK;
}

/*****************************************************************************
 * IDirect3DDevice3::SetCurrentViewport
 *
 * Sets a Direct3DViewport as the current viewport.
 * For the thunks note that all viewport interface versions are equal
 *
 * Params:
 *  Direct3DViewport3: The viewport to set
 *
 * Version 2 and 3
 *
 * Returns:
 *  D3D_OK on success
 *  (Is a NULL viewport valid?)
 *
 *****************************************************************************/
1685
static HRESULT WINAPI d3d_device3_SetCurrentViewport(IDirect3DDevice3 *iface, IDirect3DViewport3 *Direct3DViewport3)
1686
{
1687
    struct d3d_device *This = impl_from_IDirect3DDevice3(iface);
1688
    struct d3d_viewport *vp = unsafe_impl_from_IDirect3DViewport3(Direct3DViewport3);
1689 1690

    TRACE("iface %p, viewport %p.\n", iface, Direct3DViewport3);
1691

1692
    wined3d_mutex_lock();
1693 1694
    /* Do nothing if the specified viewport is the same as the current one */
    if (This->current_viewport == vp )
1695
    {
1696
        wined3d_mutex_unlock();
1697 1698
        return D3D_OK;
    }
1699

1700 1701 1702
    if (vp->active_device != This)
    {
        WARN("Viewport %p active device is %p.\n", vp, vp->active_device);
1703
        wined3d_mutex_unlock();
1704 1705
        return DDERR_INVALIDPARAMS;
    }
1706 1707 1708 1709

    /* Release previous viewport and AddRef the new one */
    if (This->current_viewport)
    {
1710
        TRACE("ViewportImpl is at %p, interface is at %p\n", This->current_viewport,
1711 1712
                &This->current_viewport->IDirect3DViewport3_iface);
        IDirect3DViewport3_Release(&This->current_viewport->IDirect3DViewport3_iface);
1713 1714 1715 1716 1717 1718 1719
    }
    IDirect3DViewport3_AddRef(Direct3DViewport3);

    /* Set this viewport as the current viewport */
    This->current_viewport = vp;

    /* Activate this viewport */
1720
    viewport_activate(This->current_viewport, FALSE);
1721

1722 1723
    wined3d_mutex_unlock();

1724 1725 1726
    return D3D_OK;
}

1727
static HRESULT WINAPI d3d_device2_SetCurrentViewport(IDirect3DDevice2 *iface, IDirect3DViewport2 *viewport)
1728
{
1729 1730
    struct d3d_device *device = impl_from_IDirect3DDevice2(iface);
    struct d3d_viewport *vp = unsafe_impl_from_IDirect3DViewport2(viewport);
1731

1732
    TRACE("iface %p, viewport %p.\n", iface, viewport);
1733

1734
    return d3d_device3_SetCurrentViewport(&device->IDirect3DDevice3_iface, &vp->IDirect3DViewport3_iface);
1735 1736 1737 1738 1739 1740 1741 1742 1743 1744 1745 1746 1747 1748 1749 1750 1751
}

/*****************************************************************************
 * IDirect3DDevice3::GetCurrentViewport
 *
 * Returns the currently active viewport.
 *
 * Version 2 and 3
 *
 * Params:
 *  Direct3DViewport3: Address to return the interface pointer at
 *
 * Returns:
 *  D3D_OK on success
 *  DDERR_INVALIDPARAMS if Direct3DViewport == NULL
 *
 *****************************************************************************/
1752
static HRESULT WINAPI d3d_device3_GetCurrentViewport(IDirect3DDevice3 *iface, IDirect3DViewport3 **viewport)
1753
{
1754
    struct d3d_device *device = impl_from_IDirect3DDevice3(iface);
1755

1756
    TRACE("iface %p, viewport %p.\n", iface, viewport);
1757

1758
    if (!viewport)
1759 1760
        return DDERR_INVALIDPARAMS;

1761
    wined3d_mutex_lock();
1762
    *viewport = &device->current_viewport->IDirect3DViewport3_iface;
1763 1764

    /* AddRef the returned viewport */
1765 1766
    if (*viewport)
        IDirect3DViewport3_AddRef(*viewport);
1767

1768
    TRACE("Returning interface %p.\n", *viewport);
1769

1770 1771
    wined3d_mutex_unlock();

1772 1773 1774
    return D3D_OK;
}

1775
static HRESULT WINAPI d3d_device2_GetCurrentViewport(IDirect3DDevice2 *iface, IDirect3DViewport2 **viewport)
1776
{
1777
    struct d3d_device *device = impl_from_IDirect3DDevice2(iface);
1778

1779
    TRACE("iface %p, viewport %p.\n", iface, viewport);
1780

1781 1782
    return d3d_device3_GetCurrentViewport(&device->IDirect3DDevice3_iface,
            (IDirect3DViewport3 **)viewport);
1783 1784 1785 1786 1787 1788 1789 1790 1791 1792 1793 1794 1795 1796 1797 1798 1799 1800 1801 1802
}

/*****************************************************************************
 * IDirect3DDevice7::SetRenderTarget
 *
 * Sets the render target for the Direct3DDevice.
 * For the thunks note that IDirectDrawSurface7 == IDirectDrawSurface4 and
 * IDirectDrawSurface3 == IDirectDrawSurface
 *
 * Version 2, 3 and 7
 *
 * Params:
 *  NewTarget: Pointer to an IDirectDrawSurface7 interface to set as the new
 *             render target
 *  Flags: Some flags
 *
 * Returns:
 *  D3D_OK on success, for details see IWineD3DDevice::SetRenderTarget
 *
 *****************************************************************************/
1803
static HRESULT d3d_device_set_render_target(struct d3d_device *device, struct ddraw_surface *target)
1804
{
1805
    HRESULT hr;
1806

1807
    wined3d_mutex_lock();
1808

1809
    if (device->target == target)
1810 1811
    {
        TRACE("No-op SetRenderTarget operation, not doing anything\n");
1812
        wined3d_mutex_unlock();
1813 1814
        return D3D_OK;
    }
1815 1816
    device->target = target;
    hr = wined3d_device_set_render_target(device->wined3d_device, 0,
1817
            target ? target->wined3d_surface : NULL, FALSE);
1818 1819
    if(hr != D3D_OK)
    {
1820
        wined3d_mutex_unlock();
1821 1822
        return hr;
    }
1823
    d3d_device_update_depth_stencil(device);
1824 1825 1826

    wined3d_mutex_unlock();

1827
    return D3D_OK;
1828 1829
}

1830 1831
static HRESULT d3d_device7_SetRenderTarget(IDirect3DDevice7 *iface,
        IDirectDrawSurface7 *NewTarget, DWORD flags)
1832
{
1833
    struct d3d_device *device = impl_from_IDirect3DDevice7(iface);
1834
    struct ddraw_surface *target = unsafe_impl_from_IDirectDrawSurface7(NewTarget);
1835

1836
    TRACE("iface %p, target %p, flags %#x.\n", iface, NewTarget, flags);
1837 1838

    IDirectDrawSurface7_AddRef(NewTarget);
1839 1840
    IDirectDrawSurface7_Release(&device->target->IDirectDrawSurface7_iface);
    return d3d_device_set_render_target(device, target);
1841 1842
}

1843 1844
static HRESULT WINAPI d3d_device7_SetRenderTarget_FPUSetup(IDirect3DDevice7 *iface,
        IDirectDrawSurface7 *NewTarget, DWORD flags)
1845
{
1846
    return d3d_device7_SetRenderTarget(iface, NewTarget, flags);
1847 1848
}

1849 1850
static HRESULT WINAPI d3d_device7_SetRenderTarget_FPUPreserve(IDirect3DDevice7 *iface,
        IDirectDrawSurface7 *NewTarget, DWORD flags)
1851 1852 1853 1854 1855
{
    HRESULT hr;
    WORD old_fpucw;

    old_fpucw = d3d_fpu_setup();
1856
    hr = d3d_device7_SetRenderTarget(iface, NewTarget, flags);
1857 1858 1859 1860 1861
    set_fpu_control_word(old_fpucw);

    return hr;
}

1862 1863
static HRESULT WINAPI d3d_device3_SetRenderTarget(IDirect3DDevice3 *iface,
        IDirectDrawSurface4 *NewRenderTarget, DWORD flags)
1864
{
1865
    struct d3d_device *device = impl_from_IDirect3DDevice3(iface);
1866
    struct ddraw_surface *target = unsafe_impl_from_IDirectDrawSurface4(NewRenderTarget);
1867

1868
    TRACE("iface %p, target %p, flags %#x.\n", iface, NewRenderTarget, flags);
1869

1870
    IDirectDrawSurface4_AddRef(NewRenderTarget);
1871 1872
    IDirectDrawSurface4_Release(&device->target->IDirectDrawSurface4_iface);
    return d3d_device_set_render_target(device, target);
1873 1874
}

1875 1876
static HRESULT WINAPI d3d_device2_SetRenderTarget(IDirect3DDevice2 *iface,
        IDirectDrawSurface *NewRenderTarget, DWORD flags)
1877
{
1878
    struct d3d_device *device = impl_from_IDirect3DDevice2(iface);
1879
    struct ddraw_surface *target = unsafe_impl_from_IDirectDrawSurface(NewRenderTarget);
1880

1881
    TRACE("iface %p, target %p, flags %#x.\n", iface, NewRenderTarget, flags);
1882

1883
    IDirectDrawSurface_AddRef(NewRenderTarget);
1884 1885
    IDirectDrawSurface_Release(&device->target->IDirectDrawSurface_iface);
    return d3d_device_set_render_target(device, target);
1886 1887 1888 1889 1890 1891 1892 1893 1894 1895 1896 1897 1898 1899 1900 1901 1902 1903 1904
}

/*****************************************************************************
 * IDirect3DDevice7::GetRenderTarget
 *
 * Returns the current render target.
 * This is handled locally, because the WineD3D render target's parent
 * is an IParent
 *
 * Version 2, 3 and 7
 *
 * Params:
 *  RenderTarget: Address to store the surface interface pointer
 *
 * Returns:
 *  D3D_OK on success
 *  DDERR_INVALIDPARAMS if RenderTarget == NULL
 *
 *****************************************************************************/
1905
static HRESULT WINAPI d3d_device7_GetRenderTarget(IDirect3DDevice7 *iface, IDirectDrawSurface7 **RenderTarget)
1906
{
1907
    struct d3d_device *device = impl_from_IDirect3DDevice7(iface);
1908 1909

    TRACE("iface %p, target %p.\n", iface, RenderTarget);
1910 1911 1912 1913

    if(!RenderTarget)
        return DDERR_INVALIDPARAMS;

1914
    wined3d_mutex_lock();
1915
    *RenderTarget = &device->target->IDirectDrawSurface7_iface;
1916
    IDirectDrawSurface7_AddRef(*RenderTarget);
1917
    wined3d_mutex_unlock();
1918 1919 1920 1921

    return D3D_OK;
}

1922
static HRESULT WINAPI d3d_device3_GetRenderTarget(IDirect3DDevice3 *iface, IDirectDrawSurface4 **RenderTarget)
1923
{
1924
    struct d3d_device *device = impl_from_IDirect3DDevice3(iface);
1925
    IDirectDrawSurface7 *RenderTarget7;
1926
    struct ddraw_surface *RenderTargetImpl;
1927
    HRESULT hr;
1928 1929 1930

    TRACE("iface %p, target %p.\n", iface, RenderTarget);

1931 1932 1933
    if(!RenderTarget)
        return DDERR_INVALIDPARAMS;

1934
    hr = d3d_device7_GetRenderTarget(&device->IDirect3DDevice7_iface, &RenderTarget7);
1935
    if(hr != D3D_OK) return hr;
1936
    RenderTargetImpl = impl_from_IDirectDrawSurface7(RenderTarget7);
1937
    *RenderTarget = &RenderTargetImpl->IDirectDrawSurface4_iface;
1938 1939
    IDirectDrawSurface4_AddRef(*RenderTarget);
    IDirectDrawSurface7_Release(RenderTarget7);
1940 1941 1942
    return D3D_OK;
}

1943
static HRESULT WINAPI d3d_device2_GetRenderTarget(IDirect3DDevice2 *iface, IDirectDrawSurface **RenderTarget)
1944
{
1945
    struct d3d_device *device = impl_from_IDirect3DDevice2(iface);
1946
    IDirectDrawSurface7 *RenderTarget7;
1947
    struct ddraw_surface *RenderTargetImpl;
1948
    HRESULT hr;
1949 1950 1951

    TRACE("iface %p, target %p.\n", iface, RenderTarget);

1952 1953 1954
    if(!RenderTarget)
        return DDERR_INVALIDPARAMS;

1955
    hr = d3d_device7_GetRenderTarget(&device->IDirect3DDevice7_iface, &RenderTarget7);
1956
    if(hr != D3D_OK) return hr;
1957
    RenderTargetImpl = impl_from_IDirectDrawSurface7(RenderTarget7);
1958
    *RenderTarget = &RenderTargetImpl->IDirectDrawSurface_iface;
1959 1960
    IDirectDrawSurface_AddRef(*RenderTarget);
    IDirectDrawSurface7_Release(RenderTarget7);
1961 1962 1963 1964 1965 1966
    return D3D_OK;
}

/*****************************************************************************
 * IDirect3DDevice3::Begin
 *
1967
 * Begins a description block of vertices. This is similar to glBegin()
1968 1969 1970 1971 1972 1973 1974 1975 1976 1977 1978 1979 1980 1981
 * and glEnd(). After a call to IDirect3DDevice3::End, the vertices
 * described with IDirect3DDevice::Vertex are drawn.
 *
 * Version 2 and 3
 *
 * Params:
 *  PrimitiveType: The type of primitives to draw
 *  VertexTypeDesc: A flexible vertex format description of the vertices
 *  Flags: Some flags..
 *
 * Returns:
 *  D3D_OK on success
 *
 *****************************************************************************/
1982 1983
static HRESULT WINAPI d3d_device3_Begin(IDirect3DDevice3 *iface,
        D3DPRIMITIVETYPE primitive_type, DWORD fvf, DWORD flags)
1984
{
1985
    struct d3d_device *device = impl_from_IDirect3DDevice3(iface);
1986

1987 1988
    TRACE("iface %p, primitive_type %#x, fvf %#x, flags %#x.\n",
            iface, primitive_type, fvf, flags);
1989

1990
    wined3d_mutex_lock();
1991 1992 1993 1994 1995
    device->primitive_type = primitive_type;
    device->vertex_type = fvf;
    device->render_flags = flags;
    device->vertex_size = get_flexible_vertex_size(device->vertex_type);
    device->nb_vertices = 0;
1996
    wined3d_mutex_unlock();
1997 1998 1999 2000

    return D3D_OK;
}

2001 2002
static HRESULT WINAPI d3d_device2_Begin(IDirect3DDevice2 *iface,
        D3DPRIMITIVETYPE primitive_type, D3DVERTEXTYPE vertex_type, DWORD flags)
2003
{
2004 2005
    struct d3d_device *device = impl_from_IDirect3DDevice2(iface);
    DWORD fvf;
2006 2007

    TRACE("iface %p, primitive_type %#x, vertex_type %#x, flags %#x.\n",
2008
            iface, primitive_type, vertex_type, flags);
2009

2010
    switch (vertex_type)
2011
    {
2012 2013 2014
        case D3DVT_VERTEX: fvf = D3DFVF_VERTEX; break;
        case D3DVT_LVERTEX: fvf = D3DFVF_LVERTEX; break;
        case D3DVT_TLVERTEX: fvf = D3DFVF_TLVERTEX; break;
2015
        default:
2016
            ERR("Unexpected vertex type %#x.\n", vertex_type);
2017
            return DDERR_INVALIDPARAMS;  /* Should never happen */
2018 2019
    };

2020
    return d3d_device3_Begin(&device->IDirect3DDevice3_iface, primitive_type, fvf, flags);
2021 2022 2023 2024 2025 2026 2027 2028 2029 2030 2031 2032 2033
}

/*****************************************************************************
 * IDirect3DDevice3::BeginIndexed
 *
 * Draws primitives based on vertices in a vertex array which are specified
 * by indices.
 *
 * Version 2 and 3
 *
 * Params:
 *  PrimitiveType: Primitive type to draw
 *  VertexType: A FVF description of the vertex format
2034
 *  Vertices: pointer to an array containing the vertices
2035 2036 2037 2038 2039 2040 2041
 *  NumVertices: The number of vertices in the vertex array
 *  Flags: Some flags ...
 *
 * Returns:
 *  D3D_OK, because it's a stub
 *
 *****************************************************************************/
2042 2043 2044
static HRESULT WINAPI d3d_device3_BeginIndexed(IDirect3DDevice3 *iface,
        D3DPRIMITIVETYPE primitive_type, DWORD fvf,
        void *vertices, DWORD vertex_count, DWORD flags)
2045
{
2046 2047
    FIXME("iface %p, primitive_type %#x, fvf %#x, vertices %p, vertex_count %u, flags %#x stub!\n",
            iface, primitive_type, fvf, vertices, vertex_count, flags);
2048

2049 2050 2051 2052
    return D3D_OK;
}


2053 2054 2055
static HRESULT WINAPI d3d_device2_BeginIndexed(IDirect3DDevice2 *iface,
        D3DPRIMITIVETYPE primitive_type, D3DVERTEXTYPE vertex_type,
        void *vertices, DWORD vertex_count, DWORD flags)
2056
{
2057 2058
    struct d3d_device *device = impl_from_IDirect3DDevice2(iface);
    DWORD fvf;
2059 2060

    TRACE("iface %p, primitive_type %#x, vertex_type %#x, vertices %p, vertex_count %u, flags %#x stub!\n",
2061
            iface, primitive_type, vertex_type, vertices, vertex_count, flags);
2062

2063
    switch (vertex_type)
2064
    {
2065 2066 2067
        case D3DVT_VERTEX: fvf = D3DFVF_VERTEX; break;
        case D3DVT_LVERTEX: fvf = D3DFVF_LVERTEX; break;
        case D3DVT_TLVERTEX: fvf = D3DFVF_TLVERTEX; break;
2068
        default:
2069
            ERR("Unexpected vertex type %#x.\n", vertex_type);
2070
            return DDERR_INVALIDPARAMS;  /* Should never happen */
2071 2072
    };

2073 2074
    return d3d_device3_BeginIndexed(&device->IDirect3DDevice3_iface,
            primitive_type, fvf, vertices, vertex_count, flags);
2075 2076 2077 2078 2079 2080
}

/*****************************************************************************
 * IDirect3DDevice3::Vertex
 *
 * Draws a vertex as described by IDirect3DDevice3::Begin. It places all
2081
 * drawn vertices in a vertex buffer. If the buffer is too small, its
2082 2083 2084 2085 2086 2087 2088 2089 2090 2091 2092 2093
 * size is increased.
 *
 * Version 2 and 3
 *
 * Params:
 *  Vertex: Pointer to the vertex
 *
 * Returns:
 *  D3D_OK, on success
 *  DDERR_INVALIDPARAMS if Vertex is NULL
 *
 *****************************************************************************/
2094
static HRESULT WINAPI d3d_device3_Vertex(IDirect3DDevice3 *iface, void *vertex)
2095
{
2096
    struct d3d_device *device = impl_from_IDirect3DDevice3(iface);
2097

2098
    TRACE("iface %p, vertex %p.\n", iface, vertex);
2099

2100
    if (!vertex)
2101 2102
        return DDERR_INVALIDPARAMS;

2103
    wined3d_mutex_lock();
2104
    if ((device->nb_vertices + 1) * device->vertex_size > device->buffer_size)
2105 2106
    {
        BYTE *old_buffer;
2107 2108 2109 2110

        device->buffer_size = device->buffer_size ? device->buffer_size * 2 : device->vertex_size * 3;
        old_buffer = device->vertex_buffer;
        device->vertex_buffer = HeapAlloc(GetProcessHeap(), 0, device->buffer_size);
2111 2112
        if (old_buffer)
        {
2113
            memcpy(device->vertex_buffer, old_buffer, device->nb_vertices * device->vertex_size);
2114 2115 2116 2117
            HeapFree(GetProcessHeap(), 0, old_buffer);
        }
    }

2118
    memcpy(device->vertex_buffer + device->nb_vertices++ * device->vertex_size, vertex, device->vertex_size);
2119
    wined3d_mutex_unlock();
2120 2121 2122 2123

    return D3D_OK;
}

2124
static HRESULT WINAPI d3d_device2_Vertex(IDirect3DDevice2 *iface, void *vertex)
2125
{
2126
    struct d3d_device *device = impl_from_IDirect3DDevice2(iface);
2127

2128
    TRACE("iface %p, vertex %p.\n", iface, vertex);
2129

2130
    return d3d_device3_Vertex(&device->IDirect3DDevice3_iface, vertex);
2131 2132 2133 2134 2135
}

/*****************************************************************************
 * IDirect3DDevice3::Index
 *
2136
 * Specifies an index to a vertex to be drawn. The vertex array has to
2137 2138 2139 2140 2141 2142 2143 2144 2145
 * be specified with BeginIndexed first.
 *
 * Parameters:
 *  VertexIndex: The index of the vertex to draw
 *
 * Returns:
 *  D3D_OK because it's a stub
 *
 *****************************************************************************/
2146
static HRESULT WINAPI d3d_device3_Index(IDirect3DDevice3 *iface, WORD index)
2147
{
2148
    FIXME("iface %p, index %#x stub!\n", iface, index);
2149

2150 2151 2152
    return D3D_OK;
}

2153
static HRESULT WINAPI d3d_device2_Index(IDirect3DDevice2 *iface, WORD index)
2154
{
2155
    struct d3d_device *device = impl_from_IDirect3DDevice2(iface);
2156

2157
    TRACE("iface %p, index %#x.\n", iface, index);
2158

2159
    return d3d_device3_Index(&device->IDirect3DDevice3_iface, index);
2160 2161 2162 2163 2164 2165 2166 2167 2168 2169 2170 2171 2172 2173 2174 2175 2176 2177 2178 2179
}

/*****************************************************************************
 * IDirect3DDevice3::End
 *
 * Ends a draw begun with IDirect3DDevice3::Begin or
 * IDirect3DDevice::BeginIndexed. The vertices specified with
 * IDirect3DDevice::Vertex or IDirect3DDevice::Index are drawn using
 * the IDirect3DDevice7::DrawPrimitive method. So far only
 * non-indexed mode is supported
 *
 * Version 2 and 3
 *
 * Params:
 *  Flags: Some flags, as usual. Don't know which are defined
 *
 * Returns:
 *  The return value of IDirect3DDevice7::DrawPrimitive
 *
 *****************************************************************************/
2180
static HRESULT WINAPI d3d_device3_End(IDirect3DDevice3 *iface, DWORD flags)
2181
{
2182
    struct d3d_device *device = impl_from_IDirect3DDevice3(iface);
2183

2184
    TRACE("iface %p, flags %#x.\n", iface, flags);
2185

2186 2187
    return IDirect3DDevice7_DrawPrimitive(&device->IDirect3DDevice7_iface, device->primitive_type,
            device->vertex_type, device->vertex_buffer, device->nb_vertices, device->render_flags);
2188 2189
}

2190
static HRESULT WINAPI d3d_device2_End(IDirect3DDevice2 *iface, DWORD flags)
2191
{
2192
    struct d3d_device *device = impl_from_IDirect3DDevice2(iface);
2193

2194
    TRACE("iface %p, flags %#x.\n", iface, flags);
2195

2196
    return d3d_device3_End(&device->IDirect3DDevice3_iface, flags);
2197 2198 2199 2200 2201 2202 2203 2204 2205 2206 2207 2208 2209 2210 2211 2212 2213 2214 2215
}

/*****************************************************************************
 * IDirect3DDevice7::GetRenderState
 *
 * Returns the value of a render state. The possible render states are
 * defined in include/d3dtypes.h
 *
 * Version 2, 3 and 7
 *
 * Params:
 *  RenderStateType: Render state to return the current setting of
 *  Value: Address to store the value at
 *
 * Returns:
 *  D3D_OK on success, for details see IWineD3DDevice::GetRenderState
 *  DDERR_INVALIDPARAMS if Value == NULL
 *
 *****************************************************************************/
2216 2217
static HRESULT d3d_device7_GetRenderState(IDirect3DDevice7 *iface,
        D3DRENDERSTATETYPE state, DWORD *value)
2218
{
2219
    struct d3d_device *device = impl_from_IDirect3DDevice7(iface);
2220
    HRESULT hr = D3D_OK;
2221

2222
    TRACE("iface %p, state %#x, value %p.\n", iface, state, value);
2223

2224
    if (!value)
2225 2226
        return DDERR_INVALIDPARAMS;

2227
    wined3d_mutex_lock();
2228
    switch (state)
2229
    {
2230 2231
        case D3DRENDERSTATE_TEXTUREMAG:
        {
2232
            enum wined3d_texture_filter_type tex_mag;
2233

2234
            tex_mag = wined3d_device_get_sampler_state(device->wined3d_device, 0, WINED3D_SAMP_MAG_FILTER);
2235 2236
            switch (tex_mag)
            {
2237
                case WINED3D_TEXF_POINT:
2238
                    *value = D3DFILTER_NEAREST;
2239
                    break;
2240
                case WINED3D_TEXF_LINEAR:
2241
                    *value = D3DFILTER_LINEAR;
2242 2243 2244
                    break;
                default:
                    ERR("Unhandled texture mag %d !\n",tex_mag);
2245
                    *value = 0;
2246
            }
2247
            break;
2248 2249 2250 2251
        }

        case D3DRENDERSTATE_TEXTUREMIN:
        {
2252 2253
            enum wined3d_texture_filter_type tex_min;
            enum wined3d_texture_filter_type tex_mip;
2254

2255 2256
            tex_min = wined3d_device_get_sampler_state(device->wined3d_device, 0, WINED3D_SAMP_MIN_FILTER);
            tex_mip = wined3d_device_get_sampler_state(device->wined3d_device, 0, WINED3D_SAMP_MIP_FILTER);
2257 2258
            switch (tex_min)
            {
2259
                case WINED3D_TEXF_POINT:
2260 2261
                    switch (tex_mip)
                    {
2262
                        case WINED3D_TEXF_NONE:
2263
                            *value = D3DFILTER_NEAREST;
2264
                            break;
2265
                        case WINED3D_TEXF_POINT:
2266
                            *value = D3DFILTER_MIPNEAREST;
2267
                            break;
2268
                        case WINED3D_TEXF_LINEAR:
2269
                            *value = D3DFILTER_LINEARMIPNEAREST;
2270 2271 2272
                            break;
                        default:
                            ERR("Unhandled mip filter %#x.\n", tex_mip);
2273
                            *value = D3DFILTER_NEAREST;
2274 2275
                            break;
                    }
2276
                    break;
2277
                case WINED3D_TEXF_LINEAR:
2278 2279
                    switch (tex_mip)
                    {
2280
                        case WINED3D_TEXF_NONE:
2281
                            *value = D3DFILTER_LINEAR;
2282
                            break;
2283
                        case WINED3D_TEXF_POINT:
2284
                            *value = D3DFILTER_MIPLINEAR;
2285
                            break;
2286
                        case WINED3D_TEXF_LINEAR:
2287
                            *value = D3DFILTER_LINEARMIPLINEAR;
2288 2289 2290
                            break;
                        default:
                            ERR("Unhandled mip filter %#x.\n", tex_mip);
2291
                            *value = D3DFILTER_LINEAR;
2292 2293
                            break;
                    }
2294 2295
                    break;
                default:
2296
                    ERR("Unhandled texture min filter %#x.\n",tex_min);
2297
                    *value = D3DFILTER_NEAREST;
2298
                    break;
2299
            }
2300
            break;
2301 2302
        }

2303
        case D3DRENDERSTATE_TEXTUREADDRESS:
2304
        case D3DRENDERSTATE_TEXTUREADDRESSU:
2305
            *value = wined3d_device_get_sampler_state(device->wined3d_device, 0, WINED3D_SAMP_ADDRESS_U);
2306
            break;
2307
        case D3DRENDERSTATE_TEXTUREADDRESSV:
2308
            *value = wined3d_device_get_sampler_state(device->wined3d_device, 0, WINED3D_SAMP_ADDRESS_V);
2309
            break;
2310

2311 2312 2313 2314 2315
        case D3DRENDERSTATE_BORDERCOLOR:
            FIXME("Unhandled render state D3DRENDERSTATE_BORDERCOLOR.\n");
            hr = E_NOTIMPL;
            break;

2316 2317
        case D3DRENDERSTATE_TEXTUREHANDLE:
        case D3DRENDERSTATE_TEXTUREMAPBLEND:
2318
            WARN("Render state %#x is invalid in d3d7.\n", state);
2319 2320 2321
            hr = DDERR_INVALIDPARAMS;
            break;

2322
        case D3DRENDERSTATE_ZBIAS:
2323
            *value = wined3d_device_get_render_state(device->wined3d_device, WINED3D_RS_DEPTHBIAS);
2324
            break;
2325

2326
        default:
2327 2328
            if (state >= D3DRENDERSTATE_STIPPLEPATTERN00
                    && state <= D3DRENDERSTATE_STIPPLEPATTERN31)
2329
            {
2330
                FIXME("Unhandled stipple pattern render state (%#x).\n", state);
2331 2332 2333
                hr = E_NOTIMPL;
                break;
            }
2334
            *value = wined3d_device_get_render_state(device->wined3d_device, state);
2335
    }
2336 2337
    wined3d_mutex_unlock();

2338
    return hr;
2339 2340
}

2341 2342
static HRESULT WINAPI d3d_device7_GetRenderState_FPUSetup(IDirect3DDevice7 *iface,
        D3DRENDERSTATETYPE state, DWORD *value)
2343
{
2344
    return d3d_device7_GetRenderState(iface, state, value);
2345 2346
}

2347 2348
static HRESULT WINAPI d3d_device7_GetRenderState_FPUPreserve(IDirect3DDevice7 *iface,
        D3DRENDERSTATETYPE state, DWORD *value)
2349 2350 2351 2352 2353
{
    HRESULT hr;
    WORD old_fpucw;

    old_fpucw = d3d_fpu_setup();
2354
    hr = d3d_device7_GetRenderState(iface, state, value);
2355 2356 2357 2358 2359
    set_fpu_control_word(old_fpucw);

    return hr;
}

2360 2361
static HRESULT WINAPI d3d_device3_GetRenderState(IDirect3DDevice3 *iface,
        D3DRENDERSTATETYPE state, DWORD *value)
2362
{
2363
    struct d3d_device *device = impl_from_IDirect3DDevice3(iface);
2364

2365
    TRACE("iface %p, state %#x, value %p.\n", iface, state, value);
2366

2367
    switch (state)
2368 2369 2370 2371
    {
        case D3DRENDERSTATE_TEXTUREHANDLE:
        {
            /* This state is wrapped to SetTexture in SetRenderState, so
2372 2373
             * it has to be wrapped to GetTexture here. */
            struct wined3d_texture *tex = NULL;
2374
            *value = 0;
2375

2376
            wined3d_mutex_lock();
2377
            if ((tex = wined3d_device_get_texture(device->wined3d_device, 0)))
2378
            {
2379 2380
                /* The parent of the texture is the IDirectDrawSurface7
                 * interface of the ddraw surface. */
2381
                struct ddraw_surface *parent = wined3d_texture_get_parent(tex);
2382 2383
                if (parent)
                    *value = parent->Handle;
2384
            }
2385
            wined3d_mutex_unlock();
2386

2387
            return D3D_OK;
2388 2389
        }

2390 2391
        case D3DRENDERSTATE_TEXTUREMAPBLEND:
        {
2392 2393
            /* D3DRENDERSTATE_TEXTUREMAPBLEND is mapped to texture state stages in SetRenderState; reverse
               the mapping to get the value. */
2394 2395 2396
            DWORD colorop, colorarg1, colorarg2;
            DWORD alphaop, alphaarg1, alphaarg2;

2397
            wined3d_mutex_lock();
2398

2399
            device->legacyTextureBlending = TRUE;
2400

2401 2402 2403 2404 2405 2406
            colorop = wined3d_device_get_texture_stage_state(device->wined3d_device, 0, WINED3D_TSS_COLOR_OP);
            colorarg1 = wined3d_device_get_texture_stage_state(device->wined3d_device, 0, WINED3D_TSS_COLOR_ARG1);
            colorarg2 = wined3d_device_get_texture_stage_state(device->wined3d_device, 0, WINED3D_TSS_COLOR_ARG2);
            alphaop = wined3d_device_get_texture_stage_state(device->wined3d_device, 0, WINED3D_TSS_ALPHA_OP);
            alphaarg1 = wined3d_device_get_texture_stage_state(device->wined3d_device, 0, WINED3D_TSS_ALPHA_ARG1);
            alphaarg2 = wined3d_device_get_texture_stage_state(device->wined3d_device, 0, WINED3D_TSS_ALPHA_ARG2);
2407

2408 2409
            if (colorop == WINED3D_TOP_SELECT_ARG1 && colorarg1 == WINED3DTA_TEXTURE
                    && alphaop == WINED3D_TOP_SELECT_ARG1 && alphaarg1 == WINED3DTA_TEXTURE)
2410
                *value = D3DTBLEND_DECAL;
2411 2412 2413
            else if (colorop == WINED3D_TOP_SELECT_ARG1 && colorarg1 == WINED3DTA_TEXTURE
                    && alphaop == WINED3D_TOP_MODULATE
                    && alphaarg1 == WINED3DTA_TEXTURE && alphaarg2 == WINED3DTA_CURRENT)
2414
                *value = D3DTBLEND_DECALALPHA;
2415 2416 2417 2418
            else if (colorop == WINED3D_TOP_MODULATE
                    && colorarg1 == WINED3DTA_TEXTURE && colorarg2 == WINED3DTA_CURRENT
                    && alphaop == WINED3D_TOP_MODULATE
                    && alphaarg1 == WINED3DTA_TEXTURE && alphaarg2 == WINED3DTA_CURRENT)
2419
                *value = D3DTBLEND_MODULATEALPHA;
2420 2421
            else
            {
2422
                struct wined3d_texture *tex = NULL;
2423 2424 2425
                BOOL tex_alpha = FALSE;
                DDPIXELFORMAT ddfmt;

2426
                if ((tex = wined3d_device_get_texture(device->wined3d_device, 0)))
2427
                {
2428 2429
                    struct wined3d_resource *sub_resource;

2430
                    if ((sub_resource = wined3d_texture_get_sub_resource(tex, 0)))
2431
                    {
2432 2433 2434
                        struct wined3d_resource_desc desc;

                        wined3d_resource_get_desc(sub_resource, &desc);
2435
                        ddfmt.dwSize = sizeof(ddfmt);
2436
                        PixelFormat_WineD3DtoDD(&ddfmt, desc.format);
2437 2438 2439 2440
                        if (ddfmt.u5.dwRGBAlphaBitMask) tex_alpha = TRUE;
                    }
                }

2441 2442 2443 2444 2445
                if (!(colorop == WINED3D_TOP_MODULATE
                        && colorarg1 == WINED3DTA_TEXTURE && colorarg2 == WINED3DTA_CURRENT
                        && alphaop == (tex_alpha ? WINED3D_TOP_SELECT_ARG1 : WINED3D_TOP_SELECT_ARG2)
                        && alphaarg1 == WINED3DTA_TEXTURE && alphaarg2 == WINED3DTA_CURRENT))
                    ERR("Unexpected texture stage state setup, returning D3DTBLEND_MODULATE - likely erroneous.\n");
2446

2447
                *value = D3DTBLEND_MODULATE;
2448 2449
            }

2450
            wined3d_mutex_unlock();
2451 2452 2453 2454 2455

            return D3D_OK;
        }

        default:
2456
            return IDirect3DDevice7_GetRenderState(&device->IDirect3DDevice7_iface, state, value);
2457
    }
2458 2459
}

2460 2461
static HRESULT WINAPI d3d_device2_GetRenderState(IDirect3DDevice2 *iface,
        D3DRENDERSTATETYPE state, DWORD *value)
2462
{
2463
    struct d3d_device *device = impl_from_IDirect3DDevice2(iface);
2464

2465
    TRACE("iface %p, state %#x, value %p.\n", iface, state, value);
2466

2467
    return IDirect3DDevice3_GetRenderState(&device->IDirect3DDevice3_iface, state, value);
2468 2469
}

2470 2471 2472 2473 2474 2475 2476 2477 2478 2479 2480 2481 2482 2483 2484 2485 2486
/*****************************************************************************
 * IDirect3DDevice7::SetRenderState
 *
 * Sets a render state. The possible render states are defined in
 * include/d3dtypes.h
 *
 * Version 2, 3 and 7
 *
 * Params:
 *  RenderStateType: State to set
 *  Value: Value to assign to that state
 *
 * Returns:
 *  D3D_OK on success,
 *  for details see IWineD3DDevice::SetRenderState
 *
 *****************************************************************************/
2487 2488
static HRESULT d3d_device7_SetRenderState(IDirect3DDevice7 *iface,
        D3DRENDERSTATETYPE state, DWORD value)
2489
{
2490
    struct d3d_device *device = impl_from_IDirect3DDevice7(iface);
2491
    HRESULT hr = D3D_OK;
2492

2493
    TRACE("iface %p, state %#x, value %#x.\n", iface, state, value);
2494

2495
    wined3d_mutex_lock();
2496
    /* Some render states need special care */
2497
    switch (state)
2498
    {
2499 2500 2501 2502 2503 2504 2505 2506 2507 2508 2509 2510 2511
        /*
         * The ddraw texture filter mapping works like this:
         *     D3DFILTER_NEAREST            Point min/mag, no mip
         *     D3DFILTER_MIPNEAREST         Point min/mag, point mip
         *     D3DFILTER_LINEARMIPNEAREST:  Point min/mag, linear mip
         *
         *     D3DFILTER_LINEAR             Linear min/mag, no mip
         *     D3DFILTER_MIPLINEAR          Linear min/mag, point mip
         *     D3DFILTER_LINEARMIPLINEAR    Linear min/mag, linear mip
         *
         * This is the opposite of the GL naming convention,
         * D3DFILTER_LINEARMIPNEAREST corresponds to GL_NEAREST_MIPMAP_LINEAR.
         */
2512 2513
        case D3DRENDERSTATE_TEXTUREMAG:
        {
2514
            enum wined3d_texture_filter_type tex_mag;
2515

2516
            switch (value)
2517 2518
            {
                case D3DFILTER_NEAREST:
2519
                case D3DFILTER_MIPNEAREST:
2520
                case D3DFILTER_LINEARMIPNEAREST:
2521
                    tex_mag = WINED3D_TEXF_POINT;
2522 2523
                    break;
                case D3DFILTER_LINEAR:
2524
                case D3DFILTER_MIPLINEAR:
2525
                case D3DFILTER_LINEARMIPLINEAR:
2526
                    tex_mag = WINED3D_TEXF_LINEAR;
2527 2528
                    break;
                default:
2529
                    tex_mag = WINED3D_TEXF_POINT;
2530
                    FIXME("Unhandled texture mag %#x.\n", value);
2531
                    break;
2532 2533
            }

2534
            wined3d_device_set_sampler_state(device->wined3d_device, 0, WINED3D_SAMP_MAG_FILTER, tex_mag);
2535
            break;
2536 2537 2538 2539
        }

        case D3DRENDERSTATE_TEXTUREMIN:
        {
2540 2541
            enum wined3d_texture_filter_type tex_min;
            enum wined3d_texture_filter_type tex_mip;
2542

2543
            switch (value)
2544 2545
            {
                case D3DFILTER_NEAREST:
2546 2547
                    tex_min = WINED3D_TEXF_POINT;
                    tex_mip = WINED3D_TEXF_NONE;
2548 2549
                    break;
                case D3DFILTER_LINEAR:
2550 2551
                    tex_min = WINED3D_TEXF_LINEAR;
                    tex_mip = WINED3D_TEXF_NONE;
2552
                    break;
2553
                case D3DFILTER_MIPNEAREST:
2554 2555
                    tex_min = WINED3D_TEXF_POINT;
                    tex_mip = WINED3D_TEXF_POINT;
2556 2557
                    break;
                case D3DFILTER_MIPLINEAR:
2558 2559
                    tex_min = WINED3D_TEXF_LINEAR;
                    tex_mip = WINED3D_TEXF_POINT;
2560 2561
                    break;
                case D3DFILTER_LINEARMIPNEAREST:
2562 2563
                    tex_min = WINED3D_TEXF_POINT;
                    tex_mip = WINED3D_TEXF_LINEAR;
2564 2565
                    break;
                case D3DFILTER_LINEARMIPLINEAR:
2566 2567
                    tex_min = WINED3D_TEXF_LINEAR;
                    tex_mip = WINED3D_TEXF_LINEAR;
2568 2569
                    break;

2570
                default:
2571
                    FIXME("Unhandled texture min %#x.\n",value);
2572 2573
                    tex_min = WINED3D_TEXF_POINT;
                    tex_mip = WINED3D_TEXF_NONE;
2574
                    break;
2575 2576
            }

2577
            wined3d_device_set_sampler_state(device->wined3d_device,
2578
                    0, WINED3D_SAMP_MIP_FILTER, tex_mip);
2579
            wined3d_device_set_sampler_state(device->wined3d_device,
2580
                    0, WINED3D_SAMP_MIN_FILTER, tex_min);
2581
            break;
2582 2583
        }

2584
        case D3DRENDERSTATE_TEXTUREADDRESS:
2585 2586
            wined3d_device_set_sampler_state(device->wined3d_device,
                    0, WINED3D_SAMP_ADDRESS_V, value);
2587
            /* Drop through */
2588
        case D3DRENDERSTATE_TEXTUREADDRESSU:
2589
            wined3d_device_set_sampler_state(device->wined3d_device,
2590
                    0, WINED3D_SAMP_ADDRESS_U, value);
2591
            break;
2592
        case D3DRENDERSTATE_TEXTUREADDRESSV:
2593
            wined3d_device_set_sampler_state(device->wined3d_device,
2594
                    0, WINED3D_SAMP_ADDRESS_V, value);
2595
            break;
2596

2597 2598 2599 2600 2601 2602 2603
        case D3DRENDERSTATE_BORDERCOLOR:
            /* This should probably just forward to the corresponding sampler
             * state. Needs tests. */
            FIXME("Unhandled render state D3DRENDERSTATE_BORDERCOLOR.\n");
            hr = E_NOTIMPL;
            break;

2604 2605
        case D3DRENDERSTATE_TEXTUREHANDLE:
        case D3DRENDERSTATE_TEXTUREMAPBLEND:
2606
            WARN("Render state %#x is invalid in d3d7.\n", state);
2607 2608 2609
            hr = DDERR_INVALIDPARAMS;
            break;

2610
        case D3DRENDERSTATE_ZBIAS:
2611
            wined3d_device_set_render_state(device->wined3d_device, WINED3D_RS_DEPTHBIAS, value);
2612 2613
            break;

2614
        default:
2615 2616
            if (state >= D3DRENDERSTATE_STIPPLEPATTERN00
                    && state <= D3DRENDERSTATE_STIPPLEPATTERN31)
2617
            {
2618
                FIXME("Unhandled stipple pattern render state (%#x).\n", state);
2619 2620 2621
                hr = E_NOTIMPL;
                break;
            }
2622

2623
            wined3d_device_set_render_state(device->wined3d_device, state, value);
2624 2625
            break;
    }
2626 2627
    wined3d_mutex_unlock();

2628 2629 2630
    return hr;
}

2631 2632
static HRESULT WINAPI d3d_device7_SetRenderState_FPUSetup(IDirect3DDevice7 *iface,
        D3DRENDERSTATETYPE state, DWORD value)
2633
{
2634
    return d3d_device7_SetRenderState(iface, state, value);
2635 2636
}

2637 2638
static HRESULT WINAPI d3d_device7_SetRenderState_FPUPreserve(IDirect3DDevice7 *iface,
        D3DRENDERSTATETYPE state, DWORD value)
2639 2640 2641 2642 2643
{
    HRESULT hr;
    WORD old_fpucw;

    old_fpucw = d3d_fpu_setup();
2644
    hr = d3d_device7_SetRenderState(iface, state, value);
2645 2646 2647 2648 2649
    set_fpu_control_word(old_fpucw);

    return hr;
}

2650 2651
static HRESULT WINAPI d3d_device3_SetRenderState(IDirect3DDevice3 *iface,
        D3DRENDERSTATETYPE state, DWORD value)
2652
{
2653 2654 2655 2656 2657 2658 2659 2660 2661 2662 2663 2664 2665 2666 2667 2668 2669 2670 2671
    /* Note about D3DRENDERSTATE_TEXTUREMAPBLEND implementation: most of values
    for this state can be directly mapped to texture stage colorop and alphaop, but
    D3DTBLEND_MODULATE is tricky: it uses alpha from texture when available and alpha
    from diffuse otherwise. So changing the texture must be monitored in SetTexture to modify
    alphaarg when needed.

    Aliens vs Predator 1 depends on accurate D3DTBLEND_MODULATE emulation

    Legacy texture blending (TEXTUREMAPBLEND) and texture stage states: directx6 docs state that
    TEXTUREMAPBLEND is deprecated, yet can still be used. Games must not use both or results
    are undefined. D3DTBLEND_MODULATE mode in particular is dependent on texture pixel format and
    requires fixup of stage 0 texture states when texture changes, but this fixup can interfere
    with games not using this deprecated state. So a flag 'legacyTextureBlending' has to be kept
    in device - TRUE if the app is using TEXTUREMAPBLEND.

    Tests show that setting TEXTUREMAPBLEND on native doesn't seem to change values returned by
    GetTextureStageState and vice versa. Not so on Wine, but it is 'undefined' anyway so, probably, ok,
    unless some broken game will be found that cares. */

2672
    struct d3d_device *device = impl_from_IDirect3DDevice3(iface);
2673
    HRESULT hr;
2674

2675
    TRACE("iface %p, state %#x, value %#x.\n", iface, state, value);
2676

2677
    wined3d_mutex_lock();
2678

2679
    switch (state)
2680 2681 2682
    {
        case D3DRENDERSTATE_TEXTUREHANDLE:
        {
2683
            struct ddraw_surface *surf;
2684

2685
            if (value == 0)
2686
            {
2687
                hr = wined3d_device_set_texture(device->wined3d_device, 0, NULL);
2688 2689 2690
                break;
            }

2691
            surf = ddraw_get_object(&device->handle_table, value - 1, DDRAW_HANDLE_SURFACE);
2692
            if (!surf)
2693
            {
2694
                WARN("Invalid texture handle.\n");
2695 2696 2697
                hr = DDERR_INVALIDPARAMS;
                break;
            }
2698

2699
            hr = IDirect3DDevice3_SetTexture(iface, 0, &surf->IDirect3DTexture2_iface);
2700
            break;
2701 2702
        }

2703 2704
        case D3DRENDERSTATE_TEXTUREMAPBLEND:
        {
2705
            device->legacyTextureBlending = TRUE;
2706

2707
            switch (value)
2708 2709
            {
                case D3DTBLEND_MODULATE:
2710
                {
2711
                    struct wined3d_texture *tex = NULL;
2712 2713 2714
                    BOOL tex_alpha = FALSE;
                    DDPIXELFORMAT ddfmt;

2715
                    if ((tex = wined3d_device_get_texture(device->wined3d_device, 0)))
2716
                    {
2717 2718
                        struct wined3d_resource *sub_resource;

2719
                        if ((sub_resource = wined3d_texture_get_sub_resource(tex, 0)))
2720
                        {
2721 2722 2723
                            struct wined3d_resource_desc desc;

                            wined3d_resource_get_desc(sub_resource, &desc);
2724
                            ddfmt.dwSize = sizeof(ddfmt);
2725
                            PixelFormat_WineD3DtoDD(&ddfmt, desc.format);
2726 2727 2728 2729 2730
                            if (ddfmt.u5.dwRGBAlphaBitMask) tex_alpha = TRUE;
                        }
                    }

                    if (tex_alpha)
2731
                        wined3d_device_set_texture_stage_state(device->wined3d_device,
2732
                                0, WINED3D_TSS_ALPHA_OP, WINED3D_TOP_SELECT_ARG1);
2733
                    else
2734
                        wined3d_device_set_texture_stage_state(device->wined3d_device,
2735
                                0, WINED3D_TSS_ALPHA_OP, WINED3D_TOP_SELECT_ARG2);
2736
                    wined3d_device_set_texture_stage_state(device->wined3d_device,
2737
                            0, WINED3D_TSS_ALPHA_ARG1, WINED3DTA_TEXTURE);
2738
                    wined3d_device_set_texture_stage_state(device->wined3d_device,
2739
                            0, WINED3D_TSS_ALPHA_ARG2, WINED3DTA_CURRENT);
2740
                    wined3d_device_set_texture_stage_state(device->wined3d_device,
2741
                            0, WINED3D_TSS_COLOR_ARG1, WINED3DTA_TEXTURE);
2742
                    wined3d_device_set_texture_stage_state(device->wined3d_device,
2743
                            0, WINED3D_TSS_COLOR_ARG2, WINED3DTA_CURRENT);
2744
                    wined3d_device_set_texture_stage_state(device->wined3d_device,
2745
                            0, WINED3D_TSS_COLOR_OP, WINED3D_TOP_MODULATE);
2746
                    break;
2747
                }
2748

2749
                case D3DTBLEND_ADD:
2750
                    wined3d_device_set_texture_stage_state(device->wined3d_device,
2751
                            0, WINED3D_TSS_COLOR_OP, WINED3D_TOP_ADD);
2752
                    wined3d_device_set_texture_stage_state(device->wined3d_device,
2753
                            0, WINED3D_TSS_COLOR_ARG1, WINED3DTA_TEXTURE);
2754
                    wined3d_device_set_texture_stage_state(device->wined3d_device,
2755
                            0, WINED3D_TSS_COLOR_ARG2, WINED3DTA_CURRENT);
2756
                    wined3d_device_set_texture_stage_state(device->wined3d_device,
2757
                            0, WINED3D_TSS_ALPHA_OP, WINED3D_TOP_SELECT_ARG2);
2758
                    wined3d_device_set_texture_stage_state(device->wined3d_device,
2759
                            0, WINED3D_TSS_ALPHA_ARG2, WINED3DTA_CURRENT);
2760 2761
                    break;

2762
                case D3DTBLEND_MODULATEALPHA:
2763
                    wined3d_device_set_texture_stage_state(device->wined3d_device,
2764
                            0, WINED3D_TSS_COLOR_ARG1, WINED3DTA_TEXTURE);
2765
                    wined3d_device_set_texture_stage_state(device->wined3d_device,
2766
                            0, WINED3D_TSS_ALPHA_ARG1, WINED3DTA_TEXTURE);
2767
                    wined3d_device_set_texture_stage_state(device->wined3d_device,
2768
                            0, WINED3D_TSS_COLOR_ARG2, WINED3DTA_CURRENT);
2769
                    wined3d_device_set_texture_stage_state(device->wined3d_device,
2770
                            0, WINED3D_TSS_ALPHA_ARG2, WINED3DTA_CURRENT);
2771
                    wined3d_device_set_texture_stage_state(device->wined3d_device,
2772
                            0, WINED3D_TSS_COLOR_OP, WINED3D_TOP_MODULATE);
2773
                    wined3d_device_set_texture_stage_state(device->wined3d_device,
2774
                            0, WINED3D_TSS_ALPHA_OP, WINED3D_TOP_MODULATE);
2775 2776
                    break;

2777
                case D3DTBLEND_COPY:
2778
                case D3DTBLEND_DECAL:
2779
                    wined3d_device_set_texture_stage_state(device->wined3d_device,
2780
                            0, WINED3D_TSS_COLOR_ARG1, WINED3DTA_TEXTURE);
2781
                    wined3d_device_set_texture_stage_state(device->wined3d_device,
2782
                            0, WINED3D_TSS_ALPHA_ARG1, WINED3DTA_TEXTURE);
2783
                    wined3d_device_set_texture_stage_state(device->wined3d_device,
2784
                            0, WINED3D_TSS_COLOR_OP, WINED3D_TOP_SELECT_ARG1);
2785
                    wined3d_device_set_texture_stage_state(device->wined3d_device,
2786
                            0, WINED3D_TSS_ALPHA_OP, WINED3D_TOP_SELECT_ARG1);
2787 2788 2789
                    break;

                case D3DTBLEND_DECALALPHA:
2790
                    wined3d_device_set_texture_stage_state(device->wined3d_device,
2791
                            0, WINED3D_TSS_COLOR_OP, WINED3D_TOP_BLEND_TEXTURE_ALPHA);
2792
                    wined3d_device_set_texture_stage_state(device->wined3d_device,
2793
                            0, WINED3D_TSS_COLOR_ARG1, WINED3DTA_TEXTURE);
2794
                    wined3d_device_set_texture_stage_state(device->wined3d_device,
2795
                            0, WINED3D_TSS_COLOR_ARG2, WINED3DTA_CURRENT);
2796
                    wined3d_device_set_texture_stage_state(device->wined3d_device,
2797
                            0, WINED3D_TSS_ALPHA_OP, WINED3D_TOP_SELECT_ARG2);
2798
                    wined3d_device_set_texture_stage_state(device->wined3d_device,
2799
                            0, WINED3D_TSS_ALPHA_ARG2, WINED3DTA_CURRENT);
2800 2801 2802
                    break;

                default:
2803
                    FIXME("Unhandled texture environment %#x.\n", value);
2804 2805 2806
            }

            hr = D3D_OK;
2807 2808 2809
            break;
        }

2810
        default:
2811
            hr = IDirect3DDevice7_SetRenderState(&device->IDirect3DDevice7_iface, state, value);
2812 2813
            break;
    }
2814
    wined3d_mutex_unlock();
2815

2816
    return hr;
2817 2818
}

2819 2820
static HRESULT WINAPI d3d_device2_SetRenderState(IDirect3DDevice2 *iface,
        D3DRENDERSTATETYPE state, DWORD value)
2821
{
2822
    struct d3d_device *device = impl_from_IDirect3DDevice2(iface);
2823

2824
    TRACE("iface %p, state %#x, value %#x.\n", iface, state, value);
2825

2826
    return IDirect3DDevice3_SetRenderState(&device->IDirect3DDevice3_iface, state, value);
2827 2828
}

2829 2830 2831 2832 2833 2834 2835 2836 2837 2838 2839 2840 2841 2842
/*****************************************************************************
 * Direct3DDevice3::SetLightState
 *
 * Sets a light state for Direct3DDevice3 and Direct3DDevice2. The
 * light states are forwarded to Direct3DDevice7 render states
 *
 * Version 2 and 3
 *
 * Params:
 *  LightStateType: The light state to change
 *  Value: The value to assign to that light state
 *
 * Returns:
 *  D3D_OK on success
2843
 *  DDERR_INVALIDPARAMS if the parameters were incorrect
2844 2845 2846
 *  Also check IDirect3DDevice7::SetRenderState
 *
 *****************************************************************************/
2847 2848
static HRESULT WINAPI d3d_device3_SetLightState(IDirect3DDevice3 *iface,
        D3DLIGHTSTATETYPE state, DWORD value)
2849
{
2850
    struct d3d_device *device = impl_from_IDirect3DDevice3(iface);
2851
    HRESULT hr;
2852

2853
    TRACE("iface %p, state %#x, value %#x.\n", iface, state, value);
2854

2855
    if (!state || (state > D3DLIGHTSTATE_COLORVERTEX))
2856 2857 2858 2859 2860
    {
        TRACE("Unexpected Light State Type\n");
        return DDERR_INVALIDPARAMS;
    }

2861
    wined3d_mutex_lock();
2862
    if (state == D3DLIGHTSTATE_MATERIAL)
2863
    {
2864
        struct d3d_material *m = ddraw_get_object(&device->handle_table, value - 1, DDRAW_HANDLE_MATERIAL);
2865
        if (!m)
2866
        {
2867
            WARN("Invalid material handle.\n");
2868
            wined3d_mutex_unlock();
2869 2870
            return DDERR_INVALIDPARAMS;
        }
2871

2872
        TRACE(" activating material %p.\n", m);
2873
        material_activate(m);
2874

2875
        device->material = value;
2876
    }
2877
    else if (state == D3DLIGHTSTATE_COLORMODEL)
2878
    {
2879
        switch (value)
2880 2881 2882 2883 2884 2885 2886 2887 2888 2889
        {
            case D3DCOLOR_MONO:
                ERR("DDCOLOR_MONO should not happen!\n");
                break;
            case D3DCOLOR_RGB:
                /* We are already in this mode */
                TRACE("Setting color model to RGB (no-op).\n");
                break;
            default:
                ERR("Unknown color model!\n");
2890
                wined3d_mutex_unlock();
2891 2892 2893 2894 2895 2896
                return DDERR_INVALIDPARAMS;
        }
    }
    else
    {
        D3DRENDERSTATETYPE rs;
2897
        switch (state)
2898 2899 2900
        {
            case D3DLIGHTSTATE_AMBIENT:       /* 2 */
                rs = D3DRENDERSTATE_AMBIENT;
2901
                break;
2902 2903 2904 2905 2906 2907 2908 2909 2910 2911 2912 2913 2914 2915 2916 2917
            case D3DLIGHTSTATE_FOGMODE:       /* 4 */
                rs = D3DRENDERSTATE_FOGVERTEXMODE;
                break;
            case D3DLIGHTSTATE_FOGSTART:      /* 5 */
                rs = D3DRENDERSTATE_FOGSTART;
                break;
            case D3DLIGHTSTATE_FOGEND:        /* 6 */
                rs = D3DRENDERSTATE_FOGEND;
                break;
            case D3DLIGHTSTATE_FOGDENSITY:    /* 7 */
                rs = D3DRENDERSTATE_FOGDENSITY;
                break;
            case D3DLIGHTSTATE_COLORVERTEX:   /* 8 */
                rs = D3DRENDERSTATE_COLORVERTEX;
                break;
            default:
2918
                FIXME("Unhandled D3DLIGHTSTATETYPE %#x.\n", state);
2919
                wined3d_mutex_unlock();
2920 2921 2922
                return DDERR_INVALIDPARAMS;
        }

2923
        hr = IDirect3DDevice7_SetRenderState(&device->IDirect3DDevice7_iface, rs, value);
2924
        wined3d_mutex_unlock();
2925
        return hr;
2926
    }
2927
    wined3d_mutex_unlock();
2928 2929 2930 2931

    return D3D_OK;
}

2932 2933
static HRESULT WINAPI d3d_device2_SetLightState(IDirect3DDevice2 *iface,
        D3DLIGHTSTATETYPE state, DWORD value)
2934
{
2935
    struct d3d_device *device = impl_from_IDirect3DDevice2(iface);
2936

2937
    TRACE("iface %p, state %#x, value %#x.\n", iface, state, value);
2938

2939
    return d3d_device3_SetLightState(&device->IDirect3DDevice3_iface, state, value);
2940 2941 2942 2943 2944 2945 2946 2947 2948 2949 2950 2951 2952 2953 2954 2955 2956 2957 2958 2959
}

/*****************************************************************************
 * IDirect3DDevice3::GetLightState
 *
 * Returns the current setting of a light state. The state is read from
 * the Direct3DDevice7 render state.
 *
 * Version 2 and 3
 *
 * Params:
 *  LightStateType: The light state to return
 *  Value: The address to store the light state setting at
 *
 * Returns:
 *  D3D_OK on success
 *  DDDERR_INVALIDPARAMS if the parameters were incorrect
 *  Also see IDirect3DDevice7::GetRenderState
 *
 *****************************************************************************/
2960 2961
static HRESULT WINAPI d3d_device3_GetLightState(IDirect3DDevice3 *iface,
        D3DLIGHTSTATETYPE state, DWORD *value)
2962
{
2963
    struct d3d_device *device = impl_from_IDirect3DDevice3(iface);
2964
    HRESULT hr;
2965

2966
    TRACE("iface %p, state %#x, value %p.\n", iface, state, value);
2967

2968
    if (!state || (state > D3DLIGHTSTATE_COLORVERTEX))
2969 2970 2971 2972 2973
    {
        TRACE("Unexpected Light State Type\n");
        return DDERR_INVALIDPARAMS;
    }

2974
    if (!value)
2975 2976
        return DDERR_INVALIDPARAMS;

2977
    wined3d_mutex_lock();
2978
    if (state == D3DLIGHTSTATE_MATERIAL)
2979
    {
2980
        *value = device->material;
2981
    }
2982
    else if (state == D3DLIGHTSTATE_COLORMODEL)
2983
    {
2984
        *value = D3DCOLOR_RGB;
2985 2986 2987 2988
    }
    else
    {
        D3DRENDERSTATETYPE rs;
2989
        switch (state)
2990 2991 2992
        {
            case D3DLIGHTSTATE_AMBIENT:       /* 2 */
                rs = D3DRENDERSTATE_AMBIENT;
2993
                break;
2994 2995 2996 2997 2998 2999 3000 3001 3002 3003 3004 3005 3006 3007 3008 3009
            case D3DLIGHTSTATE_FOGMODE:       /* 4 */
                rs = D3DRENDERSTATE_FOGVERTEXMODE;
                break;
            case D3DLIGHTSTATE_FOGSTART:      /* 5 */
                rs = D3DRENDERSTATE_FOGSTART;
                break;
            case D3DLIGHTSTATE_FOGEND:        /* 6 */
                rs = D3DRENDERSTATE_FOGEND;
                break;
            case D3DLIGHTSTATE_FOGDENSITY:    /* 7 */
                rs = D3DRENDERSTATE_FOGDENSITY;
                break;
            case D3DLIGHTSTATE_COLORVERTEX:   /* 8 */
                rs = D3DRENDERSTATE_COLORVERTEX;
                break;
            default:
3010
                FIXME("Unhandled D3DLIGHTSTATETYPE %#x.\n", state);
3011
                wined3d_mutex_unlock();
3012 3013 3014
                return DDERR_INVALIDPARAMS;
        }

3015
        hr = IDirect3DDevice7_GetRenderState(&device->IDirect3DDevice7_iface, rs, value);
3016
        wined3d_mutex_unlock();
3017
        return hr;
3018
    }
3019
    wined3d_mutex_unlock();
3020 3021 3022 3023

    return D3D_OK;
}

3024 3025
static HRESULT WINAPI d3d_device2_GetLightState(IDirect3DDevice2 *iface,
        D3DLIGHTSTATETYPE state, DWORD *value)
3026
{
3027
    struct d3d_device *device = impl_from_IDirect3DDevice2(iface);
3028

3029
    TRACE("iface %p, state %#x, value %p.\n", iface, state, value);
3030

3031
    return d3d_device3_GetLightState(&device->IDirect3DDevice3_iface, state, value);
3032 3033 3034 3035 3036
}

/*****************************************************************************
 * IDirect3DDevice7::SetTransform
 *
3037
 * Assigns a D3DMATRIX to a transform type. The transform types are defined
3038 3039 3040
 * in include/d3dtypes.h.
 * The D3DTRANSFORMSTATE_WORLD (=1) is translated to D3DTS_WORLDMATRIX(0)
 * (=255) for wined3d, because the 1 transform state was removed in d3d8
3041
 * and WineD3D already understands the replacement D3DTS_WORLDMATRIX(0)
3042 3043 3044 3045 3046 3047 3048 3049 3050 3051 3052 3053 3054
 *
 * Version 2, 3 and 7
 *
 * Params:
 *  TransformStateType: transform state to set
 *  Matrix: Matrix to assign to the state
 *
 * Returns:
 *  D3D_OK on success
 *  DDERR_INVALIDPARAMS if Matrix == NULL
 *  For details see IWineD3DDevice::SetTransform
 *
 *****************************************************************************/
3055 3056
static HRESULT d3d_device7_SetTransform(IDirect3DDevice7 *iface,
        D3DTRANSFORMSTATETYPE state, D3DMATRIX *matrix)
3057
{
3058 3059
    struct d3d_device *device = impl_from_IDirect3DDevice7(iface);
    enum wined3d_transform_state wined3d_state;
3060

3061
    TRACE("iface %p, state %#x, matrix %p.\n", iface, state, matrix);
3062

3063
    switch (state)
3064
    {
3065
        case D3DTRANSFORMSTATE_WORLD:
3066
            wined3d_state = WINED3D_TS_WORLD_MATRIX(0);
3067 3068
            break;
        case D3DTRANSFORMSTATE_WORLD1:
3069
            wined3d_state = WINED3D_TS_WORLD_MATRIX(1);
3070 3071
            break;
        case D3DTRANSFORMSTATE_WORLD2:
3072
            wined3d_state = WINED3D_TS_WORLD_MATRIX(2);
3073 3074
            break;
        case D3DTRANSFORMSTATE_WORLD3:
3075
            wined3d_state = WINED3D_TS_WORLD_MATRIX(3);
3076 3077
            break;
        default:
3078
            wined3d_state = state;
3079
    }
3080

3081
    if (!matrix)
3082
        return DDERR_INVALIDPARAMS;
3083

3084
    /* Note: D3DMATRIX is compatible with struct wined3d_matrix. */
3085
    wined3d_mutex_lock();
3086
    wined3d_device_set_transform(device->wined3d_device, wined3d_state, (struct wined3d_matrix *)matrix);
3087 3088
    wined3d_mutex_unlock();

3089
    return D3D_OK;
3090 3091
}

3092 3093
static HRESULT WINAPI d3d_device7_SetTransform_FPUSetup(IDirect3DDevice7 *iface,
        D3DTRANSFORMSTATETYPE state, D3DMATRIX *matrix)
3094
{
3095
    return d3d_device7_SetTransform(iface, state, matrix);
3096 3097
}

3098 3099
static HRESULT WINAPI d3d_device7_SetTransform_FPUPreserve(IDirect3DDevice7 *iface,
        D3DTRANSFORMSTATETYPE state, D3DMATRIX *matrix)
3100 3101 3102 3103 3104
{
    HRESULT hr;
    WORD old_fpucw;

    old_fpucw = d3d_fpu_setup();
3105
    hr = d3d_device7_SetTransform(iface, state, matrix);
3106 3107 3108 3109 3110
    set_fpu_control_word(old_fpucw);

    return hr;
}

3111
static HRESULT WINAPI d3d_device3_SetTransform(IDirect3DDevice3 *iface,
3112
        D3DTRANSFORMSTATETYPE state, D3DMATRIX *matrix)
3113
{
3114
    struct d3d_device *device = impl_from_IDirect3DDevice3(iface);
3115

3116
    TRACE("iface %p, state %#x, matrix %p.\n", iface, state, matrix);
3117

3118 3119 3120 3121 3122 3123 3124 3125
    if (!matrix)
        return DDERR_INVALIDPARAMS;

    if (state == D3DTRANSFORMSTATE_PROJECTION)
    {
        D3DMATRIX projection;

        wined3d_mutex_lock();
3126
        multiply_matrix(&projection, &device->legacy_clipspace, matrix);
3127
        wined3d_device_set_transform(device->wined3d_device,
3128
                WINED3D_TS_PROJECTION, (struct wined3d_matrix *)&projection);
3129
        device->legacy_projection = *matrix;
3130 3131
        wined3d_mutex_unlock();

3132
        return D3D_OK;
3133 3134
    }

3135
    return IDirect3DDevice7_SetTransform(&device->IDirect3DDevice7_iface, state, matrix);
3136 3137
}

3138 3139
static HRESULT WINAPI d3d_device2_SetTransform(IDirect3DDevice2 *iface,
        D3DTRANSFORMSTATETYPE state, D3DMATRIX *matrix)
3140
{
3141
    struct d3d_device *device = impl_from_IDirect3DDevice2(iface);
3142

3143
    TRACE("iface %p, state %#x, matrix %p.\n", iface, state, matrix);
3144

3145
    return IDirect3DDevice7_SetTransform(&device->IDirect3DDevice7_iface, state, matrix);
3146 3147 3148 3149 3150 3151 3152 3153 3154 3155 3156 3157 3158 3159 3160 3161 3162 3163 3164
}

/*****************************************************************************
 * IDirect3DDevice7::GetTransform
 *
 * Returns the matrix assigned to a transform state
 * D3DTRANSFORMSTATE_WORLD is translated to D3DTS_WORLDMATRIX(0), see
 * SetTransform
 *
 * Params:
 *  TransformStateType: State to read the matrix from
 *  Matrix: Address to store the matrix at
 *
 * Returns:
 *  D3D_OK on success
 *  DDERR_INVALIDPARAMS if Matrix == NULL
 *  For details, see IWineD3DDevice::GetTransform
 *
 *****************************************************************************/
3165 3166
static HRESULT d3d_device7_GetTransform(IDirect3DDevice7 *iface,
        D3DTRANSFORMSTATETYPE state, D3DMATRIX *matrix)
3167
{
3168 3169
    struct d3d_device *device = impl_from_IDirect3DDevice7(iface);
    enum wined3d_transform_state wined3d_state;
3170

3171
    TRACE("iface %p, state %#x, matrix %p.\n", iface, state, matrix);
3172

3173
    switch (state)
3174
    {
3175
        case D3DTRANSFORMSTATE_WORLD:
3176
            wined3d_state = WINED3D_TS_WORLD_MATRIX(0);
3177 3178
            break;
        case D3DTRANSFORMSTATE_WORLD1:
3179
            wined3d_state = WINED3D_TS_WORLD_MATRIX(1);
3180 3181
            break;
        case D3DTRANSFORMSTATE_WORLD2:
3182
            wined3d_state = WINED3D_TS_WORLD_MATRIX(2);
3183 3184
            break;
        case D3DTRANSFORMSTATE_WORLD3:
3185
            wined3d_state = WINED3D_TS_WORLD_MATRIX(3);
3186 3187
            break;
        default:
3188
            wined3d_state = state;
3189
    }
3190

3191
    if (!matrix)
3192 3193
        return DDERR_INVALIDPARAMS;

3194
    /* Note: D3DMATRIX is compatible with struct wined3d_matrix. */
3195
    wined3d_mutex_lock();
3196
    wined3d_device_get_transform(device->wined3d_device, wined3d_state, (struct wined3d_matrix *)matrix);
3197 3198
    wined3d_mutex_unlock();

3199
    return D3D_OK;
3200 3201
}

3202 3203
static HRESULT WINAPI d3d_device7_GetTransform_FPUSetup(IDirect3DDevice7 *iface,
        D3DTRANSFORMSTATETYPE state, D3DMATRIX *matrix)
3204
{
3205
    return d3d_device7_GetTransform(iface, state, matrix);
3206 3207
}

3208 3209
static HRESULT WINAPI d3d_device7_GetTransform_FPUPreserve(IDirect3DDevice7 *iface,
        D3DTRANSFORMSTATETYPE state, D3DMATRIX *matrix)
3210 3211 3212 3213 3214
{
    HRESULT hr;
    WORD old_fpucw;

    old_fpucw = d3d_fpu_setup();
3215
    hr = d3d_device7_GetTransform(iface, state, matrix);
3216 3217 3218 3219 3220
    set_fpu_control_word(old_fpucw);

    return hr;
}

3221
static HRESULT WINAPI d3d_device3_GetTransform(IDirect3DDevice3 *iface,
3222
        D3DTRANSFORMSTATETYPE state, D3DMATRIX *matrix)
3223
{
3224
    struct d3d_device *device = impl_from_IDirect3DDevice3(iface);
3225

3226
    TRACE("iface %p, state %#x, matrix %p.\n", iface, state, matrix);
3227

3228 3229 3230 3231 3232 3233
    if (!matrix)
        return DDERR_INVALIDPARAMS;

    if (state == D3DTRANSFORMSTATE_PROJECTION)
    {
        wined3d_mutex_lock();
3234
        *matrix = device->legacy_projection;
3235 3236 3237 3238
        wined3d_mutex_unlock();
        return DD_OK;
    }

3239
    return IDirect3DDevice7_GetTransform(&device->IDirect3DDevice7_iface, state, matrix);
3240 3241
}

3242 3243
static HRESULT WINAPI d3d_device2_GetTransform(IDirect3DDevice2 *iface,
        D3DTRANSFORMSTATETYPE state, D3DMATRIX *matrix)
3244
{
3245
    struct d3d_device *device = impl_from_IDirect3DDevice2(iface);
3246

3247
    TRACE("iface %p, state %#x, matrix %p.\n", iface, state, matrix);
3248

3249
    return IDirect3DDevice7_GetTransform(&device->IDirect3DDevice7_iface, state, matrix);
3250 3251 3252 3253 3254 3255 3256 3257 3258 3259 3260 3261 3262 3263 3264 3265 3266 3267 3268 3269
}

/*****************************************************************************
 * IDirect3DDevice7::MultiplyTransform
 *
 * Multiplies the already-set transform matrix of a transform state
 * with another matrix. For the world matrix, see SetTransform
 *
 * Version 2, 3 and 7
 *
 * Params:
 *  TransformStateType: Transform state to multiply
 *  D3DMatrix Matrix to multiply with.
 *
 * Returns
 *  D3D_OK on success
 *  DDERR_INVALIDPARAMS if D3DMatrix is NULL
 *  For details, see IWineD3DDevice::MultiplyTransform
 *
 *****************************************************************************/
3270 3271
static HRESULT d3d_device7_MultiplyTransform(IDirect3DDevice7 *iface,
        D3DTRANSFORMSTATETYPE state, D3DMATRIX *matrix)
3272
{
3273 3274
    struct d3d_device *device = impl_from_IDirect3DDevice7(iface);
    enum wined3d_transform_state wined3d_state;
3275

3276
    TRACE("iface %p, state %#x, matrix %p.\n", iface, state, matrix);
3277

3278
    switch (state)
3279
    {
3280
        case D3DTRANSFORMSTATE_WORLD:
3281
            wined3d_state = WINED3D_TS_WORLD_MATRIX(0);
3282 3283
            break;
        case D3DTRANSFORMSTATE_WORLD1:
3284
            wined3d_state = WINED3D_TS_WORLD_MATRIX(1);
3285 3286
            break;
        case D3DTRANSFORMSTATE_WORLD2:
3287
            wined3d_state = WINED3D_TS_WORLD_MATRIX(2);
3288 3289
            break;
        case D3DTRANSFORMSTATE_WORLD3:
3290
            wined3d_state = WINED3D_TS_WORLD_MATRIX(3);
3291 3292
            break;
        default:
3293
            wined3d_state = state;
3294
    }
3295

3296
    /* Note: D3DMATRIX is compatible with struct wined3d_matrix. */
3297
    wined3d_mutex_lock();
3298
    wined3d_device_multiply_transform(device->wined3d_device,
3299
            wined3d_state, (struct wined3d_matrix *)matrix);
3300 3301
    wined3d_mutex_unlock();

3302
    return D3D_OK;
3303 3304
}

3305 3306
static HRESULT WINAPI d3d_device7_MultiplyTransform_FPUSetup(IDirect3DDevice7 *iface,
        D3DTRANSFORMSTATETYPE state, D3DMATRIX *matrix)
3307
{
3308
    return d3d_device7_MultiplyTransform(iface, state, matrix);
3309 3310
}

3311 3312
static HRESULT WINAPI d3d_device7_MultiplyTransform_FPUPreserve(IDirect3DDevice7 *iface,
        D3DTRANSFORMSTATETYPE state, D3DMATRIX *matrix)
3313 3314 3315 3316 3317
{
    HRESULT hr;
    WORD old_fpucw;

    old_fpucw = d3d_fpu_setup();
3318
    hr = d3d_device7_MultiplyTransform(iface, state, matrix);
3319 3320 3321 3322 3323
    set_fpu_control_word(old_fpucw);

    return hr;
}

3324
static HRESULT WINAPI d3d_device3_MultiplyTransform(IDirect3DDevice3 *iface,
3325
        D3DTRANSFORMSTATETYPE state, D3DMATRIX *matrix)
3326
{
3327
    struct d3d_device *device = impl_from_IDirect3DDevice3(iface);
3328

3329
    TRACE("iface %p, state %#x, matrix %p.\n", iface, state, matrix);
3330

3331 3332 3333 3334 3335
    if (state == D3DTRANSFORMSTATE_PROJECTION)
    {
        D3DMATRIX projection, tmp;

        wined3d_mutex_lock();
3336 3337
        multiply_matrix(&tmp, &device->legacy_projection, matrix);
        multiply_matrix(&projection, &device->legacy_clipspace, &tmp);
3338
        wined3d_device_set_transform(device->wined3d_device,
3339
                WINED3D_TS_PROJECTION, (struct wined3d_matrix *)&projection);
3340
        device->legacy_projection = tmp;
3341 3342
        wined3d_mutex_unlock();

3343
        return D3D_OK;
3344 3345
    }

3346
    return IDirect3DDevice7_MultiplyTransform(&device->IDirect3DDevice7_iface, state, matrix);
3347 3348
}

3349 3350
static HRESULT WINAPI d3d_device2_MultiplyTransform(IDirect3DDevice2 *iface,
        D3DTRANSFORMSTATETYPE state, D3DMATRIX *matrix)
3351
{
3352
    struct d3d_device *device = impl_from_IDirect3DDevice2(iface);
3353

3354
    TRACE("iface %p, state %#x, matrix %p.\n", iface, state, matrix);
3355

3356
    return IDirect3DDevice7_MultiplyTransform(&device->IDirect3DDevice7_iface, state, matrix);
3357 3358 3359 3360 3361
}

/*****************************************************************************
 * IDirect3DDevice7::DrawPrimitive
 *
3362
 * Draws primitives based on vertices in an application-provided pointer
3363 3364 3365 3366 3367 3368 3369 3370 3371 3372 3373 3374 3375 3376 3377 3378 3379
 *
 * Version 2, 3 and 7. The IDirect3DDevice2 thunk converts the fixed vertex type into
 * an FVF format for D3D7
 *
 * Params:
 *  PrimitiveType: The type of the primitives to draw
 *  Vertex type: Flexible vertex format vertex description
 *  Vertices: Pointer to the vertex array
 *  VertexCount: The number of vertices to draw
 *  Flags: As usual a few flags
 *
 * Returns:
 *  D3D_OK on success
 *  DDERR_INVALIDPARAMS if Vertices is NULL
 *  For details, see IWineD3DDevice::DrawPrimitiveUP
 *
 *****************************************************************************/
3380 3381 3382 3383 3384
static HRESULT d3d_device7_DrawPrimitive(IDirect3DDevice7 *iface,
        D3DPRIMITIVETYPE primitive_type, DWORD fvf, void *vertices,
        DWORD vertex_count, DWORD flags)
{
    struct d3d_device *device = impl_from_IDirect3DDevice7(iface);
3385
    UINT stride;
3386
    HRESULT hr;
3387

3388 3389
    TRACE("iface %p, primitive_type %#x, fvf %#x, vertices %p, vertex_count %u, flags %#x.\n",
            iface, primitive_type, fvf, vertices, vertex_count, flags);
3390

3391
    if (!vertices)
3392 3393 3394
        return DDERR_INVALIDPARAMS;

    /* Get the stride */
3395
    stride = get_flexible_vertex_size(fvf);
3396

3397
    wined3d_mutex_lock();
3398
    wined3d_device_set_vertex_declaration(device->wined3d_device, ddraw_find_decl(device->ddraw, fvf));
3399 3400
    wined3d_device_set_primitive_type(device->wined3d_device, primitive_type);
    hr = wined3d_device_draw_primitive_up(device->wined3d_device, vertex_count, vertices, stride);
3401 3402
    wined3d_mutex_unlock();

3403
    return hr;
3404 3405
}

3406 3407 3408
static HRESULT WINAPI d3d_device7_DrawPrimitive_FPUSetup(IDirect3DDevice7 *iface,
        D3DPRIMITIVETYPE primitive_type, DWORD fvf, void *vertices,
        DWORD vertex_count, DWORD flags)
3409
{
3410
    return d3d_device7_DrawPrimitive(iface, primitive_type, fvf, vertices, vertex_count, flags);
3411 3412
}

3413 3414 3415
static HRESULT WINAPI d3d_device7_DrawPrimitive_FPUPreserve(IDirect3DDevice7 *iface,
        D3DPRIMITIVETYPE primitive_type, DWORD fvf, void *vertices,
        DWORD vertex_count, DWORD flags)
3416 3417 3418 3419 3420
{
    HRESULT hr;
    WORD old_fpucw;

    old_fpucw = d3d_fpu_setup();
3421
    hr = d3d_device7_DrawPrimitive(iface, primitive_type, fvf, vertices, vertex_count, flags);
3422 3423 3424 3425 3426
    set_fpu_control_word(old_fpucw);

    return hr;
}

3427 3428 3429
static HRESULT WINAPI d3d_device3_DrawPrimitive(IDirect3DDevice3 *iface,
        D3DPRIMITIVETYPE primitive_type, DWORD fvf, void *vertices, DWORD vertex_count,
        DWORD flags)
3430
{
3431 3432 3433 3434
    struct d3d_device *device = impl_from_IDirect3DDevice3(iface);

    TRACE("iface %p, primitive_type %#x, fvf %#x, vertices %p, vertex_count %u, flags %#x.\n",
            iface, primitive_type, fvf, vertices, vertex_count, flags);
3435

3436 3437
    return IDirect3DDevice7_DrawPrimitive(&device->IDirect3DDevice7_iface,
            primitive_type, fvf, vertices, vertex_count, flags);
3438 3439
}

3440 3441 3442
static HRESULT WINAPI d3d_device2_DrawPrimitive(IDirect3DDevice2 *iface,
        D3DPRIMITIVETYPE primitive_type, D3DVERTEXTYPE vertex_type, void *vertices,
        DWORD vertex_count, DWORD flags)
3443
{
3444 3445
    struct d3d_device *device = impl_from_IDirect3DDevice2(iface);
    DWORD fvf;
3446 3447

    TRACE("iface %p, primitive_type %#x, vertex_type %#x, vertices %p, vertex_count %u, flags %#x.\n",
3448
            iface, primitive_type, vertex_type, vertices, vertex_count, flags);
3449

3450
    switch (vertex_type)
3451
    {
3452 3453 3454
        case D3DVT_VERTEX: fvf = D3DFVF_VERTEX; break;
        case D3DVT_LVERTEX: fvf = D3DFVF_LVERTEX; break;
        case D3DVT_TLVERTEX: fvf = D3DFVF_TLVERTEX; break;
3455
        default:
3456
            FIXME("Unhandled vertex type %#x.\n", vertex_type);
3457
            return DDERR_INVALIDPARAMS;  /* Should never happen */
3458 3459
    }

3460 3461
    return IDirect3DDevice7_DrawPrimitive(&device->IDirect3DDevice7_iface,
            primitive_type, fvf, vertices, vertex_count, flags);
3462 3463 3464 3465 3466 3467 3468 3469 3470 3471 3472 3473 3474 3475 3476 3477 3478 3479 3480 3481 3482 3483 3484 3485 3486 3487
}

/*****************************************************************************
 * IDirect3DDevice7::DrawIndexedPrimitive
 *
 * Draws vertices from an application-provided pointer, based on the index
 * numbers in a WORD array.
 *
 * Version 2, 3 and 7. The version 7 thunk translates the vertex type into
 * an FVF format for D3D7
 *
 * Params:
 *  PrimitiveType: The primitive type to draw
 *  VertexType: The FVF vertex description
 *  Vertices: Pointer to the vertex array
 *  VertexCount: ?
 *  Indices: Pointer to the index array
 *  IndexCount: Number of indices = Number of vertices to draw
 *  Flags: As usual, some flags
 *
 * Returns:
 *  D3D_OK on success
 *  DDERR_INVALIDPARAMS if Vertices or Indices is NULL
 *  For details, see IWineD3DDevice::DrawIndexedPrimitiveUP
 *
 *****************************************************************************/
3488 3489 3490 3491 3492
static HRESULT d3d_device7_DrawIndexedPrimitive(IDirect3DDevice7 *iface,
        D3DPRIMITIVETYPE primitive_type, DWORD fvf, void *vertices, DWORD vertex_count,
        WORD *indices, DWORD index_count, DWORD flags)
{
    struct d3d_device *device = impl_from_IDirect3DDevice7(iface);
3493
    HRESULT hr;
3494

3495 3496 3497
    TRACE("iface %p, primitive_type %#x, fvf %#x, vertices %p, vertex_count %u, "
            "indices %p, index_count %u, flags %#x.\n",
            iface, primitive_type, fvf, vertices, vertex_count, indices, index_count, flags);
3498

3499
    /* Set the D3DDevice's FVF */
3500
    wined3d_mutex_lock();
3501
    wined3d_device_set_vertex_declaration(device->wined3d_device, ddraw_find_decl(device->ddraw, fvf));
3502 3503 3504
    wined3d_device_set_primitive_type(device->wined3d_device, primitive_type);
    hr = wined3d_device_draw_indexed_primitive_up(device->wined3d_device, index_count, indices,
            WINED3DFMT_R16_UINT, vertices, get_flexible_vertex_size(fvf));
3505 3506
    wined3d_mutex_unlock();

3507
    return hr;
3508 3509
}

3510 3511 3512
static HRESULT WINAPI d3d_device7_DrawIndexedPrimitive_FPUSetup(IDirect3DDevice7 *iface,
        D3DPRIMITIVETYPE primitive_type, DWORD fvf, void *vertices, DWORD vertex_count,
        WORD *indices, DWORD index_count, DWORD flags)
3513
{
3514 3515
    return d3d_device7_DrawIndexedPrimitive(iface, primitive_type, fvf,
            vertices, vertex_count, indices, index_count, flags);
3516 3517
}

3518 3519 3520
static HRESULT WINAPI d3d_device7_DrawIndexedPrimitive_FPUPreserve(IDirect3DDevice7 *iface,
        D3DPRIMITIVETYPE primitive_type, DWORD fvf, void *vertices, DWORD vertex_count,
        WORD *indices, DWORD index_count, DWORD flags)
3521 3522 3523 3524 3525
{
    HRESULT hr;
    WORD old_fpucw;

    old_fpucw = d3d_fpu_setup();
3526 3527
    hr = d3d_device7_DrawIndexedPrimitive(iface, primitive_type, fvf,
            vertices, vertex_count, indices, index_count, flags);
3528 3529 3530 3531 3532
    set_fpu_control_word(old_fpucw);

    return hr;
}

3533 3534 3535
static HRESULT WINAPI d3d_device3_DrawIndexedPrimitive(IDirect3DDevice3 *iface,
        D3DPRIMITIVETYPE primitive_type, DWORD fvf, void *vertices, DWORD vertex_count,
        WORD *indices, DWORD index_count, DWORD flags)
3536
{
3537
    struct d3d_device *device = impl_from_IDirect3DDevice3(iface);
3538

3539 3540 3541 3542 3543 3544
    TRACE("iface %p, primitive_type %#x, fvf %#x, vertices %p, vertex_count %u, "
            "indices %p, index_count %u, flags %#x.\n",
            iface, primitive_type, fvf, vertices, vertex_count, indices, index_count, flags);

    return IDirect3DDevice7_DrawIndexedPrimitive(&device->IDirect3DDevice7_iface,
            primitive_type, fvf, vertices, vertex_count, indices, index_count, flags);
3545 3546
}

3547 3548 3549
static HRESULT WINAPI d3d_device2_DrawIndexedPrimitive(IDirect3DDevice2 *iface,
        D3DPRIMITIVETYPE primitive_type, D3DVERTEXTYPE vertex_type, void *vertices,
        DWORD vertex_count, WORD *indices, DWORD index_count, DWORD flags)
3550
{
3551 3552
    struct d3d_device *device = impl_from_IDirect3DDevice2(iface);
    DWORD fvf;
3553

3554 3555 3556
    TRACE("iface %p, primitive_type %#x, vertex_type %#x, vertices %p, vertex_count %u, "
            "indices %p, index_count %u, flags %#x.\n",
            iface, primitive_type, vertex_type, vertices, vertex_count, indices, index_count, flags);
3557

3558
    switch (vertex_type)
3559
    {
3560 3561 3562
        case D3DVT_VERTEX: fvf = D3DFVF_VERTEX; break;
        case D3DVT_LVERTEX: fvf = D3DFVF_LVERTEX; break;
        case D3DVT_TLVERTEX: fvf = D3DFVF_TLVERTEX; break;
3563
        default:
3564
            ERR("Unhandled vertex type %#x.\n", vertex_type);
3565
            return DDERR_INVALIDPARAMS;  /* Should never happen */
3566 3567
    }

3568 3569
    return IDirect3DDevice7_DrawIndexedPrimitive(&device->IDirect3DDevice7_iface,
            primitive_type, fvf, vertices, vertex_count, indices, index_count, flags);
3570 3571 3572 3573 3574 3575 3576 3577 3578 3579 3580 3581 3582 3583 3584 3585 3586 3587
}

/*****************************************************************************
 * IDirect3DDevice7::SetClipStatus
 *
 * Sets the clip status. This defines things as clipping conditions and
 * the extents of the clipping region.
 *
 * Version 2, 3 and 7
 *
 * Params:
 *  ClipStatus:
 *
 * Returns:
 *  D3D_OK because it's a stub
 *  (DDERR_INVALIDPARAMS if ClipStatus == NULL)
 *
 *****************************************************************************/
3588
static HRESULT WINAPI d3d_device7_SetClipStatus(IDirect3DDevice7 *iface, D3DCLIPSTATUS *clip_status)
3589
{
3590
    FIXME("iface %p, clip_status %p stub!\n", iface, clip_status);
3591 3592 3593 3594 3595 3596 3597 3598

    /* D3DCLIPSTATUS and WINED3DCLIPSTATUS are different. I don't know how to convert them
     * Perhaps this needs a new data type and an additional IWineD3DDevice method
     */
    /* return IWineD3DDevice_SetClipStatus(This->wineD3DDevice, ClipStatus);*/
    return D3D_OK;
}

3599
static HRESULT WINAPI d3d_device3_SetClipStatus(IDirect3DDevice3 *iface, D3DCLIPSTATUS *clip_status)
3600
{
3601 3602 3603
    struct d3d_device *device = impl_from_IDirect3DDevice3(iface);

    TRACE("iface %p, clip_status %p.\n", iface, clip_status);
3604

3605
    return IDirect3DDevice7_SetClipStatus(&device->IDirect3DDevice7_iface, clip_status);
3606 3607
}

3608
static HRESULT WINAPI d3d_device2_SetClipStatus(IDirect3DDevice2 *iface, D3DCLIPSTATUS *clip_status)
3609
{
3610
    struct d3d_device *device = impl_from_IDirect3DDevice2(iface);
3611

3612 3613 3614
    TRACE("iface %p, clip_status %p.\n", iface, clip_status);

    return IDirect3DDevice7_SetClipStatus(&device->IDirect3DDevice7_iface, clip_status);
3615 3616 3617 3618 3619 3620 3621 3622 3623 3624 3625 3626 3627 3628
}

/*****************************************************************************
 * IDirect3DDevice7::GetClipStatus
 *
 * Returns the clip status
 *
 * Params:
 *  ClipStatus: Address to write the clip status to
 *
 * Returns:
 *  D3D_OK because it's a stub
 *
 *****************************************************************************/
3629
static HRESULT WINAPI d3d_device7_GetClipStatus(IDirect3DDevice7 *iface, D3DCLIPSTATUS *clip_status)
3630
{
3631
    FIXME("iface %p, clip_status %p stub!\n", iface, clip_status);
3632 3633 3634 3635 3636 3637

    /* D3DCLIPSTATUS and WINED3DCLIPSTATUS are different. I don't know how to convert them */
    /* return IWineD3DDevice_GetClipStatus(This->wineD3DDevice, ClipStatus);*/
    return D3D_OK;
}

3638
static HRESULT WINAPI d3d_device3_GetClipStatus(IDirect3DDevice3 *iface, D3DCLIPSTATUS *clip_status)
3639
{
3640 3641 3642
    struct d3d_device *device = impl_from_IDirect3DDevice3(iface);

    TRACE("iface %p, clip_status %p.\n", iface, clip_status);
3643

3644
    return IDirect3DDevice7_GetClipStatus(&device->IDirect3DDevice7_iface, clip_status);
3645 3646
}

3647
static HRESULT WINAPI d3d_device2_GetClipStatus(IDirect3DDevice2 *iface, D3DCLIPSTATUS *clip_status)
3648
{
3649
    struct d3d_device *device = impl_from_IDirect3DDevice2(iface);
3650

3651 3652 3653
    TRACE("iface %p, clip_status %p.\n", iface, clip_status);

    return IDirect3DDevice7_GetClipStatus(&device->IDirect3DDevice7_iface, clip_status);
3654 3655 3656 3657 3658 3659 3660 3661 3662 3663 3664
}

/*****************************************************************************
 * IDirect3DDevice::DrawPrimitiveStrided
 *
 * Draws vertices described by a D3DDRAWPRIMITIVESTRIDEDDATA structure.
 *
 * Version 3 and 7
 *
 * Params:
 *  PrimitiveType: The primitive type to draw
3665
 *  VertexType: The FVF description of the vertices to draw (for the stride??)
3666 3667 3668 3669 3670 3671 3672 3673 3674 3675 3676
 *  D3DDrawPrimStrideData: A D3DDRAWPRIMITIVESTRIDEDDATA structure describing
 *                         the vertex data locations
 *  VertexCount: The number of vertices to draw
 *  Flags: Some flags
 *
 * Returns:
 *  D3D_OK, because it's a stub
 *  (DDERR_INVALIDPARAMS if D3DDrawPrimStrideData is NULL)
 *  (For details, see IWineD3DDevice::DrawPrimitiveStrided)
 *
 *****************************************************************************/
3677 3678 3679 3680
static HRESULT d3d_device7_DrawPrimitiveStrided(IDirect3DDevice7 *iface, D3DPRIMITIVETYPE PrimitiveType,
        DWORD VertexType, D3DDRAWPRIMITIVESTRIDEDDATA *D3DDrawPrimStrideData, DWORD VertexCount, DWORD Flags)
{
    struct d3d_device *device = impl_from_IDirect3DDevice7(iface);
3681
    struct wined3d_strided_data wined3d_strided;
3682
    DWORD i;
3683
    HRESULT hr;
3684

3685 3686
    TRACE("iface %p, primitive_type %#x, FVF %#x, strided_data %p, vertex_count %u, flags %#x.\n",
            iface, PrimitiveType, VertexType, D3DDrawPrimStrideData, VertexCount, Flags);
3687

3688
    memset(&wined3d_strided, 0, sizeof(wined3d_strided));
3689 3690 3691
    /* Get the strided data right. the wined3d structure is a bit bigger
     * Watch out: The contents of the strided data are determined by the fvf,
     * not by the members set in D3DDrawPrimStrideData. So it's valid
3692 3693
     * to have diffuse.lpvData set to 0xdeadbeef if the diffuse flag is
     * not set in the fvf.
3694 3695 3696
     */
    if(VertexType & D3DFVF_POSITION_MASK)
    {
3697 3698 3699
        wined3d_strided.position.format = WINED3DFMT_R32G32B32_FLOAT;
        wined3d_strided.position.data = D3DDrawPrimStrideData->position.lpvData;
        wined3d_strided.position.stride = D3DDrawPrimStrideData->position.dwStride;
3700 3701
        if (VertexType & D3DFVF_XYZRHW)
        {
3702 3703 3704 3705 3706 3707 3708
            wined3d_strided.position.format = WINED3DFMT_R32G32B32A32_FLOAT;
            wined3d_strided.position_transformed = TRUE;
        }
        else
        {
            wined3d_strided.position_transformed = FALSE;
        }
3709 3710
    }

3711
    if (VertexType & D3DFVF_NORMAL)
3712
    {
3713 3714 3715
        wined3d_strided.normal.format = WINED3DFMT_R32G32B32_FLOAT;
        wined3d_strided.normal.data = D3DDrawPrimStrideData->normal.lpvData;
        wined3d_strided.normal.stride = D3DDrawPrimStrideData->normal.dwStride;
3716 3717
    }

3718
    if (VertexType & D3DFVF_DIFFUSE)
3719
    {
3720 3721 3722
        wined3d_strided.diffuse.format = WINED3DFMT_B8G8R8A8_UNORM;
        wined3d_strided.diffuse.data = D3DDrawPrimStrideData->diffuse.lpvData;
        wined3d_strided.diffuse.stride = D3DDrawPrimStrideData->diffuse.dwStride;
3723 3724
    }

3725
    if (VertexType & D3DFVF_SPECULAR)
3726
    {
3727 3728 3729
        wined3d_strided.specular.format = WINED3DFMT_B8G8R8A8_UNORM;
        wined3d_strided.specular.data = D3DDrawPrimStrideData->specular.lpvData;
        wined3d_strided.specular.stride = D3DDrawPrimStrideData->specular.dwStride;
3730 3731
    }

3732
    for (i = 0; i < GET_TEXCOUNT_FROM_FVF(VertexType); ++i)
3733
    {
3734
        switch (GET_TEXCOORD_SIZE_FROM_FVF(VertexType, i))
3735
        {
3736 3737 3738 3739
            case 1: wined3d_strided.tex_coords[i].format = WINED3DFMT_R32_FLOAT; break;
            case 2: wined3d_strided.tex_coords[i].format = WINED3DFMT_R32G32_FLOAT; break;
            case 3: wined3d_strided.tex_coords[i].format = WINED3DFMT_R32G32B32_FLOAT; break;
            case 4: wined3d_strided.tex_coords[i].format = WINED3DFMT_R32G32B32A32_FLOAT; break;
3740
            default: ERR("Unexpected texture coordinate size %d\n",
3741 3742
                         GET_TEXCOORD_SIZE_FROM_FVF(VertexType, i));
        }
3743 3744
        wined3d_strided.tex_coords[i].data = D3DDrawPrimStrideData->textureCoords[i].lpvData;
        wined3d_strided.tex_coords[i].stride = D3DDrawPrimStrideData->textureCoords[i].dwStride;
3745 3746
    }

3747
    /* WineD3D doesn't need the FVF here */
3748
    wined3d_mutex_lock();
3749 3750
    wined3d_device_set_primitive_type(device->wined3d_device, PrimitiveType);
    hr = wined3d_device_draw_primitive_strided(device->wined3d_device, VertexCount, &wined3d_strided);
3751 3752
    wined3d_mutex_unlock();

3753
    return hr;
3754 3755
}

3756 3757 3758
static HRESULT WINAPI d3d_device7_DrawPrimitiveStrided_FPUSetup(IDirect3DDevice7 *iface,
        D3DPRIMITIVETYPE PrimitiveType, DWORD VertexType,
        D3DDRAWPRIMITIVESTRIDEDDATA *D3DDrawPrimStrideData, DWORD VertexCount, DWORD Flags)
3759
{
3760 3761
    return d3d_device7_DrawPrimitiveStrided(iface, PrimitiveType,
            VertexType, D3DDrawPrimStrideData, VertexCount, Flags);
3762 3763
}

3764 3765 3766
static HRESULT WINAPI d3d_device7_DrawPrimitiveStrided_FPUPreserve(IDirect3DDevice7 *iface,
        D3DPRIMITIVETYPE PrimitiveType, DWORD VertexType,
        D3DDRAWPRIMITIVESTRIDEDDATA *D3DDrawPrimStrideData, DWORD VertexCount, DWORD Flags)
3767 3768 3769 3770 3771
{
    HRESULT hr;
    WORD old_fpucw;

    old_fpucw = d3d_fpu_setup();
3772 3773
    hr = d3d_device7_DrawPrimitiveStrided(iface, PrimitiveType,
            VertexType, D3DDrawPrimStrideData, VertexCount, Flags);
3774 3775 3776 3777 3778
    set_fpu_control_word(old_fpucw);

    return hr;
}

3779
static HRESULT WINAPI d3d_device3_DrawPrimitiveStrided(IDirect3DDevice3 *iface,
3780 3781
        D3DPRIMITIVETYPE PrimitiveType, DWORD VertexType,
        D3DDRAWPRIMITIVESTRIDEDDATA *D3DDrawPrimStrideData, DWORD VertexCount, DWORD Flags)
3782
{
3783
    struct d3d_device *device = impl_from_IDirect3DDevice3(iface);
3784

3785 3786 3787
    TRACE("iface %p, primitive_type %#x, FVF %#x, strided_data %p, vertex_count %u, flags %#x.\n",
            iface, PrimitiveType, VertexType, D3DDrawPrimStrideData, VertexCount, Flags);

3788
    return IDirect3DDevice7_DrawPrimitiveStrided(&device->IDirect3DDevice7_iface,
3789
            PrimitiveType, VertexType, D3DDrawPrimStrideData, VertexCount, Flags);
3790 3791 3792 3793 3794 3795 3796 3797 3798 3799 3800 3801 3802 3803 3804 3805 3806 3807 3808
}

/*****************************************************************************
 * IDirect3DDevice7::DrawIndexedPrimitiveStrided
 *
 * Draws primitives specified by strided data locations based on indices
 *
 * Version 3 and 7
 *
 * Params:
 *  PrimitiveType:
 *
 * Returns:
 *  D3D_OK, because it's a stub
 *  (DDERR_INVALIDPARAMS if D3DDrawPrimStrideData is NULL)
 *  (DDERR_INVALIDPARAMS if Indices is NULL)
 *  (For more details, see IWineD3DDevice::DrawIndexedPrimitiveStrided)
 *
 *****************************************************************************/
3809 3810 3811 3812 3813 3814
static HRESULT d3d_device7_DrawIndexedPrimitiveStrided(IDirect3DDevice7 *iface,
        D3DPRIMITIVETYPE PrimitiveType, DWORD VertexType,
        D3DDRAWPRIMITIVESTRIDEDDATA *D3DDrawPrimStrideData, DWORD VertexCount,
        WORD *Indices, DWORD IndexCount, DWORD Flags)
{
    struct d3d_device *device = impl_from_IDirect3DDevice7(iface);
3815
    struct wined3d_strided_data wined3d_strided;
3816
    DWORD i;
3817 3818
    HRESULT hr;

3819 3820
    TRACE("iface %p, primitive_type %#x, FVF %#x, strided_data %p, vertex_count %u, indices %p, index_count %u, flags %#x.\n",
            iface, PrimitiveType, VertexType, D3DDrawPrimStrideData, VertexCount, Indices, IndexCount, Flags);
3821

3822
    memset(&wined3d_strided, 0, sizeof(wined3d_strided));
3823 3824 3825 3826
    /* Get the strided data right. the wined3d structure is a bit bigger
     * Watch out: The contents of the strided data are determined by the fvf,
     * not by the members set in D3DDrawPrimStrideData. So it's valid
     * to have diffuse.lpvData set to 0xdeadbeef if the diffuse flag is
3827 3828
     * not set in the fvf. */
    if (VertexType & D3DFVF_POSITION_MASK)
3829
    {
3830 3831 3832
        wined3d_strided.position.format = WINED3DFMT_R32G32B32_FLOAT;
        wined3d_strided.position.data = D3DDrawPrimStrideData->position.lpvData;
        wined3d_strided.position.stride = D3DDrawPrimStrideData->position.dwStride;
3833 3834
        if (VertexType & D3DFVF_XYZRHW)
        {
3835 3836 3837 3838 3839 3840 3841
            wined3d_strided.position.format = WINED3DFMT_R32G32B32A32_FLOAT;
            wined3d_strided.position_transformed = TRUE;
        }
        else
        {
            wined3d_strided.position_transformed = FALSE;
        }
3842 3843
    }

3844
    if (VertexType & D3DFVF_NORMAL)
3845
    {
3846 3847 3848
        wined3d_strided.normal.format = WINED3DFMT_R32G32B32_FLOAT;
        wined3d_strided.normal.data = D3DDrawPrimStrideData->normal.lpvData;
        wined3d_strided.normal.stride = D3DDrawPrimStrideData->normal.dwStride;
3849 3850
    }

3851
    if (VertexType & D3DFVF_DIFFUSE)
3852
    {
3853 3854 3855
        wined3d_strided.diffuse.format = WINED3DFMT_B8G8R8A8_UNORM;
        wined3d_strided.diffuse.data = D3DDrawPrimStrideData->diffuse.lpvData;
        wined3d_strided.diffuse.stride = D3DDrawPrimStrideData->diffuse.dwStride;
3856 3857
    }

3858
    if (VertexType & D3DFVF_SPECULAR)
3859
    {
3860 3861 3862
        wined3d_strided.specular.format = WINED3DFMT_B8G8R8A8_UNORM;
        wined3d_strided.specular.data = D3DDrawPrimStrideData->specular.lpvData;
        wined3d_strided.specular.stride = D3DDrawPrimStrideData->specular.dwStride;
3863 3864
    }

3865
    for (i = 0; i < GET_TEXCOUNT_FROM_FVF(VertexType); ++i)
3866
    {
3867
        switch (GET_TEXCOORD_SIZE_FROM_FVF(VertexType, i))
3868
        {
3869 3870 3871 3872
            case 1: wined3d_strided.tex_coords[i].format = WINED3DFMT_R32_FLOAT; break;
            case 2: wined3d_strided.tex_coords[i].format = WINED3DFMT_R32G32_FLOAT; break;
            case 3: wined3d_strided.tex_coords[i].format = WINED3DFMT_R32G32B32_FLOAT; break;
            case 4: wined3d_strided.tex_coords[i].format = WINED3DFMT_R32G32B32A32_FLOAT; break;
3873 3874 3875
            default: ERR("Unexpected texture coordinate size %d\n",
                         GET_TEXCOORD_SIZE_FROM_FVF(VertexType, i));
        }
3876 3877
        wined3d_strided.tex_coords[i].data = D3DDrawPrimStrideData->textureCoords[i].lpvData;
        wined3d_strided.tex_coords[i].stride = D3DDrawPrimStrideData->textureCoords[i].dwStride;
3878 3879 3880
    }

    /* WineD3D doesn't need the FVF here */
3881
    wined3d_mutex_lock();
3882 3883
    wined3d_device_set_primitive_type(device->wined3d_device, PrimitiveType);
    hr = wined3d_device_draw_indexed_primitive_strided(device->wined3d_device,
3884
            IndexCount, &wined3d_strided, VertexCount, Indices, WINED3DFMT_R16_UINT);
3885 3886
    wined3d_mutex_unlock();

3887
    return hr;
3888 3889
}

3890 3891 3892 3893
static HRESULT WINAPI d3d_device7_DrawIndexedPrimitiveStrided_FPUSetup(IDirect3DDevice7 *iface,
        D3DPRIMITIVETYPE PrimitiveType, DWORD VertexType,
        D3DDRAWPRIMITIVESTRIDEDDATA *D3DDrawPrimStrideData, DWORD VertexCount,
        WORD *Indices, DWORD IndexCount, DWORD Flags)
3894
{
3895 3896
    return d3d_device7_DrawIndexedPrimitiveStrided(iface, PrimitiveType, VertexType,
            D3DDrawPrimStrideData, VertexCount, Indices, IndexCount, Flags);
3897 3898
}

3899 3900 3901 3902
static HRESULT WINAPI d3d_device7_DrawIndexedPrimitiveStrided_FPUPreserve(IDirect3DDevice7 *iface,
        D3DPRIMITIVETYPE PrimitiveType, DWORD VertexType,
        D3DDRAWPRIMITIVESTRIDEDDATA *D3DDrawPrimStrideData, DWORD VertexCount,
        WORD *Indices, DWORD IndexCount, DWORD Flags)
3903 3904 3905 3906 3907
{
    HRESULT hr;
    WORD old_fpucw;

    old_fpucw = d3d_fpu_setup();
3908 3909
    hr = d3d_device7_DrawIndexedPrimitiveStrided(iface, PrimitiveType, VertexType,
            D3DDrawPrimStrideData, VertexCount, Indices, IndexCount, Flags);
3910 3911 3912 3913 3914
    set_fpu_control_word(old_fpucw);

    return hr;
}

3915
static HRESULT WINAPI d3d_device3_DrawIndexedPrimitiveStrided(IDirect3DDevice3 *iface,
3916 3917 3918
        D3DPRIMITIVETYPE PrimitiveType, DWORD VertexType,
        D3DDRAWPRIMITIVESTRIDEDDATA *D3DDrawPrimStrideData, DWORD VertexCount, WORD *Indices,
        DWORD IndexCount, DWORD Flags)
3919
{
3920
    struct d3d_device *device = impl_from_IDirect3DDevice3(iface);
3921

3922 3923 3924
    TRACE("iface %p, primitive_type %#x, FVF %#x, strided_data %p, vertex_count %u, indices %p, index_count %u, flags %#x.\n",
            iface, PrimitiveType, VertexType, D3DDrawPrimStrideData, VertexCount, Indices, IndexCount, Flags);

3925
    return IDirect3DDevice7_DrawIndexedPrimitiveStrided(&device->IDirect3DDevice7_iface,
3926
            PrimitiveType, VertexType, D3DDrawPrimStrideData, VertexCount, Indices, IndexCount, Flags);
3927 3928 3929 3930 3931 3932 3933 3934 3935 3936 3937 3938 3939 3940 3941 3942 3943 3944 3945 3946 3947
}

/*****************************************************************************
 * IDirect3DDevice7::DrawPrimitiveVB
 *
 * Draws primitives from a vertex buffer to the screen.
 *
 * Version 3 and 7
 *
 * Params:
 *  PrimitiveType: Type of primitive to be rendered.
 *  D3DVertexBuf: Source Vertex Buffer
 *  StartVertex: Index of the first vertex from the buffer to be rendered
 *  NumVertices: Number of vertices to be rendered
 *  Flags: Can be D3DDP_WAIT to wait until rendering has finished
 *
 * Return values
 *  D3D_OK on success
 *  DDERR_INVALIDPARAMS if D3DVertexBuf is NULL
 *
 *****************************************************************************/
3948 3949 3950 3951
static HRESULT d3d_device7_DrawPrimitiveVB(IDirect3DDevice7 *iface, D3DPRIMITIVETYPE PrimitiveType,
        IDirect3DVertexBuffer7 *D3DVertexBuf, DWORD StartVertex, DWORD NumVertices, DWORD Flags)
{
    struct d3d_device *device = impl_from_IDirect3DDevice7(iface);
3952
    struct d3d_vertex_buffer *vb = unsafe_impl_from_IDirect3DVertexBuffer7(D3DVertexBuf);
3953 3954 3955
    HRESULT hr;
    DWORD stride;

3956 3957
    TRACE("iface %p, primitive_type %#x, vb %p, start_vertex %u, vertex_count %u, flags %#x.\n",
            iface, PrimitiveType, D3DVertexBuf, StartVertex, NumVertices, Flags);
3958 3959

    /* Sanity checks */
3960
    if (!vb)
3961
    {
3962
        WARN("No Vertex buffer specified.\n");
3963 3964
        return DDERR_INVALIDPARAMS;
    }
3965
    stride = get_flexible_vertex_size(vb->fvf);
3966

3967
    wined3d_mutex_lock();
3968
    wined3d_device_set_vertex_declaration(device->wined3d_device, vb->wineD3DVertexDeclaration);
3969 3970
    hr = wined3d_device_set_stream_source(device->wined3d_device, 0, vb->wineD3DVertexBuffer, 0, stride);
    if (FAILED(hr))
3971
    {
3972
        WARN("Failed to set stream source, hr %#x.\n", hr);
3973
        wined3d_mutex_unlock();
3974 3975 3976 3977
        return hr;
    }

    /* Now draw the primitives */
3978 3979
    wined3d_device_set_primitive_type(device->wined3d_device, PrimitiveType);
    hr = wined3d_device_draw_primitive(device->wined3d_device, StartVertex, NumVertices);
3980 3981
    wined3d_mutex_unlock();

3982
    return hr;
3983 3984
}

3985 3986
static HRESULT WINAPI d3d_device7_DrawPrimitiveVB_FPUSetup(IDirect3DDevice7 *iface, D3DPRIMITIVETYPE PrimitiveType,
        IDirect3DVertexBuffer7 *D3DVertexBuf, DWORD StartVertex, DWORD NumVertices, DWORD Flags)
3987
{
3988
    return d3d_device7_DrawPrimitiveVB(iface, PrimitiveType, D3DVertexBuf, StartVertex, NumVertices, Flags);
3989 3990
}

3991 3992
static HRESULT WINAPI d3d_device7_DrawPrimitiveVB_FPUPreserve(IDirect3DDevice7 *iface, D3DPRIMITIVETYPE PrimitiveType,
        IDirect3DVertexBuffer7 *D3DVertexBuf, DWORD StartVertex, DWORD NumVertices, DWORD Flags)
3993 3994 3995 3996 3997
{
    HRESULT hr;
    WORD old_fpucw;

    old_fpucw = d3d_fpu_setup();
3998
    hr = d3d_device7_DrawPrimitiveVB(iface, PrimitiveType, D3DVertexBuf, StartVertex, NumVertices, Flags);
3999 4000 4001 4002 4003
    set_fpu_control_word(old_fpucw);

    return hr;
}

4004 4005
static HRESULT WINAPI d3d_device3_DrawPrimitiveVB(IDirect3DDevice3 *iface, D3DPRIMITIVETYPE PrimitiveType,
        IDirect3DVertexBuffer *D3DVertexBuf, DWORD StartVertex, DWORD NumVertices, DWORD Flags)
4006
{
4007
    struct d3d_device *device = impl_from_IDirect3DDevice3(iface);
4008
    struct d3d_vertex_buffer *vb = unsafe_impl_from_IDirect3DVertexBuffer(D3DVertexBuf);
4009 4010 4011 4012

    TRACE("iface %p, primitive_type %#x, vb %p, start_vertex %u, vertex_count %u, flags %#x.\n",
            iface, PrimitiveType, D3DVertexBuf, StartVertex, NumVertices, Flags);

4013
    return IDirect3DDevice7_DrawPrimitiveVB(&device->IDirect3DDevice7_iface,
4014
            PrimitiveType, &vb->IDirect3DVertexBuffer7_iface, StartVertex, NumVertices, Flags);
4015 4016 4017 4018 4019 4020 4021 4022 4023 4024 4025 4026 4027 4028 4029 4030 4031 4032 4033 4034
}


/*****************************************************************************
 * IDirect3DDevice7::DrawIndexedPrimitiveVB
 *
 * Draws primitives from a vertex buffer to the screen
 *
 * Params:
 *  PrimitiveType: Type of primitive to be rendered.
 *  D3DVertexBuf: Source Vertex Buffer
 *  StartVertex: Index of the first vertex from the buffer to be rendered
 *  NumVertices: Number of vertices to be rendered
 *  Indices: Array of DWORDs used to index into the Vertices
 *  IndexCount: Number of indices in Indices
 *  Flags: Can be D3DDP_WAIT to wait until rendering has finished
 *
 * Return values
 *
 *****************************************************************************/
4035 4036 4037 4038 4039
static HRESULT d3d_device7_DrawIndexedPrimitiveVB(IDirect3DDevice7 *iface,
        D3DPRIMITIVETYPE PrimitiveType, IDirect3DVertexBuffer7 *D3DVertexBuf,
        DWORD StartVertex, DWORD NumVertices, WORD *Indices, DWORD IndexCount, DWORD Flags)
{
    struct d3d_device *This = impl_from_IDirect3DDevice7(iface);
4040
    struct d3d_vertex_buffer *vb = unsafe_impl_from_IDirect3DVertexBuffer7(D3DVertexBuf);
4041
    DWORD stride = get_flexible_vertex_size(vb->fvf);
4042
    struct wined3d_resource *wined3d_resource;
4043
    struct wined3d_resource_desc desc;
4044 4045 4046
    WORD *LockedIndices;
    HRESULT hr;

4047 4048
    TRACE("iface %p, primitive_type %#x, vb %p, start_vertex %u, vertex_count %u, indices %p, index_count %u, flags %#x.\n",
            iface, PrimitiveType, D3DVertexBuf, StartVertex, NumVertices, Indices, IndexCount, Flags);
4049 4050

    /* Steps:
4051 4052 4053 4054
     * 1) Upload the Indices to the index buffer
     * 2) Set the index source
     * 3) Set the Vertex Buffer as the Stream source
     * 4) Call IWineD3DDevice::DrawIndexedPrimitive
4055 4056
     */

4057
    wined3d_mutex_lock();
4058

4059
    wined3d_device_set_vertex_declaration(This->wined3d_device, vb->wineD3DVertexDeclaration);
4060

4061
    /* check that the buffer is large enough to hold the indices,
4062
     * reallocate if necessary. */
4063 4064
    wined3d_resource = wined3d_buffer_get_resource(This->indexbuffer);
    wined3d_resource_get_desc(wined3d_resource, &desc);
4065
    if (desc.size < IndexCount * sizeof(WORD))
4066
    {
4067
        UINT size = max(desc.size * 2, IndexCount * sizeof(WORD));
4068
        struct wined3d_buffer *buffer;
4069 4070 4071

        TRACE("Growing index buffer to %u bytes\n", size);

4072
        hr = wined3d_buffer_create_ib(This->wined3d_device, size, WINED3DUSAGE_DYNAMIC /* Usage */,
4073
                WINED3D_POOL_DEFAULT, NULL, &ddraw_null_wined3d_parent_ops, &buffer);
4074
        if (FAILED(hr))
4075 4076
        {
            ERR("(%p) IWineD3DDevice::CreateIndexBuffer failed with hr = %08x\n", This, hr);
4077
            wined3d_mutex_unlock();
4078 4079 4080
            return hr;
        }

4081
        wined3d_buffer_decref(This->indexbuffer);
4082 4083 4084
        This->indexbuffer = buffer;
    }

4085 4086 4087 4088 4089 4090 4091
    /* Copy the index stream into the index buffer. A new IWineD3DDevice
     * method could be created which takes an user pointer containing the
     * indices or a SetData-Method for the index buffer, which overrides the
     * index buffer data with our pointer. */
    hr = wined3d_buffer_map(This->indexbuffer, 0, IndexCount * sizeof(WORD),
            (BYTE **)&LockedIndices, 0);
    if (FAILED(hr))
4092
    {
4093
        ERR("Failed to map buffer, hr %#x.\n", hr);
4094
        wined3d_mutex_unlock();
4095 4096 4097
        return hr;
    }
    memcpy(LockedIndices, Indices, IndexCount * sizeof(WORD));
4098
    wined3d_buffer_unmap(This->indexbuffer);
4099 4100

    /* Set the index stream */
4101
    wined3d_device_set_base_vertex_index(This->wined3d_device, StartVertex);
4102
    wined3d_device_set_index_buffer(This->wined3d_device, This->indexbuffer, WINED3DFMT_R16_UINT);
4103

4104
    /* Set the vertex stream source */
4105
    hr = wined3d_device_set_stream_source(This->wined3d_device, 0, vb->wineD3DVertexBuffer, 0, stride);
4106
    if (FAILED(hr))
4107
    {
4108
        ERR("(%p) IDirect3DDevice::SetStreamSource failed with hr = %08x\n", This, hr);
4109
        wined3d_mutex_unlock();
4110 4111 4112 4113
        return hr;
    }


4114 4115
    wined3d_device_set_primitive_type(This->wined3d_device, PrimitiveType);
    hr = wined3d_device_draw_indexed_primitive(This->wined3d_device, 0, IndexCount);
4116

4117 4118
    wined3d_mutex_unlock();

4119
    return hr;
4120 4121
}

4122 4123 4124
static HRESULT WINAPI d3d_device7_DrawIndexedPrimitiveVB_FPUSetup(IDirect3DDevice7 *iface,
        D3DPRIMITIVETYPE PrimitiveType, IDirect3DVertexBuffer7 *D3DVertexBuf,
        DWORD StartVertex, DWORD NumVertices, WORD *Indices, DWORD IndexCount, DWORD Flags)
4125
{
4126 4127
    return d3d_device7_DrawIndexedPrimitiveVB(iface, PrimitiveType,
            D3DVertexBuf, StartVertex, NumVertices, Indices, IndexCount, Flags);
4128 4129
}

4130 4131 4132
static HRESULT WINAPI d3d_device7_DrawIndexedPrimitiveVB_FPUPreserve(IDirect3DDevice7 *iface,
        D3DPRIMITIVETYPE PrimitiveType, IDirect3DVertexBuffer7 *D3DVertexBuf,
        DWORD StartVertex, DWORD NumVertices, WORD *Indices, DWORD IndexCount, DWORD Flags)
4133 4134 4135 4136 4137
{
    HRESULT hr;
    WORD old_fpucw;

    old_fpucw = d3d_fpu_setup();
4138 4139
    hr = d3d_device7_DrawIndexedPrimitiveVB(iface, PrimitiveType,
            D3DVertexBuf, StartVertex, NumVertices, Indices, IndexCount, Flags);
4140 4141 4142 4143 4144
    set_fpu_control_word(old_fpucw);

    return hr;
}

4145
static HRESULT WINAPI d3d_device3_DrawIndexedPrimitiveVB(IDirect3DDevice3 *iface,
4146 4147
        D3DPRIMITIVETYPE PrimitiveType, IDirect3DVertexBuffer *D3DVertexBuf, WORD *Indices,
        DWORD IndexCount, DWORD Flags)
4148
{
4149
    struct d3d_device *device = impl_from_IDirect3DDevice3(iface);
4150
    struct d3d_vertex_buffer *vb = unsafe_impl_from_IDirect3DVertexBuffer(D3DVertexBuf);
4151

4152 4153 4154
    TRACE("iface %p, primitive_type %#x, vb %p, indices %p, index_count %u, flags %#x.\n",
            iface, PrimitiveType, D3DVertexBuf, Indices, IndexCount, Flags);

4155 4156
    return IDirect3DDevice7_DrawIndexedPrimitiveVB(&device->IDirect3DDevice7_iface, PrimitiveType,
            &vb->IDirect3DVertexBuffer7_iface, 0, IndexCount, Indices, IndexCount, Flags);
4157 4158 4159 4160 4161 4162 4163
}

/*****************************************************************************
 * IDirect3DDevice7::ComputeSphereVisibility
 *
 * Calculates the visibility of spheres in the current viewport. The spheres
 * are passed in the Centers and Radii arrays, the results are passed back
4164
 * in the ReturnValues array. Return values are either completely visible,
4165 4166 4167 4168 4169 4170 4171 4172
 * partially visible or completely invisible.
 * The return value consist of a combination of D3DCLIP_* flags, or it's
 * 0 if the sphere is completely visible(according to the SDK, not checked)
 *
 * Version 3 and 7
 *
 * Params:
 *  Centers: Array containing the sphere centers
4173 4174
 *  Radii: Array containing the sphere radii
 *  NumSpheres: The number of centers and radii in the arrays
4175 4176 4177 4178
 *  Flags: Some flags
 *  ReturnValues: Array to write the results to
 *
 * Returns:
4179
 *  D3D_OK
4180 4181 4182 4183 4184
 *  (DDERR_INVALIDPARAMS if Centers, Radii or ReturnValues are NULL)
 *  (D3DERR_INVALIDMATRIX if the combined world, view and proj matrix
 *  is singular)
 *
 *****************************************************************************/
4185 4186 4187 4188 4189 4190 4191 4192 4193 4194 4195 4196 4197

static DWORD in_plane(UINT plane, D3DVECTOR normal, D3DVALUE origin_plane, D3DVECTOR center, D3DVALUE radius)
{
    float distance, norm;

    norm = sqrt( normal.u1.x * normal.u1.x + normal.u2.y * normal.u2.y + normal.u3.z * normal.u3.z );
    distance = ( origin_plane + normal.u1.x * center.u1.x + normal.u2.y * center.u2.y + normal.u3.z * center.u3.z ) / norm;

    if ( fabs( distance ) < radius ) return D3DSTATUS_CLIPUNIONLEFT << plane;
    if ( distance < -radius ) return (D3DSTATUS_CLIPUNIONLEFT  | D3DSTATUS_CLIPINTERSECTIONLEFT) << plane;
    return 0;
}

4198 4199
static HRESULT WINAPI d3d_device7_ComputeSphereVisibility(IDirect3DDevice7 *iface,
        D3DVECTOR *centers, D3DVALUE *radii, DWORD sphere_count, DWORD flags, DWORD *return_values)
4200
{
4201 4202 4203 4204 4205 4206
    D3DMATRIX m, temp;
    D3DVALUE origin_plane[6];
    D3DVECTOR vec[6];
    HRESULT hr;
    UINT i, j;

4207
    TRACE("iface %p, centers %p, radii %p, sphere_count %u, flags %#x, return_values %p.\n",
4208
            iface, centers, radii, sphere_count, flags, return_values);
4209

4210
    hr = d3d_device7_GetTransform(iface, D3DTRANSFORMSTATE_WORLD, &m);
4211
    if ( hr != DD_OK ) return DDERR_INVALIDPARAMS;
4212
    hr = d3d_device7_GetTransform(iface, D3DTRANSFORMSTATE_VIEW, &temp);
4213
    if ( hr != DD_OK ) return DDERR_INVALIDPARAMS;
4214
    multiply_matrix(&m, &temp, &m);
4215

4216
    hr = d3d_device7_GetTransform(iface, D3DTRANSFORMSTATE_PROJECTION, &temp);
4217
    if ( hr != DD_OK ) return DDERR_INVALIDPARAMS;
4218
    multiply_matrix(&m, &temp, &m);
4219 4220 4221 4222 4223 4224 4225 4226 4227 4228 4229 4230 4231 4232 4233 4234 4235 4236 4237 4238 4239 4240 4241 4242 4243 4244 4245 4246 4247 4248 4249 4250 4251 4252 4253 4254 4255

/* Left plane */
    vec[0].u1.x = m._14 + m._11;
    vec[0].u2.y = m._24 + m._21;
    vec[0].u3.z = m._34 + m._31;
    origin_plane[0] = m._44 + m._41;

/* Right plane */
    vec[1].u1.x = m._14 - m._11;
    vec[1].u2.y = m._24 - m._21;
    vec[1].u3.z = m._34 - m._31;
    origin_plane[1] = m._44 - m._41;

/* Top plane */
    vec[2].u1.x = m._14 - m._12;
    vec[2].u2.y = m._24 - m._22;
    vec[2].u3.z = m._34 - m._32;
    origin_plane[2] = m._44 - m._42;

/* Bottom plane */
    vec[3].u1.x = m._14 + m._12;
    vec[3].u2.y = m._24 + m._22;
    vec[3].u3.z = m._34 + m._32;
    origin_plane[3] = m._44 + m._42;

/* Front plane */
    vec[4].u1.x = m._13;
    vec[4].u2.y = m._23;
    vec[4].u3.z = m._33;
    origin_plane[4] = m._43;

/* Back plane*/
    vec[5].u1.x = m._14 - m._13;
    vec[5].u2.y = m._24 - m._23;
    vec[5].u3.z = m._34 - m._33;
    origin_plane[5] = m._44 - m._43;

4256
    for (i = 0; i < sphere_count; ++i)
4257
    {
4258 4259 4260
        return_values[i] = 0;
        for (j = 0; j < 6; ++j)
            return_values[i] |= in_plane(j, vec[j], origin_plane[j], centers[i], radii[i]);
4261
    }
4262 4263 4264 4265

    return D3D_OK;
}

4266 4267
static HRESULT WINAPI d3d_device3_ComputeSphereVisibility(IDirect3DDevice3 *iface,
        D3DVECTOR *centers, D3DVALUE *radii, DWORD sphere_count, DWORD flags, DWORD *return_values)
4268
{
4269
    struct d3d_device *device = impl_from_IDirect3DDevice3(iface);
4270

4271
    TRACE("iface %p, centers %p, radii %p, sphere_count %u, flags %#x, return_values %p.\n",
4272
            iface, centers, radii, sphere_count, flags, return_values);
4273

4274 4275
    return IDirect3DDevice7_ComputeSphereVisibility(&device->IDirect3DDevice7_iface,
            centers, radii, sphere_count, flags, return_values);
4276 4277 4278 4279 4280 4281 4282 4283 4284 4285 4286 4287 4288 4289 4290 4291 4292 4293 4294 4295 4296
}

/*****************************************************************************
 * IDirect3DDevice7::GetTexture
 *
 * Returns the texture interface handle assigned to a texture stage.
 * The returned texture is AddRefed. This is taken from old ddraw,
 * not checked in Windows.
 *
 * Version 3 and 7
 *
 * Params:
 *  Stage: Texture stage to read the texture from
 *  Texture: Address to store the interface pointer at
 *
 * Returns:
 *  D3D_OK on success
 *  DDERR_INVALIDPARAMS if Texture is NULL
 *  For details, see IWineD3DDevice::GetTexture
 *
 *****************************************************************************/
4297 4298
static HRESULT d3d_device7_GetTexture(IDirect3DDevice7 *iface,
        DWORD stage, IDirectDrawSurface7 **texture)
4299
{
4300
    struct d3d_device *device = impl_from_IDirect3DDevice7(iface);
4301
    struct wined3d_texture *wined3d_texture;
4302
    struct ddraw_surface *surface;
4303

4304
    TRACE("iface %p, stage %u, texture %p.\n", iface, stage, texture);
4305

4306
    if (!texture)
4307 4308
        return DDERR_INVALIDPARAMS;

4309
    wined3d_mutex_lock();
4310
    if (!(wined3d_texture = wined3d_device_get_texture(device->wined3d_device, stage)))
4311
    {
4312
        *texture = NULL;
4313
        wined3d_mutex_unlock();
4314
        return D3D_OK;
4315 4316
    }

4317
    surface = wined3d_texture_get_parent(wined3d_texture);
4318 4319
    *texture = &surface->IDirectDrawSurface7_iface;
    IDirectDrawSurface7_AddRef(*texture);
4320 4321
    wined3d_mutex_unlock();

4322
    return D3D_OK;
4323 4324
}

4325 4326
static HRESULT WINAPI d3d_device7_GetTexture_FPUSetup(IDirect3DDevice7 *iface,
        DWORD stage, IDirectDrawSurface7 **Texture)
4327
{
4328
    return d3d_device7_GetTexture(iface, stage, Texture);
4329 4330
}

4331 4332
static HRESULT WINAPI d3d_device7_GetTexture_FPUPreserve(IDirect3DDevice7 *iface,
        DWORD stage, IDirectDrawSurface7 **Texture)
4333 4334 4335 4336 4337
{
    HRESULT hr;
    WORD old_fpucw;

    old_fpucw = d3d_fpu_setup();
4338
    hr = d3d_device7_GetTexture(iface, stage, Texture);
4339 4340 4341 4342 4343
    set_fpu_control_word(old_fpucw);

    return hr;
}

4344
static HRESULT WINAPI d3d_device3_GetTexture(IDirect3DDevice3 *iface, DWORD stage, IDirect3DTexture2 **Texture2)
4345
{
4346
    struct d3d_device *device = impl_from_IDirect3DDevice3(iface);
4347
    struct ddraw_surface *ret_val_impl;
4348 4349 4350
    HRESULT ret;
    IDirectDrawSurface7 *ret_val;

4351
    TRACE("iface %p, stage %u, texture %p.\n", iface, stage, Texture2);
4352

4353
    ret = IDirect3DDevice7_GetTexture(&device->IDirect3DDevice7_iface, stage, &ret_val);
4354

4355
    ret_val_impl = unsafe_impl_from_IDirectDrawSurface7(ret_val);
4356
    *Texture2 = ret_val_impl ? &ret_val_impl->IDirect3DTexture2_iface : NULL;
4357

4358
    TRACE("Returning texture %p.\n", *Texture2);
4359 4360 4361 4362 4363 4364 4365

    return ret;
}

/*****************************************************************************
 * IDirect3DDevice7::SetTexture
 *
4366
 * Assigns a texture to a texture stage. Is the texture AddRef-ed?
4367 4368 4369 4370 4371 4372 4373 4374 4375 4376 4377 4378
 *
 * Version 3 and 7
 *
 * Params:
 *  Stage: The stage to assign the texture to
 *  Texture: Interface pointer to the texture surface
 *
 * Returns
 * D3D_OK on success
 * For details, see IWineD3DDevice::SetTexture
 *
 *****************************************************************************/
4379 4380
static HRESULT d3d_device7_SetTexture(IDirect3DDevice7 *iface,
        DWORD stage, IDirectDrawSurface7 *texture)
4381
{
4382 4383
    struct d3d_device *device = impl_from_IDirect3DDevice7(iface);
    struct ddraw_surface *surf = unsafe_impl_from_IDirectDrawSurface7(texture);
4384
    HRESULT hr;
4385

4386
    TRACE("iface %p, stage %u, texture %p.\n", iface, stage, texture);
4387 4388

    /* Texture may be NULL here */
4389
    wined3d_mutex_lock();
4390 4391
    hr = wined3d_device_set_texture(device->wined3d_device,
            stage, surf ? surf->wined3d_texture : NULL);
4392 4393
    wined3d_mutex_unlock();

4394
    return hr;
4395 4396
}

4397 4398
static HRESULT WINAPI d3d_device7_SetTexture_FPUSetup(IDirect3DDevice7 *iface,
        DWORD stage, IDirectDrawSurface7 *texture)
4399
{
4400
    return d3d_device7_SetTexture(iface, stage, texture);
4401 4402
}

4403 4404
static HRESULT WINAPI d3d_device7_SetTexture_FPUPreserve(IDirect3DDevice7 *iface,
        DWORD stage, IDirectDrawSurface7 *texture)
4405 4406 4407 4408 4409
{
    HRESULT hr;
    WORD old_fpucw;

    old_fpucw = d3d_fpu_setup();
4410
    hr = d3d_device7_SetTexture(iface, stage, texture);
4411 4412 4413 4414 4415
    set_fpu_control_word(old_fpucw);

    return hr;
}

4416 4417
static HRESULT WINAPI d3d_device3_SetTexture(IDirect3DDevice3 *iface,
        DWORD stage, IDirect3DTexture2 *texture)
4418
{
4419 4420
    struct d3d_device *device = impl_from_IDirect3DDevice3(iface);
    struct ddraw_surface *tex = unsafe_impl_from_IDirect3DTexture2(texture);
4421 4422
    DWORD texmapblend;
    HRESULT hr;
4423

4424
    TRACE("iface %p, stage %u, texture %p.\n", iface, stage, texture);
4425

4426
    wined3d_mutex_lock();
4427

4428
    if (device->legacyTextureBlending)
4429 4430
        IDirect3DDevice3_GetRenderState(iface, D3DRENDERSTATE_TEXTUREMAPBLEND, &texmapblend);

4431
    hr = IDirect3DDevice7_SetTexture(&device->IDirect3DDevice7_iface, stage, &tex->IDirectDrawSurface7_iface);
4432

4433
    if (device->legacyTextureBlending && texmapblend == D3DTBLEND_MODULATE)
4434 4435
    {
        /* This fixup is required by the way D3DTBLEND_MODULATE maps to texture stage states.
4436
           See d3d_device3_SetRenderState() for details. */
4437
        struct wined3d_texture *tex = NULL;
4438 4439 4440
        BOOL tex_alpha = FALSE;
        DDPIXELFORMAT ddfmt;

4441
        if ((tex = wined3d_device_get_texture(device->wined3d_device, 0)))
4442
        {
4443 4444
            struct wined3d_resource *sub_resource;

4445
            if ((sub_resource = wined3d_texture_get_sub_resource(tex, 0)))
4446
            {
4447 4448 4449
                struct wined3d_resource_desc desc;

                wined3d_resource_get_desc(sub_resource, &desc);
4450
                ddfmt.dwSize = sizeof(ddfmt);
4451
                PixelFormat_WineD3DtoDD(&ddfmt, desc.format);
4452 4453 4454 4455
                if (ddfmt.u5.dwRGBAlphaBitMask) tex_alpha = TRUE;
            }
        }

4456
        /* Arg 1/2 are already set to WINED3DTA_TEXTURE/WINED3DTA_CURRENT in case of D3DTBLEND_MODULATE */
4457
        if (tex_alpha)
4458
            wined3d_device_set_texture_stage_state(device->wined3d_device,
4459
                    0, WINED3D_TSS_ALPHA_OP, WINED3D_TOP_SELECT_ARG1);
4460
        else
4461
            wined3d_device_set_texture_stage_state(device->wined3d_device,
4462
                    0, WINED3D_TSS_ALPHA_OP, WINED3D_TOP_SELECT_ARG2);
4463 4464
    }

4465
    wined3d_mutex_unlock();
4466

4467
    return hr;
4468 4469
}

4470 4471 4472
static const struct tss_lookup
{
    BOOL sampler_state;
4473
    enum wined3d_texture_stage_state state;
4474 4475 4476
}
tss_lookup[] =
{
4477 4478 4479 4480 4481 4482 4483 4484 4485 4486 4487 4488 4489 4490 4491 4492 4493 4494 4495 4496 4497 4498 4499 4500 4501
    {FALSE, WINED3D_TSS_INVALID},                   /*  0, unused */
    {FALSE, WINED3D_TSS_COLOR_OP},                  /*  1, D3DTSS_COLOROP */
    {FALSE, WINED3D_TSS_COLOR_ARG1},                /*  2, D3DTSS_COLORARG1 */
    {FALSE, WINED3D_TSS_COLOR_ARG2},                /*  3, D3DTSS_COLORARG2 */
    {FALSE, WINED3D_TSS_ALPHA_OP},                  /*  4, D3DTSS_ALPHAOP */
    {FALSE, WINED3D_TSS_ALPHA_ARG1},                /*  5, D3DTSS_ALPHAARG1 */
    {FALSE, WINED3D_TSS_ALPHA_ARG2},                /*  6, D3DTSS_ALPHAARG2 */
    {FALSE, WINED3D_TSS_BUMPENV_MAT00},             /*  7, D3DTSS_BUMPENVMAT00 */
    {FALSE, WINED3D_TSS_BUMPENV_MAT01},             /*  8, D3DTSS_BUMPENVMAT01 */
    {FALSE, WINED3D_TSS_BUMPENV_MAT10},             /*  9, D3DTSS_BUMPENVMAT10 */
    {FALSE, WINED3D_TSS_BUMPENV_MAT11},             /* 10, D3DTSS_BUMPENVMAT11 */
    {FALSE, WINED3D_TSS_TEXCOORD_INDEX},            /* 11, D3DTSS_TEXCOORDINDEX */
    {TRUE,  WINED3D_SAMP_ADDRESS_U},                /* 12, D3DTSS_ADDRESS */
    {TRUE,  WINED3D_SAMP_ADDRESS_U},                /* 13, D3DTSS_ADDRESSU */
    {TRUE,  WINED3D_SAMP_ADDRESS_V},                /* 14, D3DTSS_ADDRESSV */
    {TRUE,  WINED3D_SAMP_BORDER_COLOR},             /* 15, D3DTSS_BORDERCOLOR */
    {TRUE,  WINED3D_SAMP_MAG_FILTER},               /* 16, D3DTSS_MAGFILTER */
    {TRUE,  WINED3D_SAMP_MIN_FILTER},               /* 17, D3DTSS_MINFILTER */
    {TRUE,  WINED3D_SAMP_MIP_FILTER},               /* 18, D3DTSS_MIPFILTER */
    {TRUE,  WINED3D_SAMP_MIPMAP_LOD_BIAS},          /* 19, D3DTSS_MIPMAPLODBIAS */
    {TRUE,  WINED3D_SAMP_MAX_MIP_LEVEL},            /* 20, D3DTSS_MAXMIPLEVEL */
    {TRUE,  WINED3D_SAMP_MAX_ANISOTROPY},           /* 21, D3DTSS_MAXANISOTROPY */
    {FALSE, WINED3D_TSS_BUMPENV_LSCALE},            /* 22, D3DTSS_BUMPENVLSCALE */
    {FALSE, WINED3D_TSS_BUMPENV_LOFFSET},           /* 23, D3DTSS_BUMPENVLOFFSET */
    {FALSE, WINED3D_TSS_TEXTURE_TRANSFORM_FLAGS},   /* 24, D3DTSS_TEXTURETRANSFORMFLAGS */
4502 4503
};

4504 4505 4506 4507 4508 4509 4510 4511 4512 4513 4514 4515 4516 4517 4518 4519 4520 4521
/*****************************************************************************
 * IDirect3DDevice7::GetTextureStageState
 *
 * Retrieves a state from a texture stage.
 *
 * Version 3 and 7
 *
 * Params:
 *  Stage: The stage to retrieve the state from
 *  TexStageStateType: The state type to retrieve
 *  State: Address to store the state's value at
 *
 * Returns:
 *  D3D_OK on success
 *  DDERR_INVALIDPARAMS if State is NULL
 *  For details, see IWineD3DDevice::GetTextureStageState
 *
 *****************************************************************************/
4522 4523
static HRESULT d3d_device7_GetTextureStageState(IDirect3DDevice7 *iface,
        DWORD stage, D3DTEXTURESTAGESTATETYPE state, DWORD *value)
4524
{
4525
    struct d3d_device *device = impl_from_IDirect3DDevice7(iface);
4526
    const struct tss_lookup *l;
4527 4528

    TRACE("iface %p, stage %u, state %#x, value %p.\n",
4529
            iface, stage, state, value);
4530

4531
    if (!value)
4532 4533
        return DDERR_INVALIDPARAMS;

4534
    if (state > D3DTSS_TEXTURETRANSFORMFLAGS)
4535
    {
4536
        WARN("Invalid state %#x passed.\n", state);
4537 4538 4539
        return DD_OK;
    }

4540
    l = &tss_lookup[state];
4541

4542
    wined3d_mutex_lock();
4543 4544

    if (l->sampler_state)
4545
    {
4546
        *value = wined3d_device_get_sampler_state(device->wined3d_device, stage, l->state);
4547

4548
        switch (state)
4549 4550 4551
        {
            /* Mipfilter is a sampler state with different values */
            case D3DTSS_MIPFILTER:
4552
            {
4553
                switch (*value)
4554
                {
4555
                    case WINED3D_TEXF_NONE:
4556
                        *value = D3DTFP_NONE;
4557 4558
                        break;
                    case WINED3D_TEXF_POINT:
4559
                        *value = D3DTFP_POINT;
4560 4561
                        break;
                    case WINED3D_TEXF_LINEAR:
4562
                        *value = D3DTFP_LINEAR;
4563
                        break;
4564
                    default:
4565 4566
                        ERR("Unexpected mipfilter value %#x.\n", *value);
                        *value = D3DTFP_NONE;
4567 4568 4569
                        break;
                }
                break;
4570
            }
4571

4572 4573
            /* Magfilter has slightly different values */
            case D3DTSS_MAGFILTER:
4574
            {
4575
                switch (*value)
4576
                {
4577
                    case WINED3D_TEXF_POINT:
4578
                            *value = D3DTFG_POINT;
4579 4580
                            break;
                    case WINED3D_TEXF_LINEAR:
4581
                            *value = D3DTFG_LINEAR;
4582 4583
                            break;
                    case WINED3D_TEXF_ANISOTROPIC:
4584
                            *value = D3DTFG_ANISOTROPIC;
4585 4586
                            break;
                    case WINED3D_TEXF_FLAT_CUBIC:
4587
                            *value = D3DTFG_FLATCUBIC;
4588 4589
                            break;
                    case WINED3D_TEXF_GAUSSIAN_CUBIC:
4590
                            *value = D3DTFG_GAUSSIANCUBIC;
4591
                            break;
4592
                    default:
4593 4594
                        ERR("Unexpected wined3d mag filter value %#x.\n", *value);
                        *value = D3DTFG_POINT;
4595 4596 4597
                        break;
                }
                break;
4598
            }
4599

4600 4601 4602 4603 4604 4605
            default:
                break;
        }
    }
    else
    {
4606
        *value = wined3d_device_get_texture_stage_state(device->wined3d_device, stage, l->state);
4607
    }
4608

4609 4610
    wined3d_mutex_unlock();

4611
    return D3D_OK;
4612 4613
}

4614 4615
static HRESULT WINAPI d3d_device7_GetTextureStageState_FPUSetup(IDirect3DDevice7 *iface,
        DWORD stage, D3DTEXTURESTAGESTATETYPE state, DWORD *value)
4616
{
4617
    return d3d_device7_GetTextureStageState(iface, stage, state, value);
4618 4619
}

4620 4621
static HRESULT WINAPI d3d_device7_GetTextureStageState_FPUPreserve(IDirect3DDevice7 *iface,
        DWORD stage, D3DTEXTURESTAGESTATETYPE state, DWORD *value)
4622 4623 4624 4625 4626
{
    HRESULT hr;
    WORD old_fpucw;

    old_fpucw = d3d_fpu_setup();
4627
    hr = d3d_device7_GetTextureStageState(iface, stage, state, value);
4628 4629 4630 4631 4632
    set_fpu_control_word(old_fpucw);

    return hr;
}

4633 4634
static HRESULT WINAPI d3d_device3_GetTextureStageState(IDirect3DDevice3 *iface,
        DWORD stage, D3DTEXTURESTAGESTATETYPE state, DWORD *value)
4635
{
4636
    struct d3d_device *device = impl_from_IDirect3DDevice3(iface);
4637

4638
    TRACE("iface %p, stage %u, state %#x, value %p.\n",
4639
            iface, stage, state, value);
4640

4641
    return IDirect3DDevice7_GetTextureStageState(&device->IDirect3DDevice7_iface, stage, state, value);
4642 4643 4644 4645 4646 4647 4648 4649 4650 4651 4652 4653 4654 4655 4656 4657 4658 4659 4660 4661
}

/*****************************************************************************
 * IDirect3DDevice7::SetTextureStageState
 *
 * Sets a texture stage state. Some stage types need to be handled specially,
 * because they do not exist in WineD3D and were moved to another place
 *
 * Version 3 and 7
 *
 * Params:
 *  Stage: The stage to modify
 *  TexStageStateType: The state to change
 *  State: The new value for the state
 *
 * Returns:
 *  D3D_OK on success
 *  For details, see IWineD3DDevice::SetTextureStageState
 *
 *****************************************************************************/
4662 4663
static HRESULT d3d_device7_SetTextureStageState(IDirect3DDevice7 *iface,
        DWORD stage, D3DTEXTURESTAGESTATETYPE state, DWORD value)
4664
{
4665
    struct d3d_device *device = impl_from_IDirect3DDevice7(iface);
4666
    const struct tss_lookup *l;
4667 4668

    TRACE("iface %p, stage %u, state %#x, value %#x.\n",
4669
            iface, stage, state, value);
4670

4671
    if (state > D3DTSS_TEXTURETRANSFORMFLAGS)
4672
    {
4673
        WARN("Invalid state %#x passed.\n", state);
4674 4675 4676
        return DD_OK;
    }

4677
    l = &tss_lookup[state];
4678

4679
    wined3d_mutex_lock();
4680 4681

    if (l->sampler_state)
4682
    {
4683
        switch (state)
4684
        {
4685 4686
            /* Mipfilter is a sampler state with different values */
            case D3DTSS_MIPFILTER:
4687
            {
4688
                switch (value)
4689
                {
4690
                    case D3DTFP_NONE:
4691
                        value = WINED3D_TEXF_NONE;
4692 4693
                        break;
                    case D3DTFP_POINT:
4694
                        value = WINED3D_TEXF_POINT;
4695
                        break;
4696
                    case 0: /* Unchecked */
4697
                    case D3DTFP_LINEAR:
4698
                        value = WINED3D_TEXF_LINEAR;
4699
                        break;
4700
                    default:
4701 4702
                        ERR("Unexpected mipfilter value %#x.\n", value);
                        value = WINED3D_TEXF_NONE;
4703 4704 4705
                        break;
                }
                break;
4706 4707
            }

4708 4709
            /* Magfilter has slightly different values */
            case D3DTSS_MAGFILTER:
4710
            {
4711
                switch (value)
4712
                {
4713
                    case D3DTFG_POINT:
4714
                        value = WINED3D_TEXF_POINT;
4715 4716
                        break;
                    case D3DTFG_LINEAR:
4717
                        value = WINED3D_TEXF_LINEAR;
4718 4719
                        break;
                    case D3DTFG_FLATCUBIC:
4720
                        value = WINED3D_TEXF_FLAT_CUBIC;
4721 4722
                        break;
                    case D3DTFG_GAUSSIANCUBIC:
4723
                        value = WINED3D_TEXF_GAUSSIAN_CUBIC;
4724 4725
                        break;
                    case D3DTFG_ANISOTROPIC:
4726
                        value = WINED3D_TEXF_ANISOTROPIC;
4727
                        break;
4728
                    default:
4729 4730
                        ERR("Unexpected d3d7 mag filter value %#x.\n", value);
                        value = WINED3D_TEXF_POINT;
4731 4732 4733
                        break;
                }
                break;
4734
            }
4735

4736
            case D3DTSS_ADDRESS:
4737
                wined3d_device_set_sampler_state(device->wined3d_device, stage, WINED3D_SAMP_ADDRESS_V, value);
4738
                break;
4739

4740 4741 4742
            default:
                break;
        }
4743

4744
        wined3d_device_set_sampler_state(device->wined3d_device, stage, l->state, value);
4745
    }
4746 4747
    else
    {
4748
        wined3d_device_set_texture_stage_state(device->wined3d_device, stage, l->state, value);
4749 4750
    }

4751 4752
    wined3d_mutex_unlock();

4753
    return D3D_OK;
4754 4755
}

4756 4757
static HRESULT WINAPI d3d_device7_SetTextureStageState_FPUSetup(IDirect3DDevice7 *iface,
        DWORD stage, D3DTEXTURESTAGESTATETYPE state, DWORD value)
4758
{
4759
    return d3d_device7_SetTextureStageState(iface, stage, state, value);
4760 4761
}

4762 4763
static HRESULT WINAPI d3d_device7_SetTextureStageState_FPUPreserve(IDirect3DDevice7 *iface,
        DWORD stage, D3DTEXTURESTAGESTATETYPE state, DWORD value)
4764 4765 4766 4767 4768
{
    HRESULT hr;
    WORD old_fpucw;

    old_fpucw = d3d_fpu_setup();
4769
    hr = d3d_device7_SetTextureStageState(iface, stage, state, value);
4770 4771 4772 4773 4774
    set_fpu_control_word(old_fpucw);

    return hr;
}

4775 4776
static HRESULT WINAPI d3d_device3_SetTextureStageState(IDirect3DDevice3 *iface,
        DWORD stage, D3DTEXTURESTAGESTATETYPE state, DWORD value)
4777
{
4778
    struct d3d_device *device = impl_from_IDirect3DDevice3(iface);
4779

4780
    TRACE("iface %p, stage %u, state %#x, value %#x.\n",
4781
            iface, stage, state, value);
4782

4783
    return IDirect3DDevice7_SetTextureStageState(&device->IDirect3DDevice7_iface, stage, state, value);
4784 4785 4786 4787 4788 4789 4790 4791 4792 4793 4794 4795
}

/*****************************************************************************
 * IDirect3DDevice7::ValidateDevice
 *
 * SDK: "Reports the device's ability to render the currently set
 * texture-blending operations in a single pass". Whatever that means
 * exactly...
 *
 * Version 3 and 7
 *
 * Params:
4796
 *  NumPasses: Address to write the number of necessary passes for the
4797 4798 4799 4800 4801 4802 4803
 *             desired effect to.
 *
 * Returns:
 *  D3D_OK on success
 *  See IWineD3DDevice::ValidateDevice for more details
 *
 *****************************************************************************/
4804
static HRESULT d3d_device7_ValidateDevice(IDirect3DDevice7 *iface, DWORD *pass_count)
4805
{
4806
    struct d3d_device *device = impl_from_IDirect3DDevice7(iface);
4807
    HRESULT hr;
4808

4809
    TRACE("iface %p, pass_count %p.\n", iface, pass_count);
4810

4811
    wined3d_mutex_lock();
4812
    hr = wined3d_device_validate_device(device->wined3d_device, pass_count);
4813 4814
    wined3d_mutex_unlock();

4815
    return hr;
4816 4817
}

4818
static HRESULT WINAPI d3d_device7_ValidateDevice_FPUSetup(IDirect3DDevice7 *iface, DWORD *pass_count)
4819
{
4820
    return d3d_device7_ValidateDevice(iface, pass_count);
4821 4822
}

4823
static HRESULT WINAPI d3d_device7_ValidateDevice_FPUPreserve(IDirect3DDevice7 *iface, DWORD *pass_count)
4824 4825 4826 4827 4828
{
    HRESULT hr;
    WORD old_fpucw;

    old_fpucw = d3d_fpu_setup();
4829
    hr = d3d_device7_ValidateDevice(iface, pass_count);
4830 4831 4832 4833 4834
    set_fpu_control_word(old_fpucw);

    return hr;
}

4835
static HRESULT WINAPI d3d_device3_ValidateDevice(IDirect3DDevice3 *iface, DWORD *pass_count)
4836
{
4837
    struct d3d_device *device = impl_from_IDirect3DDevice3(iface);
4838

4839
    TRACE("iface %p, pass_count %p.\n", iface, pass_count);
4840

4841
    return IDirect3DDevice7_ValidateDevice(&device->IDirect3DDevice7_iface, pass_count);
4842 4843 4844 4845 4846 4847 4848 4849 4850 4851 4852 4853 4854 4855 4856 4857 4858 4859 4860 4861 4862 4863 4864
}

/*****************************************************************************
 * IDirect3DDevice7::Clear
 *
 * Fills the render target, the z buffer and the stencil buffer with a
 * clear color / value
 *
 * Version 7 only
 *
 * Params:
 *  Count: Number of rectangles in Rects must be 0 if Rects is NULL
 *  Rects: Rectangles to clear. If NULL, the whole surface is cleared
 *  Flags: Some flags, as usual
 *  Color: Clear color for the render target
 *  Z: Clear value for the Z buffer
 *  Stencil: Clear value to store in each stencil buffer entry
 *
 * Returns:
 *  D3D_OK on success
 *  For details, see IWineD3DDevice::Clear
 *
 *****************************************************************************/
4865
static HRESULT d3d_device7_Clear(IDirect3DDevice7 *iface, DWORD count,
4866
        D3DRECT *rects, DWORD flags, D3DCOLOR color, D3DVALUE z, DWORD stencil)
4867
{
4868 4869 4870 4871 4872 4873 4874
    const struct wined3d_color c =
    {
        ((color >> 16) & 0xff) / 255.0f,
        ((color >>  8) & 0xff) / 255.0f,
        (color & 0xff) / 255.0f,
        ((color >> 24) & 0xff) / 255.0f,
    };
4875
    struct d3d_device *This = impl_from_IDirect3DDevice7(iface);
4876
    HRESULT hr;
4877 4878

    TRACE("iface %p, count %u, rects %p, flags %#x, color 0x%08x, z %.8e, stencil %#x.\n",
4879
            iface, count, rects, flags, color, z, stencil);
4880

4881
    wined3d_mutex_lock();
4882
    hr = wined3d_device_clear(This->wined3d_device, count, (RECT *)rects, flags, &c, z, stencil);
4883 4884
    wined3d_mutex_unlock();

4885
    return hr;
4886 4887
}

4888 4889
static HRESULT WINAPI d3d_device7_Clear_FPUSetup(IDirect3DDevice7 *iface, DWORD count,
        D3DRECT *rects, DWORD flags, D3DCOLOR color, D3DVALUE z, DWORD stencil)
4890
{
4891
    return d3d_device7_Clear(iface, count, rects, flags, color, z, stencil);
4892 4893
}

4894 4895
static HRESULT WINAPI d3d_device7_Clear_FPUPreserve(IDirect3DDevice7 *iface, DWORD count,
        D3DRECT *rects, DWORD flags, D3DCOLOR color, D3DVALUE z, DWORD stencil)
4896 4897 4898 4899 4900
{
    HRESULT hr;
    WORD old_fpucw;

    old_fpucw = d3d_fpu_setup();
4901
    hr = d3d_device7_Clear(iface, count, rects, flags, color, z, stencil);
4902 4903 4904 4905 4906
    set_fpu_control_word(old_fpucw);

    return hr;
}

4907 4908 4909 4910 4911 4912 4913 4914 4915 4916 4917 4918 4919 4920 4921 4922 4923
/*****************************************************************************
 * IDirect3DDevice7::SetViewport
 *
 * Sets the current viewport.
 *
 * Version 7 only, but IDirect3DViewport uses this call for older
 * versions
 *
 * Params:
 *  Data: The new viewport to set
 *
 * Returns:
 *  D3D_OK on success
 *  DDERR_INVALIDPARAMS if Data is NULL
 *  For more details, see IWineDDDevice::SetViewport
 *
 *****************************************************************************/
4924
static HRESULT d3d_device7_SetViewport(IDirect3DDevice7 *iface, D3DVIEWPORT7 *viewport)
4925
{
4926
    struct d3d_device *device = impl_from_IDirect3DDevice7(iface);
4927

4928
    TRACE("iface %p, viewport %p.\n", iface, viewport);
4929

4930
    if (!viewport)
4931 4932
        return DDERR_INVALIDPARAMS;

4933
    /* Note: D3DVIEWPORT7 is compatible with struct wined3d_viewport. */
4934
    wined3d_mutex_lock();
4935
    wined3d_device_set_viewport(device->wined3d_device, (struct wined3d_viewport *)viewport);
4936 4937
    wined3d_mutex_unlock();

4938
    return D3D_OK;
4939 4940
}

4941
static HRESULT WINAPI d3d_device7_SetViewport_FPUSetup(IDirect3DDevice7 *iface, D3DVIEWPORT7 *viewport)
4942
{
4943
    return d3d_device7_SetViewport(iface, viewport);
4944 4945
}

4946
static HRESULT WINAPI d3d_device7_SetViewport_FPUPreserve(IDirect3DDevice7 *iface, D3DVIEWPORT7 *viewport)
4947 4948 4949 4950 4951
{
    HRESULT hr;
    WORD old_fpucw;

    old_fpucw = d3d_fpu_setup();
4952
    hr = d3d_device7_SetViewport(iface, viewport);
4953 4954 4955 4956 4957
    set_fpu_control_word(old_fpucw);

    return hr;
}

4958 4959 4960 4961 4962 4963 4964 4965 4966 4967 4968 4969 4970 4971 4972 4973
/*****************************************************************************
 * IDirect3DDevice::GetViewport
 *
 * Returns the current viewport
 *
 * Version 7
 *
 * Params:
 *  Data: D3D7Viewport structure to write the viewport information to
 *
 * Returns:
 *  D3D_OK on success
 *  DDERR_INVALIDPARAMS if Data is NULL
 *  For more details, see IWineD3DDevice::GetViewport
 *
 *****************************************************************************/
4974
static HRESULT d3d_device7_GetViewport(IDirect3DDevice7 *iface, D3DVIEWPORT7 *viewport)
4975
{
4976
    struct d3d_device *device = impl_from_IDirect3DDevice7(iface);
4977

4978
    TRACE("iface %p, viewport %p.\n", iface, viewport);
4979

4980
    if (!viewport)
4981 4982
        return DDERR_INVALIDPARAMS;

4983
    /* Note: D3DVIEWPORT7 is compatible with struct wined3d_viewport. */
4984
    wined3d_mutex_lock();
4985
    wined3d_device_get_viewport(device->wined3d_device, (struct wined3d_viewport *)viewport);
4986
    wined3d_mutex_unlock();
4987

4988
    return D3D_OK;
4989 4990
}

4991
static HRESULT WINAPI d3d_device7_GetViewport_FPUSetup(IDirect3DDevice7 *iface, D3DVIEWPORT7 *viewport)
4992
{
4993
    return d3d_device7_GetViewport(iface, viewport);
4994 4995
}

4996
static HRESULT WINAPI d3d_device7_GetViewport_FPUPreserve(IDirect3DDevice7 *iface, D3DVIEWPORT7 *viewport)
4997 4998 4999 5000 5001
{
    HRESULT hr;
    WORD old_fpucw;

    old_fpucw = d3d_fpu_setup();
5002
    hr = d3d_device7_GetViewport(iface, viewport);
5003 5004 5005 5006 5007
    set_fpu_control_word(old_fpucw);

    return hr;
}

5008 5009 5010 5011 5012 5013 5014 5015 5016 5017 5018 5019 5020 5021 5022 5023
/*****************************************************************************
 * IDirect3DDevice7::SetMaterial
 *
 * Sets the Material
 *
 * Version 7
 *
 * Params:
 *  Mat: The material to set
 *
 * Returns:
 *  D3D_OK on success
 *  DDERR_INVALIDPARAMS if Mat is NULL.
 *  For more details, see IWineD3DDevice::SetMaterial
 *
 *****************************************************************************/
5024
static HRESULT d3d_device7_SetMaterial(IDirect3DDevice7 *iface, D3DMATERIAL7 *material)
5025
{
5026
    struct d3d_device *device = impl_from_IDirect3DDevice7(iface);
5027

5028
    TRACE("iface %p, material %p.\n", iface, material);
5029

5030 5031
    if (!material)
        return DDERR_INVALIDPARAMS;
5032 5033

    wined3d_mutex_lock();
5034
    /* Note: D3DMATERIAL7 is compatible with struct wined3d_material. */
5035
    wined3d_device_set_material(device->wined3d_device, (struct wined3d_material *)material);
5036 5037
    wined3d_mutex_unlock();

5038
    return D3D_OK;
5039 5040
}

5041
static HRESULT WINAPI d3d_device7_SetMaterial_FPUSetup(IDirect3DDevice7 *iface, D3DMATERIAL7 *material)
5042
{
5043
    return d3d_device7_SetMaterial(iface, material);
5044 5045
}

5046
static HRESULT WINAPI d3d_device7_SetMaterial_FPUPreserve(IDirect3DDevice7 *iface, D3DMATERIAL7 *material)
5047 5048 5049 5050 5051
{
    HRESULT hr;
    WORD old_fpucw;

    old_fpucw = d3d_fpu_setup();
5052
    hr = d3d_device7_SetMaterial(iface, material);
5053 5054 5055 5056 5057
    set_fpu_control_word(old_fpucw);

    return hr;
}

5058 5059 5060 5061 5062 5063 5064 5065
/*****************************************************************************
 * IDirect3DDevice7::GetMaterial
 *
 * Returns the current material
 *
 * Version 7
 *
 * Params:
5066
 *  Mat: D3DMATERIAL7 structure to write the material parameters to
5067 5068 5069 5070 5071 5072 5073
 *
 * Returns:
 *  D3D_OK on success
 *  DDERR_INVALIDPARAMS if Mat is NULL
 *  For more details, see IWineD3DDevice::GetMaterial
 *
 *****************************************************************************/
5074
static HRESULT d3d_device7_GetMaterial(IDirect3DDevice7 *iface, D3DMATERIAL7 *material)
5075
{
5076
    struct d3d_device *device = impl_from_IDirect3DDevice7(iface);
5077

5078
    TRACE("iface %p, material %p.\n", iface, material);
5079

5080
    wined3d_mutex_lock();
5081
    /* Note: D3DMATERIAL7 is compatible with struct wined3d_material. */
5082
    wined3d_device_get_material(device->wined3d_device, (struct wined3d_material *)material);
5083 5084
    wined3d_mutex_unlock();

5085
    return D3D_OK;
5086 5087
}

5088
static HRESULT WINAPI d3d_device7_GetMaterial_FPUSetup(IDirect3DDevice7 *iface, D3DMATERIAL7 *material)
5089
{
5090
    return d3d_device7_GetMaterial(iface, material);
5091 5092
}

5093
static HRESULT WINAPI d3d_device7_GetMaterial_FPUPreserve(IDirect3DDevice7 *iface, D3DMATERIAL7 *material)
5094 5095 5096 5097 5098
{
    HRESULT hr;
    WORD old_fpucw;

    old_fpucw = d3d_fpu_setup();
5099
    hr = d3d_device7_GetMaterial(iface, material);
5100 5101 5102 5103 5104
    set_fpu_control_word(old_fpucw);

    return hr;
}

5105 5106 5107 5108 5109 5110 5111 5112 5113 5114 5115 5116 5117 5118 5119 5120
/*****************************************************************************
 * IDirect3DDevice7::SetLight
 *
 * Assigns a light to a light index, but doesn't activate it yet.
 *
 * Version 7, IDirect3DLight uses this method for older versions
 *
 * Params:
 *  LightIndex: The index of the new light
 *  Light: A D3DLIGHT7 structure describing the light
 *
 * Returns:
 *  D3D_OK on success
 *  For more details, see IWineD3DDevice::SetLight
 *
 *****************************************************************************/
5121
static HRESULT d3d_device7_SetLight(IDirect3DDevice7 *iface, DWORD light_idx, D3DLIGHT7 *light)
5122
{
5123
    struct d3d_device *device = impl_from_IDirect3DDevice7(iface);
5124
    HRESULT hr;
5125

5126
    TRACE("iface %p, light_idx %u, light %p.\n", iface, light_idx, light);
5127

5128
    wined3d_mutex_lock();
5129
    /* Note: D3DLIGHT7 is compatible with struct wined3d_light. */
5130
    hr = wined3d_device_set_light(device->wined3d_device, light_idx, (struct wined3d_light *)light);
5131 5132
    wined3d_mutex_unlock();

5133 5134 5135
    return hr_ddraw_from_wined3d(hr);
}

5136
static HRESULT WINAPI d3d_device7_SetLight_FPUSetup(IDirect3DDevice7 *iface, DWORD light_idx, D3DLIGHT7 *light)
5137
{
5138
    return d3d_device7_SetLight(iface, light_idx, light);
5139 5140
}

5141
static HRESULT WINAPI d3d_device7_SetLight_FPUPreserve(IDirect3DDevice7 *iface, DWORD light_idx, D3DLIGHT7 *light)
5142 5143 5144 5145 5146
{
    HRESULT hr;
    WORD old_fpucw;

    old_fpucw = d3d_fpu_setup();
5147
    hr = d3d_device7_SetLight(iface, light_idx, light);
5148 5149 5150 5151 5152
    set_fpu_control_word(old_fpucw);

    return hr;
}

5153 5154 5155 5156 5157 5158 5159 5160 5161 5162 5163 5164 5165 5166
/*****************************************************************************
 * IDirect3DDevice7::GetLight
 *
 * Returns the light assigned to a light index
 *
 * Params:
 *  Light: Structure to write the light information to
 *
 * Returns:
 *  D3D_OK on success
 *  DDERR_INVALIDPARAMS if Light is NULL
 *  For details, see IWineD3DDevice::GetLight
 *
 *****************************************************************************/
5167
static HRESULT d3d_device7_GetLight(IDirect3DDevice7 *iface, DWORD light_idx, D3DLIGHT7 *light)
5168
{
5169
    struct d3d_device *device = impl_from_IDirect3DDevice7(iface);
5170
    HRESULT rc;
5171

5172
    TRACE("iface %p, light_idx %u, light %p.\n", iface, light_idx, light);
5173

5174
    wined3d_mutex_lock();
5175
    /* Note: D3DLIGHT7 is compatible with struct wined3d_light. */
5176
    rc =  wined3d_device_get_light(device->wined3d_device, light_idx, (struct wined3d_light *)light);
5177
    wined3d_mutex_unlock();
5178 5179 5180 5181 5182

    /* Translate the result. WineD3D returns other values than D3D7 */
    return hr_ddraw_from_wined3d(rc);
}

5183
static HRESULT WINAPI d3d_device7_GetLight_FPUSetup(IDirect3DDevice7 *iface, DWORD light_idx, D3DLIGHT7 *light)
5184
{
5185
    return d3d_device7_GetLight(iface, light_idx, light);
5186 5187
}

5188
static HRESULT WINAPI d3d_device7_GetLight_FPUPreserve(IDirect3DDevice7 *iface, DWORD light_idx, D3DLIGHT7 *light)
5189 5190 5191 5192 5193
{
    HRESULT hr;
    WORD old_fpucw;

    old_fpucw = d3d_fpu_setup();
5194
    hr = d3d_device7_GetLight(iface, light_idx, light);
5195 5196 5197 5198 5199
    set_fpu_control_word(old_fpucw);

    return hr;
}

5200 5201 5202 5203 5204 5205 5206 5207 5208 5209 5210 5211
/*****************************************************************************
 * IDirect3DDevice7::BeginStateBlock
 *
 * Begins recording to a stateblock
 *
 * Version 7
 *
 * Returns:
 *  D3D_OK on success
 *  For details see IWineD3DDevice::BeginStateBlock
 *
 *****************************************************************************/
5212
static HRESULT d3d_device7_BeginStateBlock(IDirect3DDevice7 *iface)
5213
{
5214
    struct d3d_device *device = impl_from_IDirect3DDevice7(iface);
5215
    HRESULT hr;
5216 5217

    TRACE("iface %p.\n", iface);
5218

5219
    wined3d_mutex_lock();
5220
    hr = wined3d_device_begin_stateblock(device->wined3d_device);
5221 5222
    wined3d_mutex_unlock();

5223 5224 5225
    return hr_ddraw_from_wined3d(hr);
}

5226
static HRESULT WINAPI d3d_device7_BeginStateBlock_FPUSetup(IDirect3DDevice7 *iface)
5227
{
5228
    return d3d_device7_BeginStateBlock(iface);
5229 5230
}

5231
static HRESULT WINAPI d3d_device7_BeginStateBlock_FPUPreserve(IDirect3DDevice7 *iface)
5232 5233 5234 5235 5236
{
    HRESULT hr;
    WORD old_fpucw;

    old_fpucw = d3d_fpu_setup();
5237
    hr = d3d_device7_BeginStateBlock(iface);
5238 5239 5240 5241 5242
    set_fpu_control_word(old_fpucw);

    return hr;
}

5243 5244 5245 5246
/*****************************************************************************
 * IDirect3DDevice7::EndStateBlock
 *
 * Stops recording to a state block and returns the created stateblock
5247
 * handle.
5248 5249 5250 5251 5252 5253 5254 5255 5256 5257 5258 5259
 *
 * Version 7
 *
 * Params:
 *  BlockHandle: Address to store the stateblock's handle to
 *
 * Returns:
 *  D3D_OK on success
 *  DDERR_INVALIDPARAMS if BlockHandle is NULL
 *  See IWineD3DDevice::EndStateBlock for more details
 *
 *****************************************************************************/
5260
static HRESULT d3d_device7_EndStateBlock(IDirect3DDevice7 *iface, DWORD *stateblock)
5261
{
5262
    struct d3d_device *device = impl_from_IDirect3DDevice7(iface);
5263
    struct wined3d_stateblock *wined3d_sb;
5264
    HRESULT hr;
5265 5266
    DWORD h;

5267
    TRACE("iface %p, stateblock %p.\n", iface, stateblock);
5268

5269
    if (!stateblock)
5270 5271
        return DDERR_INVALIDPARAMS;

5272
    wined3d_mutex_lock();
5273

5274
    hr = wined3d_device_end_stateblock(device->wined3d_device, &wined3d_sb);
5275 5276 5277
    if (FAILED(hr))
    {
        WARN("Failed to end stateblock, hr %#x.\n", hr);
5278
        wined3d_mutex_unlock();
5279
        *stateblock = 0;
5280 5281 5282
        return hr_ddraw_from_wined3d(hr);
    }

5283
    h = ddraw_allocate_handle(&device->handle_table, wined3d_sb, DDRAW_HANDLE_STATEBLOCK);
5284
    if (h == DDRAW_INVALID_HANDLE)
5285
    {
5286
        ERR("Failed to allocate a stateblock handle.\n");
5287
        wined3d_stateblock_decref(wined3d_sb);
5288
        wined3d_mutex_unlock();
5289
        *stateblock = 0;
5290 5291
        return DDERR_OUTOFMEMORY;
    }
5292

5293
    wined3d_mutex_unlock();
5294
    *stateblock = h + 1;
5295

5296 5297 5298
    return hr_ddraw_from_wined3d(hr);
}

5299
static HRESULT WINAPI d3d_device7_EndStateBlock_FPUSetup(IDirect3DDevice7 *iface, DWORD *stateblock)
5300
{
5301
    return d3d_device7_EndStateBlock(iface, stateblock);
5302 5303
}

5304
static HRESULT WINAPI d3d_device7_EndStateBlock_FPUPreserve(IDirect3DDevice7 *iface, DWORD *stateblock)
5305 5306 5307 5308 5309
{
    HRESULT hr;
    WORD old_fpucw;

    old_fpucw = d3d_fpu_setup();
5310
    hr = d3d_device7_EndStateBlock(iface, stateblock);
5311 5312 5313 5314 5315
    set_fpu_control_word(old_fpucw);

    return hr;
}

5316 5317 5318 5319 5320 5321 5322 5323 5324 5325 5326 5327 5328 5329 5330 5331 5332
/*****************************************************************************
 * IDirect3DDevice7::PreLoad
 *
 * Allows the app to signal that a texture will be used soon, to allow
 * the Direct3DDevice to load it to the video card in the meantime.
 *
 * Version 7
 *
 * Params:
 *  Texture: The texture to preload
 *
 * Returns:
 *  D3D_OK on success
 *  DDERR_INVALIDPARAMS if Texture is NULL
 *  See IWineD3DSurface::PreLoad for details
 *
 *****************************************************************************/
5333
static HRESULT d3d_device7_PreLoad(IDirect3DDevice7 *iface, IDirectDrawSurface7 *texture)
5334
{
5335
    struct ddraw_surface *surface = unsafe_impl_from_IDirectDrawSurface7(texture);
5336

5337
    TRACE("iface %p, texture %p.\n", iface, texture);
5338

5339
    if (!texture)
5340 5341
        return DDERR_INVALIDPARAMS;

5342
    wined3d_mutex_lock();
5343
    wined3d_surface_preload(surface->wined3d_surface);
5344 5345
    wined3d_mutex_unlock();

5346 5347 5348
    return D3D_OK;
}

5349
static HRESULT WINAPI d3d_device7_PreLoad_FPUSetup(IDirect3DDevice7 *iface, IDirectDrawSurface7 *texture)
5350
{
5351
    return d3d_device7_PreLoad(iface, texture);
5352 5353
}

5354
static HRESULT WINAPI d3d_device7_PreLoad_FPUPreserve(IDirect3DDevice7 *iface, IDirectDrawSurface7 *texture)
5355 5356 5357 5358 5359
{
    HRESULT hr;
    WORD old_fpucw;

    old_fpucw = d3d_fpu_setup();
5360
    hr = d3d_device7_PreLoad(iface, texture);
5361 5362 5363 5364 5365
    set_fpu_control_word(old_fpucw);

    return hr;
}

5366 5367 5368 5369 5370 5371 5372 5373 5374 5375 5376 5377 5378
/*****************************************************************************
 * IDirect3DDevice7::ApplyStateBlock
 *
 * Activates the state stored in a state block handle.
 *
 * Params:
 *  BlockHandle: The stateblock handle to activate
 *
 * Returns:
 *  D3D_OK on success
 *  D3DERR_INVALIDSTATEBLOCK if BlockHandle is NULL
 *
 *****************************************************************************/
5379
static HRESULT d3d_device7_ApplyStateBlock(IDirect3DDevice7 *iface, DWORD stateblock)
5380
{
5381
    struct d3d_device *device = impl_from_IDirect3DDevice7(iface);
5382
    struct wined3d_stateblock *wined3d_sb;
5383

5384
    TRACE("iface %p, stateblock %#x.\n", iface, stateblock);
5385

5386
    wined3d_mutex_lock();
5387
    wined3d_sb = ddraw_get_object(&device->handle_table, stateblock - 1, DDRAW_HANDLE_STATEBLOCK);
5388
    if (!wined3d_sb)
5389
    {
5390
        WARN("Invalid stateblock handle.\n");
5391
        wined3d_mutex_unlock();
5392
        return D3DERR_INVALIDSTATEBLOCK;
5393
    }
5394

5395
    wined3d_stateblock_apply(wined3d_sb);
5396
    wined3d_mutex_unlock();
5397

5398
    return D3D_OK;
5399 5400
}

5401
static HRESULT WINAPI d3d_device7_ApplyStateBlock_FPUSetup(IDirect3DDevice7 *iface, DWORD stateblock)
5402
{
5403
    return d3d_device7_ApplyStateBlock(iface, stateblock);
5404 5405
}

5406
static HRESULT WINAPI d3d_device7_ApplyStateBlock_FPUPreserve(IDirect3DDevice7 *iface, DWORD stateblock)
5407 5408 5409 5410 5411
{
    HRESULT hr;
    WORD old_fpucw;

    old_fpucw = d3d_fpu_setup();
5412
    hr = d3d_device7_ApplyStateBlock(iface, stateblock);
5413 5414 5415 5416 5417
    set_fpu_control_word(old_fpucw);

    return hr;
}

5418 5419 5420 5421 5422 5423 5424 5425 5426 5427 5428 5429 5430 5431 5432 5433
/*****************************************************************************
 * IDirect3DDevice7::CaptureStateBlock
 *
 * Updates a stateblock's values to the values currently set for the device
 *
 * Version 7
 *
 * Params:
 *  BlockHandle: Stateblock to update
 *
 * Returns:
 *  D3D_OK on success
 *  D3DERR_INVALIDSTATEBLOCK if BlockHandle is NULL
 *  See IWineD3DDevice::CaptureStateBlock for more details
 *
 *****************************************************************************/
5434
static HRESULT d3d_device7_CaptureStateBlock(IDirect3DDevice7 *iface, DWORD stateblock)
5435
{
5436
    struct d3d_device *device = impl_from_IDirect3DDevice7(iface);
5437
    struct wined3d_stateblock *wined3d_sb;
5438

5439
    TRACE("iface %p, stateblock %#x.\n", iface, stateblock);
5440

5441
    wined3d_mutex_lock();
5442
    wined3d_sb = ddraw_get_object(&device->handle_table, stateblock - 1, DDRAW_HANDLE_STATEBLOCK);
5443
    if (!wined3d_sb)
5444
    {
5445
        WARN("Invalid stateblock handle.\n");
5446
        wined3d_mutex_unlock();
5447 5448
        return D3DERR_INVALIDSTATEBLOCK;
    }
5449

5450
    wined3d_stateblock_capture(wined3d_sb);
5451 5452
    wined3d_mutex_unlock();

5453
    return D3D_OK;
5454 5455
}

5456
static HRESULT WINAPI d3d_device7_CaptureStateBlock_FPUSetup(IDirect3DDevice7 *iface, DWORD stateblock)
5457
{
5458
    return d3d_device7_CaptureStateBlock(iface, stateblock);
5459 5460
}

5461
static HRESULT WINAPI d3d_device7_CaptureStateBlock_FPUPreserve(IDirect3DDevice7 *iface, DWORD stateblock)
5462 5463 5464 5465 5466
{
    HRESULT hr;
    WORD old_fpucw;

    old_fpucw = d3d_fpu_setup();
5467
    hr = d3d_device7_CaptureStateBlock(iface, stateblock);
5468 5469 5470 5471 5472
    set_fpu_control_word(old_fpucw);

    return hr;
}

5473 5474 5475 5476 5477 5478 5479 5480 5481 5482 5483 5484 5485 5486 5487
/*****************************************************************************
 * IDirect3DDevice7::DeleteStateBlock
 *
 * Deletes a stateblock handle. This means releasing the WineD3DStateBlock
 *
 * Version 7
 *
 * Params:
 *  BlockHandle: Stateblock handle to delete
 *
 * Returns:
 *  D3D_OK on success
 *  D3DERR_INVALIDSTATEBLOCK if BlockHandle is 0
 *
 *****************************************************************************/
5488
static HRESULT d3d_device7_DeleteStateBlock(IDirect3DDevice7 *iface, DWORD stateblock)
5489
{
5490
    struct d3d_device *device = impl_from_IDirect3DDevice7(iface);
5491
    struct wined3d_stateblock *wined3d_sb;
5492
    ULONG ref;
5493

5494
    TRACE("iface %p, stateblock %#x.\n", iface, stateblock);
5495

5496
    wined3d_mutex_lock();
5497

5498
    wined3d_sb = ddraw_free_handle(&device->handle_table, stateblock - 1, DDRAW_HANDLE_STATEBLOCK);
5499
    if (!wined3d_sb)
5500
    {
5501
        WARN("Invalid stateblock handle.\n");
5502
        wined3d_mutex_unlock();
5503 5504
        return D3DERR_INVALIDSTATEBLOCK;
    }
5505

5506
    if ((ref = wined3d_stateblock_decref(wined3d_sb)))
5507
    {
5508
        ERR("Something is still holding stateblock %p (refcount %u).\n", wined3d_sb, ref);
5509
    }
5510

5511 5512
    wined3d_mutex_unlock();

5513 5514 5515
    return D3D_OK;
}

5516
static HRESULT WINAPI d3d_device7_DeleteStateBlock_FPUSetup(IDirect3DDevice7 *iface, DWORD stateblock)
5517
{
5518
    return d3d_device7_DeleteStateBlock(iface, stateblock);
5519 5520
}

5521
static HRESULT WINAPI d3d_device7_DeleteStateBlock_FPUPreserve(IDirect3DDevice7 *iface, DWORD stateblock)
5522 5523 5524 5525 5526
{
    HRESULT hr;
    WORD old_fpucw;

    old_fpucw = d3d_fpu_setup();
5527
    hr = d3d_device7_DeleteStateBlock(iface, stateblock);
5528 5529 5530 5531 5532
    set_fpu_control_word(old_fpucw);

    return hr;
}

5533 5534 5535 5536 5537 5538 5539 5540 5541 5542 5543 5544 5545 5546 5547 5548
/*****************************************************************************
 * IDirect3DDevice7::CreateStateBlock
 *
 * Creates a new state block handle.
 *
 * Version 7
 *
 * Params:
 *  Type: The state block type
 *  BlockHandle: Address to write the created handle to
 *
 * Returns:
 *   D3D_OK on success
 *   DDERR_INVALIDPARAMS if BlockHandle is NULL
 *
 *****************************************************************************/
5549 5550
static HRESULT d3d_device7_CreateStateBlock(IDirect3DDevice7 *iface,
        D3DSTATEBLOCKTYPE type, DWORD *stateblock)
5551
{
5552
    struct d3d_device *device = impl_from_IDirect3DDevice7(iface);
5553
    struct wined3d_stateblock *wined3d_sb;
5554
    HRESULT hr;
5555 5556
    DWORD h;

5557
    TRACE("iface %p, type %#x, stateblock %p.\n", iface, type, stateblock);
5558

5559
    if (!stateblock)
5560
        return DDERR_INVALIDPARAMS;
5561 5562 5563 5564 5565

    if (type != D3DSBT_ALL
            && type != D3DSBT_PIXELSTATE
            && type != D3DSBT_VERTEXSTATE)
    {
5566 5567 5568
        WARN("Unexpected stateblock type, returning DDERR_INVALIDPARAMS\n");
        return DDERR_INVALIDPARAMS;
    }
5569

5570
    wined3d_mutex_lock();
5571 5572

    /* The D3DSTATEBLOCKTYPE enum is fine here. */
5573
    hr = wined3d_stateblock_create(device->wined3d_device, type, &wined3d_sb);
5574
    if (FAILED(hr))
5575
    {
5576
        WARN("Failed to create stateblock, hr %#x.\n", hr);
5577
        wined3d_mutex_unlock();
5578 5579 5580
        return hr_ddraw_from_wined3d(hr);
    }

5581
    h = ddraw_allocate_handle(&device->handle_table, wined3d_sb, DDRAW_HANDLE_STATEBLOCK);
5582 5583 5584
    if (h == DDRAW_INVALID_HANDLE)
    {
        ERR("Failed to allocate stateblock handle.\n");
5585
        wined3d_stateblock_decref(wined3d_sb);
5586
        wined3d_mutex_unlock();
5587 5588
        return DDERR_OUTOFMEMORY;
    }
5589

5590
    *stateblock = h + 1;
5591
    wined3d_mutex_unlock();
5592

5593 5594 5595
    return hr_ddraw_from_wined3d(hr);
}

5596 5597
static HRESULT WINAPI d3d_device7_CreateStateBlock_FPUSetup(IDirect3DDevice7 *iface,
        D3DSTATEBLOCKTYPE type, DWORD *stateblock)
5598
{
5599
    return d3d_device7_CreateStateBlock(iface, type, stateblock);
5600 5601
}

5602 5603
static HRESULT WINAPI d3d_device7_CreateStateBlock_FPUPreserve(IDirect3DDevice7 *iface,
        D3DSTATEBLOCKTYPE type, DWORD *stateblock)
5604 5605 5606 5607 5608
{
    HRESULT hr;
    WORD old_fpucw;

    old_fpucw = d3d_fpu_setup();
5609
    hr = d3d_device7_CreateStateBlock(iface, type, stateblock);
5610 5611 5612 5613 5614
    set_fpu_control_word(old_fpucw);

    return hr;
}

5615
static BOOL is_mip_level_subset(struct ddraw_surface *dest, struct ddraw_surface *src)
5616
{
5617
    struct ddraw_surface *src_level, *dest_level;
5618 5619 5620 5621 5622 5623 5624 5625 5626 5627 5628 5629 5630 5631 5632 5633 5634 5635 5636 5637 5638 5639
    IDirectDrawSurface7 *temp;
    DDSURFACEDESC2 ddsd;
    BOOL levelFound; /* at least one suitable sublevel in dest found */

    /* To satisfy "destination is mip level subset of source" criteria (regular texture counts as 1 level),
     * 1) there must be at least one mip level in destination that matched dimensions of some mip level in source and
     * 2) there must be no destination levels that don't match any levels in source. Otherwise it's INVALIDPARAMS.
     */
    levelFound = FALSE;

    src_level = src;
    dest_level = dest;

    for (;src_level && dest_level;)
    {
        if (src_level->surface_desc.dwWidth == dest_level->surface_desc.dwWidth &&
            src_level->surface_desc.dwHeight == dest_level->surface_desc.dwHeight)
        {
            levelFound = TRUE;

            ddsd.ddsCaps.dwCaps = DDSCAPS_TEXTURE;
            ddsd.ddsCaps.dwCaps2 = DDSCAPS2_MIPMAPSUBLEVEL;
5640
            IDirectDrawSurface7_GetAttachedSurface(&dest_level->IDirectDrawSurface7_iface, &ddsd.ddsCaps, &temp);
5641

5642
            if (dest_level != dest) IDirectDrawSurface7_Release(&dest_level->IDirectDrawSurface7_iface);
5643

5644
            dest_level = unsafe_impl_from_IDirectDrawSurface7(temp);
5645 5646 5647 5648
        }

        ddsd.ddsCaps.dwCaps = DDSCAPS_TEXTURE;
        ddsd.ddsCaps.dwCaps2 = DDSCAPS2_MIPMAPSUBLEVEL;
5649
        IDirectDrawSurface7_GetAttachedSurface(&src_level->IDirectDrawSurface7_iface, &ddsd.ddsCaps, &temp);
5650

5651
        if (src_level != src) IDirectDrawSurface7_Release(&src_level->IDirectDrawSurface7_iface);
5652

5653
        src_level = unsafe_impl_from_IDirectDrawSurface7(temp);
5654 5655
    }

5656 5657
    if (src_level && src_level != src) IDirectDrawSurface7_Release(&src_level->IDirectDrawSurface7_iface);
    if (dest_level && dest_level != dest) IDirectDrawSurface7_Release(&dest_level->IDirectDrawSurface7_iface);
5658 5659 5660 5661

    return !dest_level && levelFound;
}

5662
static void copy_mipmap_chain(struct d3d_device *device, struct ddraw_surface *dest,
5663
        struct ddraw_surface *src, const POINT *DestPoint, const RECT *SrcRect)
5664
{
5665
    struct ddraw_surface *src_level, *dest_level;
5666 5667 5668
    IDirectDrawSurface7 *temp;
    DDSURFACEDESC2 ddsd;
    POINT point;
5669
    RECT src_rect;
5670 5671 5672 5673
    HRESULT hr;
    IDirectDrawPalette *pal = NULL, *pal_src = NULL;
    DWORD ckeyflag;
    DDCOLORKEY ddckey;
5674 5675

    /* Copy palette, if possible. */
5676 5677
    IDirectDrawSurface7_GetPalette(&src->IDirectDrawSurface7_iface, &pal_src);
    IDirectDrawSurface7_GetPalette(&dest->IDirectDrawSurface7_iface, &pal);
5678 5679 5680 5681 5682 5683 5684 5685 5686 5687 5688 5689 5690 5691 5692

    if (pal_src != NULL && pal != NULL)
    {
        PALETTEENTRY palent[256];

        IDirectDrawPalette_GetEntries(pal_src, 0, 0, 256, palent);
        IDirectDrawPalette_SetEntries(pal, 0, 0, 256, palent);
    }

    if (pal) IDirectDrawPalette_Release(pal);
    if (pal_src) IDirectDrawPalette_Release(pal_src);

    /* Copy colorkeys, if present. */
    for (ckeyflag = DDCKEY_DESTBLT; ckeyflag <= DDCKEY_SRCOVERLAY; ckeyflag <<= 1)
    {
5693
        hr = IDirectDrawSurface7_GetColorKey(&src->IDirectDrawSurface7_iface, ckeyflag, &ddckey);
5694 5695 5696

        if (SUCCEEDED(hr))
        {
5697
            IDirectDrawSurface7_SetColorKey(&dest->IDirectDrawSurface7_iface, ckeyflag, &ddckey);
5698 5699
        }
    }
5700 5701 5702 5703 5704

    src_level = src;
    dest_level = dest;

    point = *DestPoint;
5705
    src_rect = *SrcRect;
5706 5707 5708 5709 5710 5711

    for (;src_level && dest_level;)
    {
        if (src_level->surface_desc.dwWidth == dest_level->surface_desc.dwWidth &&
            src_level->surface_desc.dwHeight == dest_level->surface_desc.dwHeight)
        {
5712 5713 5714 5715 5716
            UINT src_w = src_rect.right - src_rect.left;
            UINT src_h = src_rect.bottom - src_rect.top;
            RECT dst_rect = {point.x, point.y, point.x + src_w, point.y + src_h};

            if (FAILED(hr = wined3d_surface_blt(dest_level->wined3d_surface, &dst_rect,
5717
                    src_level->wined3d_surface, &src_rect, 0, NULL, WINED3D_TEXF_POINT)))
5718
                ERR("Blit failed, hr %#x.\n", hr);
5719 5720 5721

            ddsd.ddsCaps.dwCaps = DDSCAPS_TEXTURE;
            ddsd.ddsCaps.dwCaps2 = DDSCAPS2_MIPMAPSUBLEVEL;
5722
            IDirectDrawSurface7_GetAttachedSurface(&dest_level->IDirectDrawSurface7_iface, &ddsd.ddsCaps, &temp);
5723

5724
            if (dest_level != dest) IDirectDrawSurface7_Release(&dest_level->IDirectDrawSurface7_iface);
5725

5726
            dest_level = unsafe_impl_from_IDirectDrawSurface7(temp);
5727 5728 5729 5730
        }

        ddsd.ddsCaps.dwCaps = DDSCAPS_TEXTURE;
        ddsd.ddsCaps.dwCaps2 = DDSCAPS2_MIPMAPSUBLEVEL;
5731
        IDirectDrawSurface7_GetAttachedSurface(&src_level->IDirectDrawSurface7_iface, &ddsd.ddsCaps, &temp);
5732

5733
        if (src_level != src) IDirectDrawSurface7_Release(&src_level->IDirectDrawSurface7_iface);
5734

5735
        src_level = unsafe_impl_from_IDirectDrawSurface7(temp);
5736 5737 5738 5739

        point.x /= 2;
        point.y /= 2;

5740 5741 5742 5743
        src_rect.top /= 2;
        src_rect.left /= 2;
        src_rect.right = (src_rect.right + 1) / 2;
        src_rect.bottom = (src_rect.bottom + 1) / 2;
5744 5745
    }

5746 5747
    if (src_level && src_level != src) IDirectDrawSurface7_Release(&src_level->IDirectDrawSurface7_iface);
    if (dest_level && dest_level != dest) IDirectDrawSurface7_Release(&dest_level->IDirectDrawSurface7_iface);
5748 5749
}

5750 5751 5752
/*****************************************************************************
 * IDirect3DDevice7::Load
 *
5753
 * Loads a rectangular area from the source into the destination texture.
5754 5755 5756 5757 5758 5759 5760 5761 5762 5763
 * It can also copy the source to the faces of a cubic environment map
 *
 * Version 7
 *
 * Params:
 *  DestTex: Destination texture
 *  DestPoint: Point in the destination where the source image should be
 *             written to
 *  SrcTex: Source texture
 *  SrcRect: Source rectangle
5764 5765 5766
 *  Flags: Cubemap faces to load (DDSCAPS2_CUBEMAP_ALLFACES, DDSCAPS2_CUBEMAP_POSITIVEX,
 *          DDSCAPS2_CUBEMAP_NEGATIVEX, DDSCAPS2_CUBEMAP_POSITIVEY, DDSCAPS2_CUBEMAP_NEGATIVEY,
 *          DDSCAPS2_CUBEMAP_POSITIVEZ, DDSCAPS2_CUBEMAP_NEGATIVEZ)
5767 5768 5769
 *
 * Returns:
 *  D3D_OK on success
5770 5771
 *  DDERR_INVALIDPARAMS if DestTex or SrcTex are NULL, broken coordinates or anything unexpected.
 *
5772 5773
 *
 *****************************************************************************/
5774 5775 5776 5777 5778 5779
static HRESULT d3d_device7_Load(IDirect3DDevice7 *iface, IDirectDrawSurface7 *dst_texture, POINT *dst_pos,
        IDirectDrawSurface7 *src_texture, RECT *src_rect, DWORD flags)
{
    struct d3d_device *device = impl_from_IDirect3DDevice7(iface);
    struct ddraw_surface *dest = unsafe_impl_from_IDirectDrawSurface7(dst_texture);
    struct ddraw_surface *src = unsafe_impl_from_IDirectDrawSurface7(src_texture);
5780 5781
    POINT destpoint;
    RECT srcrect;
5782 5783

    TRACE("iface %p, dst_texture %p, dst_pos %s, src_texture %p, src_rect %s, flags %#x.\n",
5784
            iface, dst_texture, wine_dbgstr_point(dst_pos), src_texture, wine_dbgstr_rect(src_rect), flags);
5785 5786 5787 5788

    if( (!src) || (!dest) )
        return DDERR_INVALIDPARAMS;

5789
    wined3d_mutex_lock();
5790

5791
    if (!src_rect)
5792 5793 5794 5795 5796 5797
    {
        srcrect.left = srcrect.top = 0;
        srcrect.right = src->surface_desc.dwWidth;
        srcrect.bottom = src->surface_desc.dwHeight;
    }
    else
5798 5799 5800
        srcrect = *src_rect;

    if (!dst_pos)
5801
        destpoint.x = destpoint.y = 0;
5802 5803 5804 5805
    else
        destpoint = *dst_pos;

    /* Check bad dimensions. dst_pos is validated against src, not dest, because
5806 5807 5808 5809 5810 5811 5812 5813 5814 5815 5816 5817
     * destination can be a subset of mip levels, in which case actual coordinates used
     * for it may be divided. If any dimension of dest is larger than source, it can't be
     * mip level subset, so an error can be returned early.
     */
    if (srcrect.left >= srcrect.right || srcrect.top >= srcrect.bottom ||
        srcrect.right > src->surface_desc.dwWidth ||
        srcrect.bottom > src->surface_desc.dwHeight ||
        destpoint.x + srcrect.right - srcrect.left > src->surface_desc.dwWidth ||
        destpoint.y + srcrect.bottom - srcrect.top > src->surface_desc.dwHeight ||
        dest->surface_desc.dwWidth > src->surface_desc.dwWidth ||
        dest->surface_desc.dwHeight > src->surface_desc.dwHeight)
    {
5818
        wined3d_mutex_unlock();
5819 5820 5821 5822 5823 5824 5825
        return DDERR_INVALIDPARAMS;
    }

    /* Must be top level surfaces. */
    if (src->surface_desc.ddsCaps.dwCaps2 & DDSCAPS2_MIPMAPSUBLEVEL ||
        dest->surface_desc.ddsCaps.dwCaps2 & DDSCAPS2_MIPMAPSUBLEVEL)
    {
5826
        wined3d_mutex_unlock();
5827 5828 5829 5830 5831
        return DDERR_INVALIDPARAMS;
    }

    if (src->surface_desc.ddsCaps.dwCaps2 & DDSCAPS2_CUBEMAP)
    {
5832
        struct ddraw_surface *src_face, *dest_face;
5833 5834 5835 5836 5837 5838 5839
        DWORD src_face_flag, dest_face_flag;
        IDirectDrawSurface7 *temp;
        DDSURFACEDESC2 ddsd;
        int i;

        if (!(dest->surface_desc.ddsCaps.dwCaps2 & DDSCAPS2_CUBEMAP))
        {
5840
            wined3d_mutex_unlock();
5841 5842 5843 5844 5845 5846 5847 5848 5849 5850 5851 5852 5853 5854 5855 5856 5857 5858 5859 5860 5861 5862
            return DDERR_INVALIDPARAMS;
        }

        /* Iterate through cube faces 2 times. First time is just to check INVALIDPARAMS conditions, second
         * time it's actual surface loading. */
        for (i = 0; i < 2; i++)
        {
            dest_face = dest;
            src_face = src;

            for (;dest_face && src_face;)
            {
                src_face_flag = src_face->surface_desc.ddsCaps.dwCaps2 & DDSCAPS2_CUBEMAP_ALLFACES;
                dest_face_flag = dest_face->surface_desc.ddsCaps.dwCaps2 & DDSCAPS2_CUBEMAP_ALLFACES;

                if (src_face_flag == dest_face_flag)
                {
                    if (i == 0)
                    {
                        /* Destination mip levels must be subset of source mip levels. */
                        if (!is_mip_level_subset(dest_face, src_face))
                        {
5863
                            wined3d_mutex_unlock();
5864 5865 5866
                            return DDERR_INVALIDPARAMS;
                        }
                    }
5867
                    else if (flags & dest_face_flag)
5868
                    {
5869
                        copy_mipmap_chain(device, dest_face, src_face, &destpoint, &srcrect);
5870 5871 5872 5873 5874 5875
                    }

                    if (src_face_flag < DDSCAPS2_CUBEMAP_NEGATIVEZ)
                    {
                        ddsd.ddsCaps.dwCaps = DDSCAPS_TEXTURE;
                        ddsd.ddsCaps.dwCaps2 = DDSCAPS2_CUBEMAP | (src_face_flag << 1);
5876
                        IDirectDrawSurface7_GetAttachedSurface(&src->IDirectDrawSurface7_iface, &ddsd.ddsCaps, &temp);
5877

5878
                        if (src_face != src) IDirectDrawSurface7_Release(&src_face->IDirectDrawSurface7_iface);
5879

5880
                        src_face = unsafe_impl_from_IDirectDrawSurface7(temp);
5881 5882 5883
                    }
                    else
                    {
5884
                        if (src_face != src) IDirectDrawSurface7_Release(&src_face->IDirectDrawSurface7_iface);
5885 5886 5887 5888 5889 5890 5891 5892 5893

                        src_face = NULL;
                    }
                }

                if (dest_face_flag < DDSCAPS2_CUBEMAP_NEGATIVEZ)
                {
                    ddsd.ddsCaps.dwCaps = DDSCAPS_TEXTURE;
                    ddsd.ddsCaps.dwCaps2 = DDSCAPS2_CUBEMAP | (dest_face_flag << 1);
5894
                    IDirectDrawSurface7_GetAttachedSurface(&dest->IDirectDrawSurface7_iface, &ddsd.ddsCaps, &temp);
5895

5896
                    if (dest_face != dest) IDirectDrawSurface7_Release(&dest_face->IDirectDrawSurface7_iface);
5897

5898
                    dest_face = unsafe_impl_from_IDirectDrawSurface7(temp);
5899 5900 5901
                }
                else
                {
5902
                    if (dest_face != dest) IDirectDrawSurface7_Release(&dest_face->IDirectDrawSurface7_iface);
5903 5904 5905 5906 5907 5908 5909 5910 5911 5912

                    dest_face = NULL;
                }
            }

            if (i == 0)
            {
                /* Native returns error if src faces are not subset of dest faces. */
                if (src_face)
                {
5913
                    wined3d_mutex_unlock();
5914 5915 5916 5917 5918
                    return DDERR_INVALIDPARAMS;
                }
            }
        }

5919
        wined3d_mutex_unlock();
5920 5921 5922 5923
        return D3D_OK;
    }
    else if (dest->surface_desc.ddsCaps.dwCaps2 & DDSCAPS2_CUBEMAP)
    {
5924
        wined3d_mutex_unlock();
5925 5926 5927 5928 5929 5930 5931 5932
        return DDERR_INVALIDPARAMS;
    }

    /* Handle non cube map textures. */

    /* Destination mip levels must be subset of source mip levels. */
    if (!is_mip_level_subset(dest, src))
    {
5933
        wined3d_mutex_unlock();
5934 5935 5936
        return DDERR_INVALIDPARAMS;
    }

5937
    copy_mipmap_chain(device, dest, src, &destpoint, &srcrect);
5938

5939 5940
    wined3d_mutex_unlock();

5941 5942 5943
    return D3D_OK;
}

5944 5945
static HRESULT WINAPI d3d_device7_Load_FPUSetup(IDirect3DDevice7 *iface, IDirectDrawSurface7 *dst_texture,
        POINT *dst_pos, IDirectDrawSurface7 *src_texture, RECT *src_rect, DWORD flags)
5946
{
5947
    return d3d_device7_Load(iface, dst_texture, dst_pos, src_texture, src_rect, flags);
5948 5949
}

5950 5951
static HRESULT WINAPI d3d_device7_Load_FPUPreserve(IDirect3DDevice7 *iface, IDirectDrawSurface7 *dst_texture,
        POINT *dst_pos, IDirectDrawSurface7 *src_texture, RECT *src_rect, DWORD flags)
5952 5953 5954 5955 5956
{
    HRESULT hr;
    WORD old_fpucw;

    old_fpucw = d3d_fpu_setup();
5957
    hr = d3d_device7_Load(iface, dst_texture, dst_pos, src_texture, src_rect, flags);
5958 5959 5960 5961 5962
    set_fpu_control_word(old_fpucw);

    return hr;
}

5963 5964 5965 5966 5967 5968 5969 5970 5971 5972 5973 5974 5975 5976 5977 5978
/*****************************************************************************
 * IDirect3DDevice7::LightEnable
 *
 * Enables or disables a light
 *
 * Version 7, IDirect3DLight uses this method too.
 *
 * Params:
 *  LightIndex: The index of the light to enable / disable
 *  Enable: Enable or disable the light
 *
 * Returns:
 *  D3D_OK on success
 *  For more details, see IWineD3DDevice::SetLightEnable
 *
 *****************************************************************************/
5979
static HRESULT d3d_device7_LightEnable(IDirect3DDevice7 *iface, DWORD light_idx, BOOL enabled)
5980
{
5981
    struct d3d_device *device = impl_from_IDirect3DDevice7(iface);
5982
    HRESULT hr;
5983

5984
    TRACE("iface %p, light_idx %u, enabled %#x.\n", iface, light_idx, enabled);
5985

5986
    wined3d_mutex_lock();
5987
    hr = wined3d_device_set_light_enable(device->wined3d_device, light_idx, enabled);
5988 5989
    wined3d_mutex_unlock();

5990 5991 5992
    return hr_ddraw_from_wined3d(hr);
}

5993
static HRESULT WINAPI d3d_device7_LightEnable_FPUSetup(IDirect3DDevice7 *iface, DWORD light_idx, BOOL enabled)
5994
{
5995
    return d3d_device7_LightEnable(iface, light_idx, enabled);
5996 5997
}

5998
static HRESULT WINAPI d3d_device7_LightEnable_FPUPreserve(IDirect3DDevice7 *iface, DWORD light_idx, BOOL enabled)
5999 6000 6001 6002 6003
{
    HRESULT hr;
    WORD old_fpucw;

    old_fpucw = d3d_fpu_setup();
6004
    hr = d3d_device7_LightEnable(iface, light_idx, enabled);
6005 6006 6007 6008 6009
    set_fpu_control_word(old_fpucw);

    return hr;
}

6010 6011 6012
/*****************************************************************************
 * IDirect3DDevice7::GetLightEnable
 *
6013
 * Retrieves if the light with the given index is enabled or not
6014 6015 6016 6017 6018 6019 6020 6021 6022 6023 6024 6025 6026
 *
 * Version 7
 *
 * Params:
 *  LightIndex: Index of desired light
 *  Enable: Pointer to a BOOL which contains the result
 *
 * Returns:
 *  D3D_OK on success
 *  DDERR_INVALIDPARAMS if Enable is NULL
 *  See IWineD3DDevice::GetLightEnable for more details
 *
 *****************************************************************************/
6027
static HRESULT d3d_device7_GetLightEnable(IDirect3DDevice7 *iface, DWORD light_idx, BOOL *enabled)
6028
{
6029
    struct d3d_device *device = impl_from_IDirect3DDevice7(iface);
6030
    HRESULT hr;
6031

6032
    TRACE("iface %p, light_idx %u, enabled %p.\n", iface, light_idx, enabled);
6033

6034
    if (!enabled)
6035 6036
        return DDERR_INVALIDPARAMS;

6037
    wined3d_mutex_lock();
6038
    hr = wined3d_device_get_light_enable(device->wined3d_device, light_idx, enabled);
6039 6040
    wined3d_mutex_unlock();

6041 6042 6043
    return hr_ddraw_from_wined3d(hr);
}

6044
static HRESULT WINAPI d3d_device7_GetLightEnable_FPUSetup(IDirect3DDevice7 *iface, DWORD light_idx, BOOL *enabled)
6045
{
6046
    return d3d_device7_GetLightEnable(iface, light_idx, enabled);
6047 6048
}

6049
static HRESULT WINAPI d3d_device7_GetLightEnable_FPUPreserve(IDirect3DDevice7 *iface, DWORD light_idx, BOOL *enabled)
6050 6051 6052 6053 6054
{
    HRESULT hr;
    WORD old_fpucw;

    old_fpucw = d3d_fpu_setup();
6055
    hr = d3d_device7_GetLightEnable(iface, light_idx, enabled);
6056 6057 6058 6059 6060
    set_fpu_control_word(old_fpucw);

    return hr;
}

6061 6062 6063 6064 6065 6066 6067 6068 6069 6070 6071 6072 6073 6074 6075 6076 6077
/*****************************************************************************
 * IDirect3DDevice7::SetClipPlane
 *
 * Sets custom clipping plane
 *
 * Version 7
 *
 * Params:
 *  Index: The index of the clipping plane
 *  PlaneEquation: An equation defining the clipping plane
 *
 * Returns:
 *  D3D_OK on success
 *  DDERR_INVALIDPARAMS if PlaneEquation is NULL
 *  See IWineD3DDevice::SetClipPlane for more details
 *
 *****************************************************************************/
6078
static HRESULT d3d_device7_SetClipPlane(IDirect3DDevice7 *iface, DWORD idx, D3DVALUE *plane)
6079
{
6080
    struct d3d_device *device = impl_from_IDirect3DDevice7(iface);
6081
    HRESULT hr;
6082

6083
    TRACE("iface %p, idx %u, plane %p.\n", iface, idx, plane);
6084

6085
    if (!plane)
6086 6087
        return DDERR_INVALIDPARAMS;

6088
    wined3d_mutex_lock();
6089
    hr = wined3d_device_set_clip_plane(device->wined3d_device, idx, (struct wined3d_vec4 *)plane);
6090 6091
    wined3d_mutex_unlock();

6092
    return hr;
6093 6094
}

6095
static HRESULT WINAPI d3d_device7_SetClipPlane_FPUSetup(IDirect3DDevice7 *iface, DWORD idx, D3DVALUE *plane)
6096
{
6097
    return d3d_device7_SetClipPlane(iface, idx, plane);
6098 6099
}

6100
static HRESULT WINAPI d3d_device7_SetClipPlane_FPUPreserve(IDirect3DDevice7 *iface, DWORD idx, D3DVALUE *plane)
6101 6102 6103 6104 6105
{
    HRESULT hr;
    WORD old_fpucw;

    old_fpucw = d3d_fpu_setup();
6106
    hr = d3d_device7_SetClipPlane(iface, idx, plane);
6107 6108 6109 6110 6111
    set_fpu_control_word(old_fpucw);

    return hr;
}

6112 6113 6114 6115 6116 6117 6118 6119 6120 6121 6122 6123 6124 6125 6126
/*****************************************************************************
 * IDirect3DDevice7::GetClipPlane
 *
 * Returns the clipping plane with a specific index
 *
 * Params:
 *  Index: The index of the desired plane
 *  PlaneEquation: Address to store the plane equation to
 *
 * Returns:
 *  D3D_OK on success
 *  DDERR_INVALIDPARAMS if PlaneEquation is NULL
 *  See IWineD3DDevice::GetClipPlane for more details
 *
 *****************************************************************************/
6127
static HRESULT d3d_device7_GetClipPlane(IDirect3DDevice7 *iface, DWORD idx, D3DVALUE *plane)
6128
{
6129
    struct d3d_device *device = impl_from_IDirect3DDevice7(iface);
6130
    HRESULT hr;
6131

6132
    TRACE("iface %p, idx %u, plane %p.\n", iface, idx, plane);
6133

6134
    if (!plane)
6135 6136
        return DDERR_INVALIDPARAMS;

6137
    wined3d_mutex_lock();
6138
    hr = wined3d_device_get_clip_plane(device->wined3d_device, idx, (struct wined3d_vec4 *)plane);
6139 6140
    wined3d_mutex_unlock();

6141
    return hr;
6142 6143
}

6144
static HRESULT WINAPI d3d_device7_GetClipPlane_FPUSetup(IDirect3DDevice7 *iface, DWORD idx, D3DVALUE *plane)
6145
{
6146
    return d3d_device7_GetClipPlane(iface, idx, plane);
6147 6148
}

6149
static HRESULT WINAPI d3d_device7_GetClipPlane_FPUPreserve(IDirect3DDevice7 *iface, DWORD idx, D3DVALUE *plane)
6150 6151 6152 6153 6154
{
    HRESULT hr;
    WORD old_fpucw;

    old_fpucw = d3d_fpu_setup();
6155
    hr = d3d_device7_GetClipPlane(iface, idx, plane);
6156 6157 6158 6159 6160
    set_fpu_control_word(old_fpucw);

    return hr;
}

6161 6162 6163 6164
/*****************************************************************************
 * IDirect3DDevice7::GetInfo
 *
 * Retrieves some information about the device. The DirectX sdk says that
6165
 * this version returns S_FALSE for all retail builds of DirectX, that's what
6166 6167 6168 6169 6170 6171 6172 6173 6174 6175 6176
 * this implementation does.
 *
 * Params:
 *  DevInfoID: Information type requested
 *  DevInfoStruct: Pointer to a structure to store the info to
 *  Size: Size of the structure
 *
 * Returns:
 *  S_FALSE, because it's a non-debug driver
 *
 *****************************************************************************/
6177
static HRESULT WINAPI d3d_device7_GetInfo(IDirect3DDevice7 *iface, DWORD info_id, void *info, DWORD info_size)
6178
{
6179
    TRACE("iface %p, info_id %#x, info %p, info_size %u.\n",
6180
            iface, info_id, info, info_size);
6181

6182
    if (TRACE_ON(ddraw))
6183 6184
    {
        TRACE(" info requested : ");
6185
        switch (info_id)
6186 6187 6188 6189 6190 6191 6192 6193 6194 6195 6196
        {
            case D3DDEVINFOID_TEXTUREMANAGER: TRACE("D3DDEVINFOID_TEXTUREMANAGER\n"); break;
            case D3DDEVINFOID_D3DTEXTUREMANAGER: TRACE("D3DDEVINFOID_D3DTEXTUREMANAGER\n"); break;
            case D3DDEVINFOID_TEXTURING: TRACE("D3DDEVINFOID_TEXTURING\n"); break;
            default: ERR(" invalid flag !!!\n"); return DDERR_INVALIDPARAMS;
        }
    }

    return S_FALSE; /* According to MSDN, this is valid for a non-debug driver */
}

6197 6198 6199 6200 6201 6202 6203 6204 6205 6206
/* For performance optimization, devices created in FPUSETUP and FPUPRESERVE modes
 * have separate vtables. Simple functions where this doesn't matter like GetDirect3D
 * are not duplicated.

 * Device created with DDSCL_FPUSETUP (d3d7 default) - device methods assume that FPU
 * has already been setup for optimal d3d operation.

 * Device created with DDSCL_FPUPRESERVE - resets and restores FPU mode when necessary in
 * d3d calls (FPU may be in a mode non-suitable for d3d when the app calls d3d). Required
 * by Sacrifice (game). */
6207
static const struct IDirect3DDevice7Vtbl d3d_device7_fpu_setup_vtbl =
6208 6209
{
    /*** IUnknown Methods ***/
6210 6211 6212
    d3d_device7_QueryInterface,
    d3d_device7_AddRef,
    d3d_device7_Release,
6213
    /*** IDirect3DDevice7 ***/
6214 6215 6216 6217 6218 6219 6220 6221 6222 6223 6224 6225 6226 6227 6228 6229 6230 6231 6232 6233 6234 6235 6236 6237 6238 6239 6240 6241 6242 6243 6244 6245 6246 6247 6248 6249 6250 6251 6252 6253 6254 6255 6256 6257 6258 6259
    d3d_device7_GetCaps_FPUSetup,
    d3d_device7_EnumTextureFormats_FPUSetup,
    d3d_device7_BeginScene_FPUSetup,
    d3d_device7_EndScene_FPUSetup,
    d3d_device7_GetDirect3D,
    d3d_device7_SetRenderTarget_FPUSetup,
    d3d_device7_GetRenderTarget,
    d3d_device7_Clear_FPUSetup,
    d3d_device7_SetTransform_FPUSetup,
    d3d_device7_GetTransform_FPUSetup,
    d3d_device7_SetViewport_FPUSetup,
    d3d_device7_MultiplyTransform_FPUSetup,
    d3d_device7_GetViewport_FPUSetup,
    d3d_device7_SetMaterial_FPUSetup,
    d3d_device7_GetMaterial_FPUSetup,
    d3d_device7_SetLight_FPUSetup,
    d3d_device7_GetLight_FPUSetup,
    d3d_device7_SetRenderState_FPUSetup,
    d3d_device7_GetRenderState_FPUSetup,
    d3d_device7_BeginStateBlock_FPUSetup,
    d3d_device7_EndStateBlock_FPUSetup,
    d3d_device7_PreLoad_FPUSetup,
    d3d_device7_DrawPrimitive_FPUSetup,
    d3d_device7_DrawIndexedPrimitive_FPUSetup,
    d3d_device7_SetClipStatus,
    d3d_device7_GetClipStatus,
    d3d_device7_DrawPrimitiveStrided_FPUSetup,
    d3d_device7_DrawIndexedPrimitiveStrided_FPUSetup,
    d3d_device7_DrawPrimitiveVB_FPUSetup,
    d3d_device7_DrawIndexedPrimitiveVB_FPUSetup,
    d3d_device7_ComputeSphereVisibility,
    d3d_device7_GetTexture_FPUSetup,
    d3d_device7_SetTexture_FPUSetup,
    d3d_device7_GetTextureStageState_FPUSetup,
    d3d_device7_SetTextureStageState_FPUSetup,
    d3d_device7_ValidateDevice_FPUSetup,
    d3d_device7_ApplyStateBlock_FPUSetup,
    d3d_device7_CaptureStateBlock_FPUSetup,
    d3d_device7_DeleteStateBlock_FPUSetup,
    d3d_device7_CreateStateBlock_FPUSetup,
    d3d_device7_Load_FPUSetup,
    d3d_device7_LightEnable_FPUSetup,
    d3d_device7_GetLightEnable_FPUSetup,
    d3d_device7_SetClipPlane_FPUSetup,
    d3d_device7_GetClipPlane_FPUSetup,
    d3d_device7_GetInfo
6260 6261
};

6262
static const struct IDirect3DDevice7Vtbl d3d_device7_fpu_preserve_vtbl =
6263 6264
{
    /*** IUnknown Methods ***/
6265 6266 6267
    d3d_device7_QueryInterface,
    d3d_device7_AddRef,
    d3d_device7_Release,
6268
    /*** IDirect3DDevice7 ***/
6269 6270 6271 6272 6273 6274 6275 6276 6277 6278 6279 6280 6281 6282 6283 6284 6285 6286 6287 6288 6289 6290 6291 6292 6293 6294 6295 6296 6297 6298 6299 6300 6301 6302 6303 6304 6305 6306 6307 6308 6309 6310 6311 6312 6313 6314
    d3d_device7_GetCaps_FPUPreserve,
    d3d_device7_EnumTextureFormats_FPUPreserve,
    d3d_device7_BeginScene_FPUPreserve,
    d3d_device7_EndScene_FPUPreserve,
    d3d_device7_GetDirect3D,
    d3d_device7_SetRenderTarget_FPUPreserve,
    d3d_device7_GetRenderTarget,
    d3d_device7_Clear_FPUPreserve,
    d3d_device7_SetTransform_FPUPreserve,
    d3d_device7_GetTransform_FPUPreserve,
    d3d_device7_SetViewport_FPUPreserve,
    d3d_device7_MultiplyTransform_FPUPreserve,
    d3d_device7_GetViewport_FPUPreserve,
    d3d_device7_SetMaterial_FPUPreserve,
    d3d_device7_GetMaterial_FPUPreserve,
    d3d_device7_SetLight_FPUPreserve,
    d3d_device7_GetLight_FPUPreserve,
    d3d_device7_SetRenderState_FPUPreserve,
    d3d_device7_GetRenderState_FPUPreserve,
    d3d_device7_BeginStateBlock_FPUPreserve,
    d3d_device7_EndStateBlock_FPUPreserve,
    d3d_device7_PreLoad_FPUPreserve,
    d3d_device7_DrawPrimitive_FPUPreserve,
    d3d_device7_DrawIndexedPrimitive_FPUPreserve,
    d3d_device7_SetClipStatus,
    d3d_device7_GetClipStatus,
    d3d_device7_DrawPrimitiveStrided_FPUPreserve,
    d3d_device7_DrawIndexedPrimitiveStrided_FPUPreserve,
    d3d_device7_DrawPrimitiveVB_FPUPreserve,
    d3d_device7_DrawIndexedPrimitiveVB_FPUPreserve,
    d3d_device7_ComputeSphereVisibility,
    d3d_device7_GetTexture_FPUPreserve,
    d3d_device7_SetTexture_FPUPreserve,
    d3d_device7_GetTextureStageState_FPUPreserve,
    d3d_device7_SetTextureStageState_FPUPreserve,
    d3d_device7_ValidateDevice_FPUPreserve,
    d3d_device7_ApplyStateBlock_FPUPreserve,
    d3d_device7_CaptureStateBlock_FPUPreserve,
    d3d_device7_DeleteStateBlock_FPUPreserve,
    d3d_device7_CreateStateBlock_FPUPreserve,
    d3d_device7_Load_FPUPreserve,
    d3d_device7_LightEnable_FPUPreserve,
    d3d_device7_GetLightEnable_FPUPreserve,
    d3d_device7_SetClipPlane_FPUPreserve,
    d3d_device7_GetClipPlane_FPUPreserve,
    d3d_device7_GetInfo
6315 6316
};

6317
static const struct IDirect3DDevice3Vtbl d3d_device3_vtbl =
6318 6319
{
    /*** IUnknown Methods ***/
6320 6321 6322
    d3d_device3_QueryInterface,
    d3d_device3_AddRef,
    d3d_device3_Release,
6323
    /*** IDirect3DDevice3 ***/
6324 6325 6326 6327 6328 6329 6330 6331 6332 6333 6334 6335 6336 6337 6338 6339 6340 6341 6342 6343 6344 6345 6346 6347 6348 6349 6350 6351 6352 6353 6354 6355 6356 6357 6358 6359 6360 6361 6362
    d3d_device3_GetCaps,
    d3d_device3_GetStats,
    d3d_device3_AddViewport,
    d3d_device3_DeleteViewport,
    d3d_device3_NextViewport,
    d3d_device3_EnumTextureFormats,
    d3d_device3_BeginScene,
    d3d_device3_EndScene,
    d3d_device3_GetDirect3D,
    d3d_device3_SetCurrentViewport,
    d3d_device3_GetCurrentViewport,
    d3d_device3_SetRenderTarget,
    d3d_device3_GetRenderTarget,
    d3d_device3_Begin,
    d3d_device3_BeginIndexed,
    d3d_device3_Vertex,
    d3d_device3_Index,
    d3d_device3_End,
    d3d_device3_GetRenderState,
    d3d_device3_SetRenderState,
    d3d_device3_GetLightState,
    d3d_device3_SetLightState,
    d3d_device3_SetTransform,
    d3d_device3_GetTransform,
    d3d_device3_MultiplyTransform,
    d3d_device3_DrawPrimitive,
    d3d_device3_DrawIndexedPrimitive,
    d3d_device3_SetClipStatus,
    d3d_device3_GetClipStatus,
    d3d_device3_DrawPrimitiveStrided,
    d3d_device3_DrawIndexedPrimitiveStrided,
    d3d_device3_DrawPrimitiveVB,
    d3d_device3_DrawIndexedPrimitiveVB,
    d3d_device3_ComputeSphereVisibility,
    d3d_device3_GetTexture,
    d3d_device3_SetTexture,
    d3d_device3_GetTextureStageState,
    d3d_device3_SetTextureStageState,
    d3d_device3_ValidateDevice
6363 6364
};

6365
static const struct IDirect3DDevice2Vtbl d3d_device2_vtbl =
6366 6367
{
    /*** IUnknown Methods ***/
6368 6369 6370
    d3d_device2_QueryInterface,
    d3d_device2_AddRef,
    d3d_device2_Release,
6371
    /*** IDirect3DDevice2 ***/
6372 6373 6374 6375 6376 6377 6378 6379 6380 6381 6382 6383 6384 6385 6386 6387 6388 6389 6390 6391 6392 6393 6394 6395 6396 6397 6398 6399 6400 6401
    d3d_device2_GetCaps,
    d3d_device2_SwapTextureHandles,
    d3d_device2_GetStats,
    d3d_device2_AddViewport,
    d3d_device2_DeleteViewport,
    d3d_device2_NextViewport,
    d3d_device2_EnumTextureFormats,
    d3d_device2_BeginScene,
    d3d_device2_EndScene,
    d3d_device2_GetDirect3D,
    d3d_device2_SetCurrentViewport,
    d3d_device2_GetCurrentViewport,
    d3d_device2_SetRenderTarget,
    d3d_device2_GetRenderTarget,
    d3d_device2_Begin,
    d3d_device2_BeginIndexed,
    d3d_device2_Vertex,
    d3d_device2_Index,
    d3d_device2_End,
    d3d_device2_GetRenderState,
    d3d_device2_SetRenderState,
    d3d_device2_GetLightState,
    d3d_device2_SetLightState,
    d3d_device2_SetTransform,
    d3d_device2_GetTransform,
    d3d_device2_MultiplyTransform,
    d3d_device2_DrawPrimitive,
    d3d_device2_DrawIndexedPrimitive,
    d3d_device2_SetClipStatus,
    d3d_device2_GetClipStatus
6402 6403
};

6404
static const struct IDirect3DDeviceVtbl d3d_device1_vtbl =
6405 6406
{
    /*** IUnknown Methods ***/
6407 6408 6409
    d3d_device1_QueryInterface,
    d3d_device1_AddRef,
    d3d_device1_Release,
6410
    /*** IDirect3DDevice1 ***/
6411 6412 6413 6414 6415 6416 6417 6418 6419 6420 6421 6422 6423 6424 6425 6426 6427 6428 6429
    d3d_device1_Initialize,
    d3d_device1_GetCaps,
    d3d_device1_SwapTextureHandles,
    d3d_device1_CreateExecuteBuffer,
    d3d_device1_GetStats,
    d3d_device1_Execute,
    d3d_device1_AddViewport,
    d3d_device1_DeleteViewport,
    d3d_device1_NextViewport,
    d3d_device1_Pick,
    d3d_device1_GetPickRecords,
    d3d_device1_EnumTextureFormats,
    d3d_device1_CreateMatrix,
    d3d_device1_SetMatrix,
    d3d_device1_GetMatrix,
    d3d_device1_DeleteMatrix,
    d3d_device1_BeginScene,
    d3d_device1_EndScene,
    d3d_device1_GetDirect3D
6430
};
6431

6432 6433 6434 6435 6436 6437 6438
static const struct IUnknownVtbl d3d_device_inner_vtbl =
{
    d3d_device_inner_QueryInterface,
    d3d_device_inner_AddRef,
    d3d_device_inner_Release,
};

6439
struct d3d_device *unsafe_impl_from_IDirect3DDevice7(IDirect3DDevice7 *iface)
6440 6441 6442
{
    if (!iface) return NULL;
    assert((iface->lpVtbl == &d3d_device7_fpu_preserve_vtbl) || (iface->lpVtbl == &d3d_device7_fpu_setup_vtbl));
6443
    return CONTAINING_RECORD(iface, struct d3d_device, IDirect3DDevice7_iface);
6444 6445
}

6446
struct d3d_device *unsafe_impl_from_IDirect3DDevice3(IDirect3DDevice3 *iface)
6447 6448 6449
{
    if (!iface) return NULL;
    assert(iface->lpVtbl == &d3d_device3_vtbl);
6450
    return CONTAINING_RECORD(iface, struct d3d_device, IDirect3DDevice3_iface);
6451 6452
}

6453
struct d3d_device *unsafe_impl_from_IDirect3DDevice2(IDirect3DDevice2 *iface)
6454 6455 6456
{
    if (!iface) return NULL;
    assert(iface->lpVtbl == &d3d_device2_vtbl);
6457
    return CONTAINING_RECORD(iface, struct d3d_device, IDirect3DDevice2_iface);
6458 6459
}

6460
struct d3d_device *unsafe_impl_from_IDirect3DDevice(IDirect3DDevice *iface)
6461 6462 6463
{
    if (!iface) return NULL;
    assert(iface->lpVtbl == &d3d_device1_vtbl);
6464
    return CONTAINING_RECORD(iface, struct d3d_device, IDirect3DDevice_iface);
6465 6466
}

6467
enum wined3d_depth_buffer_type d3d_device_update_depth_stencil(struct d3d_device *device)
6468 6469 6470
{
    IDirectDrawSurface7 *depthStencil = NULL;
    static DDSCAPS2 depthcaps = { DDSCAPS_ZBUFFER, 0, 0, 0 };
6471
    struct ddraw_surface *dsi;
6472

6473 6474
    IDirectDrawSurface7_GetAttachedSurface(&device->target->IDirectDrawSurface7_iface, &depthcaps, &depthStencil);
    if (!depthStencil)
6475 6476
    {
        TRACE("Setting wined3d depth stencil to NULL\n");
6477
        wined3d_device_set_depth_stencil(device->wined3d_device, NULL);
6478
        return WINED3D_ZB_FALSE;
6479 6480
    }

6481
    dsi = impl_from_IDirectDrawSurface7(depthStencil);
6482
    TRACE("Setting wined3d depth stencil to %p (wined3d %p)\n", dsi, dsi->wined3d_surface);
6483
    wined3d_device_set_depth_stencil(device->wined3d_device, dsi->wined3d_surface);
6484 6485

    IDirectDrawSurface7_Release(depthStencil);
6486
    return WINED3D_ZB_TRUE;
6487
}
6488

6489
static HRESULT d3d_device_init(struct d3d_device *device, struct ddraw *ddraw,
6490
        struct ddraw_surface *target, UINT version, IUnknown *outer_unknown)
6491
{
6492 6493 6494 6495 6496 6497 6498
    static const D3DMATRIX ident =
    {
        1.0f, 0.0f, 0.0f, 0.0f,
        0.0f, 1.0f, 0.0f, 0.0f,
        0.0f, 0.0f, 1.0f, 0.0f,
        0.0f, 0.0f, 0.0f, 1.0f,
    };
6499 6500 6501
    HRESULT hr;

    if (ddraw->cooperative_level & DDSCL_FPUPRESERVE)
6502
        device->IDirect3DDevice7_iface.lpVtbl = &d3d_device7_fpu_preserve_vtbl;
6503
    else
6504
        device->IDirect3DDevice7_iface.lpVtbl = &d3d_device7_fpu_setup_vtbl;
6505

6506
    device->IDirect3DDevice3_iface.lpVtbl = &d3d_device3_vtbl;
6507
    device->IDirect3DDevice2_iface.lpVtbl = &d3d_device2_vtbl;
6508
    device->IDirect3DDevice_iface.lpVtbl = &d3d_device1_vtbl;
6509
    device->IUnknown_inner.lpVtbl = &d3d_device_inner_vtbl;
6510
    device->ref = 1;
6511
    device->version = version;
6512 6513 6514 6515 6516 6517

    if (outer_unknown)
        device->outer_unknown = outer_unknown;
    else
        device->outer_unknown = &device->IUnknown_inner;

6518 6519
    device->ddraw = ddraw;
    device->target = target;
6520
    list_init(&device->viewport_list);
6521 6522 6523 6524 6525 6526 6527 6528

    if (!ddraw_handle_table_init(&device->handle_table, 64))
    {
        ERR("Failed to initialize handle table.\n");
        return DDERR_OUTOFMEMORY;
    }

    device->legacyTextureBlending = FALSE;
6529 6530
    device->legacy_projection = ident;
    device->legacy_clipspace = ident;
6531 6532

    /* Create an index buffer, it's needed for indexed drawing */
6533
    hr = wined3d_buffer_create_ib(ddraw->wined3d_device, 0x40000 /* Length. Don't know how long it should be */,
6534
            WINED3DUSAGE_DYNAMIC /* Usage */, WINED3D_POOL_DEFAULT, NULL,
6535
            &ddraw_null_wined3d_parent_ops, &device->indexbuffer);
6536 6537 6538 6539 6540 6541 6542 6543
    if (FAILED(hr))
    {
        ERR("Failed to create an index buffer, hr %#x.\n", hr);
        ddraw_handle_table_destroy(&device->handle_table);
        return hr;
    }

    /* This is for convenience. */
6544 6545
    device->wined3d_device = ddraw->wined3d_device;
    wined3d_device_incref(ddraw->wined3d_device);
6546

6547
    /* Render to the back buffer */
6548
    hr = wined3d_device_set_render_target(ddraw->wined3d_device, 0, target->wined3d_surface, TRUE);
6549
    if (FAILED(hr))
6550
    {
6551
        ERR("Failed to set render target, hr %#x.\n", hr);
6552
        wined3d_buffer_decref(device->indexbuffer);
6553 6554
        ddraw_handle_table_destroy(&device->handle_table);
        return hr;
6555 6556 6557 6558 6559 6560 6561 6562 6563 6564 6565
    }

    /* FIXME: This is broken. The target AddRef() makes some sense, because
     * we store a pointer during initialization, but then that's also where
     * the AddRef() should be. We don't store ddraw->d3d_target anywhere. */
    /* AddRef the render target. Also AddRef the render target from ddraw,
     * because if it is released before the app releases the D3D device, the
     * D3D capabilities of wined3d will be uninitialized, which has bad effects.
     *
     * In most cases, those surfaces are the same anyway, but this will simply
     * add another ref which is released when the device is destroyed. */
6566 6567
    if (version != 1)
        IDirectDrawSurface7_AddRef(&target->IDirectDrawSurface7_iface);
6568 6569 6570

    ddraw->d3ddevice = device;

6571
    wined3d_device_set_render_state(ddraw->wined3d_device, WINED3D_RS_ZENABLE,
6572
            d3d_device_update_depth_stencil(device));
6573 6574
    if (version == 1) /* Color keying is initially enabled for version 1 devices. */
        wined3d_device_set_render_state(ddraw->wined3d_device, WINED3D_RS_COLORKEYENABLE, TRUE);
6575 6576 6577

    return D3D_OK;
}
6578 6579

HRESULT d3d_device_create(struct ddraw *ddraw, struct ddraw_surface *target,
6580
        UINT version, struct d3d_device **device, IUnknown *outer_unknown)
6581
{
6582
    struct d3d_device *object;
6583 6584
    HRESULT hr;

6585 6586
    TRACE("ddraw %p, target %p, version %u, device %p, outer_unknown %p.\n",
            ddraw, target, version, device, outer_unknown);
6587 6588 6589 6590 6591 6592 6593 6594 6595 6596 6597 6598 6599 6600 6601 6602 6603 6604 6605 6606 6607 6608

    if (DefaultSurfaceType != WINED3D_SURFACE_TYPE_OPENGL)
    {
        ERR_(winediag)("The application wants to create a Direct3D device, "
                "but the current DirectDrawRenderer does not support this.\n");

        return DDERR_NO3D;
    }

    if (ddraw->d3ddevice)
    {
        FIXME("Only one Direct3D device per DirectDraw object supported.\n");
        return DDERR_INVALIDPARAMS;
    }

    object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
    if (!object)
    {
        ERR("Failed to allocate device memory.\n");
        return DDERR_OUTOFMEMORY;
    }

6609
    hr = d3d_device_init(object, ddraw, target, version, outer_unknown);
6610 6611 6612 6613 6614 6615 6616 6617 6618 6619 6620 6621
    if (FAILED(hr))
    {
        WARN("Failed to initialize device, hr %#x.\n", hr);
        HeapFree(GetProcessHeap(), 0, object);
        return hr;
    }

    TRACE("Created device %p.\n", object);
    *device = object;

    return D3D_OK;
}