1 /* Direct3D Viewport 2 * Copyright (c) 1998 Lionel ULMER 3 * Copyright (c) 2006-2007 Stefan DÖSINGER 4 * 5 * This library is free software; you can redistribute it and/or 6 * modify it under the terms of the GNU Lesser General Public 7 * License as published by the Free Software Foundation; either 8 * version 2.1 of the License, or (at your option) any later version. 9 * 10 * This library is distributed in the hope that it will be useful, 11 * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 13 * Lesser General Public License for more details. 14 * 15 * You should have received a copy of the GNU Lesser General Public 16 * License along with this library; if not, write to the Free Software 17 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA 18 */ 19 20 #include "config.h" 21 #include "wine/port.h" 22 23 #include "ddraw_private.h" 24 25 WINE_DEFAULT_DEBUG_CHANNEL(ddraw); 26 27 /***************************************************************************** 28 * Helper functions 29 *****************************************************************************/ 30 31 static void update_clip_space(struct d3d_device *device, 32 struct wined3d_vec3 *scale, struct wined3d_vec3 *offset) 33 { 34 D3DMATRIX clip_space = 35 { 36 scale->x, 0.0f, 0.0f, 0.0f, 37 0.0f, scale->y, 0.0f, 0.0f, 38 0.0f, 0.0f, scale->z, 0.0f, 39 offset->x, offset->y, offset->z, 1.0f, 40 }; 41 D3DMATRIX projection; 42 43 multiply_matrix(&projection, &clip_space, &device->legacy_projection); 44 wined3d_device_set_transform(device->wined3d_device, 45 WINED3D_TS_PROJECTION, (struct wined3d_matrix *)&projection); 46 device->legacy_clipspace = clip_space; 47 } 48 49 /***************************************************************************** 50 * viewport_activate 51 * 52 * activates the viewport using IDirect3DDevice7::SetViewport 53 * 54 *****************************************************************************/ 55 void viewport_activate(struct d3d_viewport *This, BOOL ignore_lights) 56 { 57 struct wined3d_vec3 scale, offset; 58 D3DVIEWPORT7 vp; 59 60 if (!ignore_lights) 61 { 62 struct d3d_light *light; 63 64 /* Activate all the lights associated with this context */ 65 LIST_FOR_EACH_ENTRY(light, &This->light_list, struct d3d_light, entry) 66 { 67 light_activate(light); 68 } 69 } 70 71 /* And copy the values in the structure used by the device */ 72 if (This->use_vp2) 73 { 74 vp.dwX = This->viewports.vp2.dwX; 75 vp.dwY = This->viewports.vp2.dwY; 76 vp.dwHeight = This->viewports.vp2.dwHeight; 77 vp.dwWidth = This->viewports.vp2.dwWidth; 78 vp.dvMinZ = 0.0f; 79 vp.dvMaxZ = 1.0f; 80 81 scale.x = 2.0f / This->viewports.vp2.dvClipWidth; 82 scale.y = 2.0f / This->viewports.vp2.dvClipHeight; 83 scale.z = 1.0f / (This->viewports.vp2.dvMaxZ - This->viewports.vp2.dvMinZ); 84 offset.x = -2.0f * This->viewports.vp2.dvClipX / This->viewports.vp2.dvClipWidth - 1.0f; 85 offset.y = -2.0f * This->viewports.vp2.dvClipY / This->viewports.vp2.dvClipHeight + 1.0f; 86 offset.z = -This->viewports.vp2.dvMinZ / (This->viewports.vp2.dvMaxZ - This->viewports.vp2.dvMinZ); 87 } 88 else 89 { 90 vp.dwX = This->viewports.vp1.dwX; 91 vp.dwY = This->viewports.vp1.dwY; 92 vp.dwHeight = This->viewports.vp1.dwHeight; 93 vp.dwWidth = This->viewports.vp1.dwWidth; 94 vp.dvMinZ = 0.0f; 95 vp.dvMaxZ = 1.0f; 96 97 scale.x = 2.0f * This->viewports.vp1.dvScaleX / This->viewports.vp1.dwWidth; 98 scale.y = 2.0f * This->viewports.vp1.dvScaleY / This->viewports.vp1.dwHeight; 99 scale.z = 1.0f; 100 offset.x = 0.0f; 101 offset.y = 0.0f; 102 offset.z = 0.0f; 103 } 104 105 update_clip_space(This->active_device, &scale, &offset); 106 IDirect3DDevice7_SetViewport(&This->active_device->IDirect3DDevice7_iface, &vp); 107 } 108 109 /***************************************************************************** 110 * _dump_D3DVIEWPORT, _dump_D3DVIEWPORT2 111 * 112 * Writes viewport information to TRACE 113 * 114 *****************************************************************************/ 115 static void _dump_D3DVIEWPORT(const D3DVIEWPORT *lpvp) 116 { 117 TRACE(" - dwSize = %d dwX = %d dwY = %d\n", 118 lpvp->dwSize, lpvp->dwX, lpvp->dwY); 119 TRACE(" - dwWidth = %d dwHeight = %d\n", 120 lpvp->dwWidth, lpvp->dwHeight); 121 TRACE(" - dvScaleX = %f dvScaleY = %f\n", 122 lpvp->dvScaleX, lpvp->dvScaleY); 123 TRACE(" - dvMaxX = %f dvMaxY = %f\n", 124 lpvp->dvMaxX, lpvp->dvMaxY); 125 TRACE(" - dvMinZ = %f dvMaxZ = %f\n", 126 lpvp->dvMinZ, lpvp->dvMaxZ); 127 } 128 129 static void _dump_D3DVIEWPORT2(const D3DVIEWPORT2 *lpvp) 130 { 131 TRACE(" - dwSize = %d dwX = %d dwY = %d\n", 132 lpvp->dwSize, lpvp->dwX, lpvp->dwY); 133 TRACE(" - dwWidth = %d dwHeight = %d\n", 134 lpvp->dwWidth, lpvp->dwHeight); 135 TRACE(" - dvClipX = %f dvClipY = %f\n", 136 lpvp->dvClipX, lpvp->dvClipY); 137 TRACE(" - dvClipWidth = %f dvClipHeight = %f\n", 138 lpvp->dvClipWidth, lpvp->dvClipHeight); 139 TRACE(" - dvMinZ = %f dvMaxZ = %f\n", 140 lpvp->dvMinZ, lpvp->dvMaxZ); 141 } 142 143 static inline struct d3d_viewport *impl_from_IDirect3DViewport3(IDirect3DViewport3 *iface) 144 { 145 return CONTAINING_RECORD(iface, struct d3d_viewport, IDirect3DViewport3_iface); 146 } 147 148 /***************************************************************************** 149 * IUnknown Methods. 150 *****************************************************************************/ 151 152 /***************************************************************************** 153 * IDirect3DViewport3::QueryInterface 154 * 155 * A normal QueryInterface. Can query all interface versions and the 156 * IUnknown interface. The VTables of the different versions 157 * are equal 158 * 159 * Params: 160 * refiid: Interface id queried for 161 * obj: Address to write the interface pointer to 162 * 163 * Returns: 164 * S_OK on success. 165 * E_NOINTERFACE if the requested interface wasn't found 166 * 167 *****************************************************************************/ 168 static HRESULT WINAPI d3d_viewport_QueryInterface(IDirect3DViewport3 *iface, REFIID riid, void **object) 169 { 170 TRACE("iface %p, riid %s, object %p.\n", iface, debugstr_guid(riid), object); 171 172 if (IsEqualGUID(&IID_IDirect3DViewport3, riid) 173 || IsEqualGUID(&IID_IDirect3DViewport2, riid) 174 || IsEqualGUID(&IID_IDirect3DViewport, riid) 175 || IsEqualGUID(&IID_IUnknown, riid)) 176 { 177 IDirect3DViewport3_AddRef(iface); 178 *object = iface; 179 return S_OK; 180 } 181 182 WARN("%s not implemented, returning E_NOINTERFACE.\n", debugstr_guid(riid)); 183 184 *object = NULL; 185 return E_NOINTERFACE; 186 } 187 188 /***************************************************************************** 189 * IDirect3DViewport3::AddRef 190 * 191 * Increases the refcount. 192 * 193 * Returns: 194 * The new refcount 195 * 196 *****************************************************************************/ 197 static ULONG WINAPI d3d_viewport_AddRef(IDirect3DViewport3 *iface) 198 { 199 struct d3d_viewport *viewport = impl_from_IDirect3DViewport3(iface); 200 ULONG ref = InterlockedIncrement(&viewport->ref); 201 202 TRACE("%p increasing refcount to %u.\n", viewport, ref); 203 204 return ref; 205 } 206 207 /***************************************************************************** 208 * IDirect3DViewport3::Release 209 * 210 * Reduces the refcount. If it falls to 0, the interface is released 211 * 212 * Returns: 213 * The new refcount 214 * 215 *****************************************************************************/ 216 static ULONG WINAPI d3d_viewport_Release(IDirect3DViewport3 *iface) 217 { 218 struct d3d_viewport *viewport = impl_from_IDirect3DViewport3(iface); 219 ULONG ref = InterlockedDecrement(&viewport->ref); 220 221 TRACE("%p decreasing refcount to %u.\n", viewport, ref); 222 223 if (!ref) 224 heap_free(viewport); 225 226 return ref; 227 } 228 229 /***************************************************************************** 230 * IDirect3DViewport Methods. 231 *****************************************************************************/ 232 233 /***************************************************************************** 234 * IDirect3DViewport3::Initialize 235 * 236 * No-op initialization. 237 * 238 * Params: 239 * Direct3D: The direct3D device this viewport is assigned to 240 * 241 * Returns: 242 * DDERR_ALREADYINITIALIZED 243 * 244 *****************************************************************************/ 245 static HRESULT WINAPI d3d_viewport_Initialize(IDirect3DViewport3 *iface, IDirect3D *d3d) 246 { 247 TRACE("iface %p, d3d %p.\n", iface, d3d); 248 249 return DDERR_ALREADYINITIALIZED; 250 } 251 252 /***************************************************************************** 253 * IDirect3DViewport3::GetViewport 254 * 255 * Returns the viewport data assigned to this viewport interface 256 * 257 * Params: 258 * Data: Address to store the data 259 * 260 * Returns: 261 * D3D_OK on success 262 * DDERR_INVALIDPARAMS if Data is NULL 263 * 264 *****************************************************************************/ 265 static HRESULT WINAPI d3d_viewport_GetViewport(IDirect3DViewport3 *iface, D3DVIEWPORT *lpData) 266 { 267 struct d3d_viewport *This = impl_from_IDirect3DViewport3(iface); 268 DWORD dwSize; 269 270 TRACE("iface %p, data %p.\n", iface, lpData); 271 272 wined3d_mutex_lock(); 273 274 dwSize = lpData->dwSize; 275 if (!This->use_vp2) 276 memcpy(lpData, &(This->viewports.vp1), dwSize); 277 else { 278 D3DVIEWPORT vp1; 279 vp1.dwSize = sizeof(vp1); 280 vp1.dwX = This->viewports.vp2.dwX; 281 vp1.dwY = This->viewports.vp2.dwY; 282 vp1.dwWidth = This->viewports.vp2.dwWidth; 283 vp1.dwHeight = This->viewports.vp2.dwHeight; 284 vp1.dvMaxX = 0.0; 285 vp1.dvMaxY = 0.0; 286 vp1.dvScaleX = 0.0; 287 vp1.dvScaleY = 0.0; 288 vp1.dvMinZ = This->viewports.vp2.dvMinZ; 289 vp1.dvMaxZ = This->viewports.vp2.dvMaxZ; 290 memcpy(lpData, &vp1, dwSize); 291 } 292 293 if (TRACE_ON(ddraw)) 294 { 295 TRACE(" returning D3DVIEWPORT :\n"); 296 _dump_D3DVIEWPORT(lpData); 297 } 298 299 wined3d_mutex_unlock(); 300 301 return DD_OK; 302 } 303 304 /***************************************************************************** 305 * IDirect3DViewport3::SetViewport 306 * 307 * Sets the viewport information for this interface 308 * 309 * Params: 310 * lpData: Viewport to set 311 * 312 * Returns: 313 * D3D_OK on success 314 * DDERR_INVALIDPARAMS if Data is NULL 315 * 316 *****************************************************************************/ 317 static HRESULT WINAPI d3d_viewport_SetViewport(IDirect3DViewport3 *iface, D3DVIEWPORT *lpData) 318 { 319 struct d3d_viewport *This = impl_from_IDirect3DViewport3(iface); 320 IDirect3DViewport3 *current_viewport; 321 322 TRACE("iface %p, data %p.\n", iface, lpData); 323 324 if (TRACE_ON(ddraw)) 325 { 326 TRACE(" getting D3DVIEWPORT :\n"); 327 _dump_D3DVIEWPORT(lpData); 328 } 329 330 wined3d_mutex_lock(); 331 332 This->use_vp2 = 0; 333 memset(&(This->viewports.vp1), 0, sizeof(This->viewports.vp1)); 334 memcpy(&(This->viewports.vp1), lpData, lpData->dwSize); 335 336 /* Tests on two games show that these values are never used properly so override 337 them with proper ones :-) 338 */ 339 This->viewports.vp1.dvMinZ = 0.0; 340 This->viewports.vp1.dvMaxZ = 1.0; 341 342 if (This->active_device) 343 { 344 IDirect3DDevice3 *d3d_device3 = &This->active_device->IDirect3DDevice3_iface; 345 if (SUCCEEDED(IDirect3DDevice3_GetCurrentViewport(d3d_device3, ¤t_viewport))) 346 { 347 if (current_viewport == iface) viewport_activate(This, FALSE); 348 IDirect3DViewport3_Release(current_viewport); 349 } 350 } 351 352 wined3d_mutex_unlock(); 353 354 return DD_OK; 355 } 356 357 /***************************************************************************** 358 * IDirect3DViewport3::TransformVertices 359 * 360 * Transforms vertices by the transformation matrix. 361 * 362 * This function is pretty similar to IDirect3DVertexBuffer7::ProcessVertices, 363 * so it's tempting to forward it to there. However, there are some 364 * tiny differences. First, the lpOffscreen flag that is reported back, 365 * then there is the homogeneous vertex that is generated. Also there's a lack 366 * of FVFs, but still a custom stride. Last, the d3d1 - d3d3 viewport has some 367 * settings (scale) that d3d7 and wined3d do not have. All in all wrapping to 368 * ProcessVertices doesn't pay of in terms of wrapper code needed and code 369 * reused. 370 * 371 * Params: 372 * dwVertexCount: The number of vertices to be transformed 373 * data: Pointer to the vertex input / output data. 374 * dwFlags: D3DTRANSFORM_CLIPPED or D3DTRANSFORM_UNCLIPPED 375 * offscreen: Logical AND of the planes that clipped the vertices if clipping 376 * is on. 0 if clipping is off. 377 * 378 * Returns: 379 * D3D_OK on success 380 * D3DERR_VIEWPORTHASNODEVICE if the viewport is not assigned to a device 381 * DDERR_INVALIDPARAMS if no clipping flag is specified 382 * 383 *****************************************************************************/ 384 struct transform_vertices_vertex 385 { 386 float x, y, z, w; /* w is unused in input data. */ 387 struct 388 { 389 DWORD p[4]; 390 } payload; 391 }; 392 393 static HRESULT WINAPI d3d_viewport_TransformVertices(IDirect3DViewport3 *iface, 394 DWORD dwVertexCount, D3DTRANSFORMDATA *data, DWORD dwFlags, DWORD *offscreen) 395 { 396 struct d3d_viewport *viewport = impl_from_IDirect3DViewport3(iface); 397 D3DVIEWPORT vp = viewport->viewports.vp1; 398 D3DMATRIX view_mat, world_mat, proj_mat, mat; 399 struct transform_vertices_vertex *in, *out; 400 float x, y, z, w; 401 unsigned int i; 402 D3DHVERTEX *outH; 403 struct d3d_device *device = viewport->active_device; 404 BOOL activate = device->current_viewport != viewport; 405 406 TRACE("iface %p, vertex_count %u, data %p, flags %#x, offscreen %p.\n", 407 iface, dwVertexCount, data, dwFlags, offscreen); 408 409 /* Tests on windows show that Windows crashes when this occurs, 410 * so don't return the (intuitive) return value 411 if (!device) 412 { 413 WARN("No device active, returning D3DERR_VIEWPORTHASNODEVICE\n"); 414 return D3DERR_VIEWPORTHASNODEVICE; 415 } 416 */ 417 418 if (!data || data->dwSize != sizeof(*data)) 419 { 420 WARN("Transform data is NULL or size is incorrect, returning DDERR_INVALIDPARAMS\n"); 421 return DDERR_INVALIDPARAMS; 422 } 423 if (!(dwFlags & (D3DTRANSFORM_UNCLIPPED | D3DTRANSFORM_CLIPPED))) 424 { 425 WARN("No clipping flag passed, returning DDERR_INVALIDPARAMS\n"); 426 return DDERR_INVALIDPARAMS; 427 } 428 429 wined3d_mutex_lock(); 430 if (activate) 431 viewport_activate(viewport, TRUE); 432 433 wined3d_device_get_transform(device->wined3d_device, 434 D3DTRANSFORMSTATE_VIEW, (struct wined3d_matrix *)&view_mat); 435 wined3d_device_get_transform(device->wined3d_device, 436 WINED3D_TS_WORLD_MATRIX(0), (struct wined3d_matrix *)&world_mat); 437 wined3d_device_get_transform(device->wined3d_device, 438 WINED3D_TS_PROJECTION, (struct wined3d_matrix *)&proj_mat); 439 multiply_matrix(&mat, &view_mat, &world_mat); 440 multiply_matrix(&mat, &proj_mat, &mat); 441 442 /* The pointer is not tested against NULL on Windows. */ 443 if (dwFlags & D3DTRANSFORM_CLIPPED) 444 *offscreen = ~0U; 445 else 446 *offscreen = 0; 447 448 outH = data->lpHOut; 449 for(i = 0; i < dwVertexCount; i++) 450 { 451 in = (struct transform_vertices_vertex *)((char *)data->lpIn + data->dwInSize * i); 452 out = (struct transform_vertices_vertex *)((char *)data->lpOut + data->dwOutSize * i); 453 454 x = (in->x * mat._11) + (in->y * mat._21) + (in->z * mat._31) + mat._41; 455 y = (in->x * mat._12) + (in->y * mat._22) + (in->z * mat._32) + mat._42; 456 z = (in->x * mat._13) + (in->y * mat._23) + (in->z * mat._33) + mat._43; 457 w = (in->x * mat._14) + (in->y * mat._24) + (in->z * mat._34) + mat._44; 458 459 if(dwFlags & D3DTRANSFORM_CLIPPED) 460 { 461 /* If clipping is enabled, Windows assumes that outH is 462 * a valid pointer. */ 463 outH[i].u1.hx = (x - device->legacy_clipspace._41 * w) / device->legacy_clipspace._11; 464 outH[i].u2.hy = (y - device->legacy_clipspace._42 * w) / device->legacy_clipspace._22; 465 outH[i].u3.hz = (z - device->legacy_clipspace._43 * w) / device->legacy_clipspace._33; 466 467 outH[i].dwFlags = 0; 468 if (x > w) 469 outH[i].dwFlags |= D3DCLIP_RIGHT; 470 if (x < -w) 471 outH[i].dwFlags |= D3DCLIP_LEFT; 472 if (y > w) 473 outH[i].dwFlags |= D3DCLIP_TOP; 474 if (y < -w) 475 outH[i].dwFlags |= D3DCLIP_BOTTOM; 476 if (z < 0.0f) 477 outH[i].dwFlags |= D3DCLIP_FRONT; 478 if (z > w) 479 outH[i].dwFlags |= D3DCLIP_BACK; 480 481 *offscreen &= outH[i].dwFlags; 482 483 if(outH[i].dwFlags) 484 { 485 /* Looks like native just drops the vertex, leaves whatever data 486 * it has in the output buffer and goes on with the next vertex. 487 * The exact scheme hasn't been figured out yet, but windows 488 * definitely writes something there. 489 */ 490 out->x = x; 491 out->y = y; 492 out->z = z; 493 out->w = w; 494 continue; 495 } 496 } 497 498 w = 1 / w; 499 x *= w; y *= w; z *= w; 500 501 out->x = (x + 1.0f) * vp.dwWidth * 0.5 + vp.dwX; 502 out->y = (-y + 1.0f) * vp.dwHeight * 0.5 + vp.dwY; 503 out->z = z; 504 out->w = w; 505 out->payload = in->payload; 506 } 507 508 if (activate && device->current_viewport) 509 viewport_activate(device->current_viewport, TRUE); 510 511 wined3d_mutex_unlock(); 512 513 TRACE("All done\n"); 514 return DD_OK; 515 } 516 517 /***************************************************************************** 518 * IDirect3DViewport3::LightElements 519 * 520 * The DirectX 5.0 sdk says that it's not implemented 521 * 522 * Params: 523 * ? 524 * 525 * Returns: 526 * DDERR_UNSUPPORTED 527 * 528 *****************************************************************************/ 529 static HRESULT WINAPI d3d_viewport_LightElements(IDirect3DViewport3 *iface, 530 DWORD element_count, D3DLIGHTDATA *data) 531 { 532 TRACE("iface %p, element_count %u, data %p.\n", iface, element_count, data); 533 534 return DDERR_UNSUPPORTED; 535 } 536 537 static HRESULT WINAPI d3d_viewport_SetBackground(IDirect3DViewport3 *iface, D3DMATERIALHANDLE material) 538 { 539 struct d3d_viewport *viewport = impl_from_IDirect3DViewport3(iface); 540 struct d3d_material *m; 541 542 TRACE("iface %p, material %#x.\n", iface, material); 543 544 wined3d_mutex_lock(); 545 546 if (!(m = ddraw_get_object(&viewport->ddraw->d3ddevice->handle_table, material - 1, DDRAW_HANDLE_MATERIAL))) 547 { 548 WARN("Invalid material handle %#x.\n", material); 549 wined3d_mutex_unlock(); 550 return DDERR_INVALIDPARAMS; 551 } 552 553 TRACE("Setting background color : %.8e %.8e %.8e %.8e.\n", 554 m->mat.u.diffuse.u1.r, m->mat.u.diffuse.u2.g, 555 m->mat.u.diffuse.u3.b, m->mat.u.diffuse.u4.a); 556 viewport->background = m; 557 558 wined3d_mutex_unlock(); 559 560 return D3D_OK; 561 } 562 563 /***************************************************************************** 564 * IDirect3DViewport3::GetBackground 565 * 566 * Returns the material handle assigned to the background of the viewport 567 * 568 * Params: 569 * lphMat: Address to store the handle 570 * lpValid: is set to FALSE if no background is set, TRUE if one is set 571 * 572 * Returns: 573 * D3D_OK 574 * 575 *****************************************************************************/ 576 static HRESULT WINAPI d3d_viewport_GetBackground(IDirect3DViewport3 *iface, 577 D3DMATERIALHANDLE *material, BOOL *valid) 578 { 579 struct d3d_viewport *viewport = impl_from_IDirect3DViewport3(iface); 580 581 TRACE("iface %p, material %p, valid %p.\n", iface, material, valid); 582 583 wined3d_mutex_lock(); 584 if (valid) 585 *valid = !!viewport->background; 586 if (material) 587 *material = viewport->background ? viewport->background->Handle : 0; 588 wined3d_mutex_unlock(); 589 590 return D3D_OK; 591 } 592 593 /***************************************************************************** 594 * IDirect3DViewport3::SetBackgroundDepth 595 * 596 * Sets a surface that represents the background depth. Its contents are 597 * used to set the depth buffer in IDirect3DViewport3::Clear 598 * 599 * Params: 600 * lpDDSurface: Surface to set 601 * 602 * Returns: D3D_OK, because it's a stub 603 * 604 *****************************************************************************/ 605 static HRESULT WINAPI d3d_viewport_SetBackgroundDepth(IDirect3DViewport3 *iface, IDirectDrawSurface *surface) 606 { 607 FIXME("iface %p, surface %p stub!\n", iface, surface); 608 609 return D3D_OK; 610 } 611 612 /***************************************************************************** 613 * IDirect3DViewport3::GetBackgroundDepth 614 * 615 * Returns the surface that represents the depth field 616 * 617 * Params: 618 * lplpDDSurface: Address to store the interface pointer 619 * lpValid: Set to TRUE if a depth is assigned, FALSE otherwise 620 * 621 * Returns: 622 * D3D_OK, because it's a stub 623 * (DDERR_INVALIDPARAMS if DDSurface of Valid is NULL) 624 * 625 *****************************************************************************/ 626 static HRESULT WINAPI d3d_viewport_GetBackgroundDepth(IDirect3DViewport3 *iface, 627 IDirectDrawSurface **surface, BOOL *valid) 628 { 629 FIXME("iface %p, surface %p, valid %p stub!\n", iface, surface, valid); 630 631 return DD_OK; 632 } 633 634 /***************************************************************************** 635 * IDirect3DViewport3::Clear 636 * 637 * Clears the render target and / or the z buffer 638 * 639 * Params: 640 * dwCount: The amount of rectangles to clear. If 0, the whole buffer is 641 * cleared 642 * lpRects: Pointer to the array of rectangles. If NULL, Count must be 0 643 * dwFlags: D3DCLEAR_ZBUFFER and / or D3DCLEAR_TARGET 644 * 645 * Returns: 646 * D3D_OK on success 647 * D3DERR_VIEWPORTHASNODEVICE if there's no active device 648 * The return value of IDirect3DDevice7::Clear 649 * 650 *****************************************************************************/ 651 static HRESULT WINAPI d3d_viewport_Clear(IDirect3DViewport3 *iface, 652 DWORD rect_count, D3DRECT *rects, DWORD flags) 653 { 654 struct d3d_viewport *This = impl_from_IDirect3DViewport3(iface); 655 DWORD color = 0x00000000; 656 HRESULT hr; 657 IDirect3DViewport3 *current_viewport; 658 IDirect3DDevice3 *d3d_device3; 659 660 TRACE("iface %p, rect_count %u, rects %p, flags %#x.\n", iface, rect_count, rects, flags); 661 662 if (!rects || !rect_count) 663 { 664 WARN("rect_count = %u, rects = %p, ignoring clear\n", rect_count, rects); 665 return D3D_OK; 666 } 667 668 if (This->active_device == NULL) { 669 ERR(" Trying to clear a viewport not attached to a device!\n"); 670 return D3DERR_VIEWPORTHASNODEVICE; 671 } 672 d3d_device3 = &This->active_device->IDirect3DDevice3_iface; 673 674 wined3d_mutex_lock(); 675 676 if (flags & D3DCLEAR_TARGET) 677 { 678 if (!This->background) 679 WARN("No background material set.\n"); 680 else 681 color = D3DRGBA(This->background->mat.u.diffuse.u1.r, 682 This->background->mat.u.diffuse.u2.g, 683 This->background->mat.u.diffuse.u3.b, 684 This->background->mat.u.diffuse.u4.a); 685 } 686 687 /* Need to temporarily activate the viewport to clear it. The previously 688 * active one will be restored afterwards. */ 689 viewport_activate(This, TRUE); 690 691 hr = IDirect3DDevice7_Clear(&This->active_device->IDirect3DDevice7_iface, rect_count, rects, 692 flags & (D3DCLEAR_ZBUFFER | D3DCLEAR_TARGET), color, 1.0, 0x00000000); 693 694 if (SUCCEEDED(IDirect3DDevice3_GetCurrentViewport(d3d_device3, ¤t_viewport))) 695 { 696 struct d3d_viewport *vp = impl_from_IDirect3DViewport3(current_viewport); 697 viewport_activate(vp, TRUE); 698 IDirect3DViewport3_Release(current_viewport); 699 } 700 701 wined3d_mutex_unlock(); 702 703 return hr; 704 } 705 706 /***************************************************************************** 707 * IDirect3DViewport3::AddLight 708 * 709 * Adds an light to the viewport 710 * 711 * Params: 712 * lpDirect3DLight: Interface of the light to add 713 * 714 * Returns: 715 * D3D_OK on success 716 * DDERR_INVALIDPARAMS if Direct3DLight is NULL 717 * DDERR_INVALIDPARAMS if there are 8 lights or more 718 * 719 *****************************************************************************/ 720 static HRESULT WINAPI d3d_viewport_AddLight(IDirect3DViewport3 *iface, IDirect3DLight *lpDirect3DLight) 721 { 722 struct d3d_viewport *This = impl_from_IDirect3DViewport3(iface); 723 struct d3d_light *light_impl = unsafe_impl_from_IDirect3DLight(lpDirect3DLight); 724 DWORD i = 0; 725 DWORD map = This->map_lights; 726 727 TRACE("iface %p, light %p.\n", iface, lpDirect3DLight); 728 729 wined3d_mutex_lock(); 730 731 if (This->num_lights >= 8) 732 { 733 wined3d_mutex_unlock(); 734 return DDERR_INVALIDPARAMS; 735 } 736 737 /* Find a light number and update both light and viewports objects accordingly */ 738 while (map & 1) 739 { 740 map >>= 1; 741 ++i; 742 } 743 light_impl->dwLightIndex = i; 744 This->num_lights++; 745 This->map_lights |= 1<<i; 746 747 /* Add the light in the 'linked' chain */ 748 list_add_head(&This->light_list, &light_impl->entry); 749 IDirect3DLight_AddRef(lpDirect3DLight); 750 751 /* Attach the light to the viewport */ 752 light_impl->active_viewport = This; 753 754 /* If active, activate the light */ 755 if (This->active_device && light_impl->light.dwFlags & D3DLIGHT_ACTIVE) 756 { 757 /* Disable the flag so that light_activate actually does its job. */ 758 light_impl->light.dwFlags &= ~D3DLIGHT_ACTIVE; 759 light_activate(light_impl); 760 } 761 762 wined3d_mutex_unlock(); 763 764 return D3D_OK; 765 } 766 767 /***************************************************************************** 768 * IDirect3DViewport3::DeleteLight 769 * 770 * Deletes a light from the viewports' light list 771 * 772 * Params: 773 * lpDirect3DLight: Light to delete 774 * 775 * Returns: 776 * D3D_OK on success 777 * DDERR_INVALIDPARAMS if the light wasn't found 778 * 779 *****************************************************************************/ 780 static HRESULT WINAPI d3d_viewport_DeleteLight(IDirect3DViewport3 *iface, IDirect3DLight *lpDirect3DLight) 781 { 782 struct d3d_viewport *viewport = impl_from_IDirect3DViewport3(iface); 783 struct d3d_light *l = unsafe_impl_from_IDirect3DLight(lpDirect3DLight); 784 785 TRACE("iface %p, light %p.\n", iface, lpDirect3DLight); 786 787 wined3d_mutex_lock(); 788 789 if (l->active_viewport != viewport) 790 { 791 WARN("Light %p active viewport is %p.\n", l, l->active_viewport); 792 wined3d_mutex_unlock(); 793 return DDERR_INVALIDPARAMS; 794 } 795 796 light_deactivate(l); 797 list_remove(&l->entry); 798 l->active_viewport = NULL; 799 IDirect3DLight_Release(lpDirect3DLight); 800 --viewport->num_lights; 801 viewport->map_lights &= ~(1 << l->dwLightIndex); 802 803 wined3d_mutex_unlock(); 804 805 return D3D_OK; 806 } 807 808 /***************************************************************************** 809 * IDirect3DViewport::NextLight 810 * 811 * Enumerates the lights associated with the viewport 812 * 813 * Params: 814 * lpDirect3DLight: Light to start with 815 * lplpDirect3DLight: Address to store the successor to 816 * 817 * Returns: 818 * D3D_OK, because it's a stub 819 * 820 *****************************************************************************/ 821 static HRESULT WINAPI d3d_viewport_NextLight(IDirect3DViewport3 *iface, 822 IDirect3DLight *lpDirect3DLight, IDirect3DLight **lplpDirect3DLight, DWORD flags) 823 { 824 struct d3d_viewport *viewport = impl_from_IDirect3DViewport3(iface); 825 struct d3d_light *l = unsafe_impl_from_IDirect3DLight(lpDirect3DLight); 826 struct list *entry; 827 HRESULT hr; 828 829 TRACE("iface %p, light %p, next_light %p, flags %#x.\n", 830 iface, lpDirect3DLight, lplpDirect3DLight, flags); 831 832 if (!lplpDirect3DLight) 833 return DDERR_INVALIDPARAMS; 834 835 wined3d_mutex_lock(); 836 837 switch (flags) 838 { 839 case D3DNEXT_NEXT: 840 if (!l || l->active_viewport != viewport) 841 { 842 if (l) 843 WARN("Light %p active viewport is %p.\n", l, l->active_viewport); 844 entry = NULL; 845 } 846 else 847 entry = list_next(&viewport->light_list, &l->entry); 848 break; 849 850 case D3DNEXT_HEAD: 851 entry = list_head(&viewport->light_list); 852 break; 853 854 case D3DNEXT_TAIL: 855 entry = list_tail(&viewport->light_list); 856 break; 857 858 default: 859 entry = NULL; 860 WARN("Invalid flags %#x.\n", flags); 861 break; 862 } 863 864 if (entry) 865 { 866 *lplpDirect3DLight = (IDirect3DLight *)LIST_ENTRY(entry, struct d3d_light, entry); 867 IDirect3DLight_AddRef(*lplpDirect3DLight); 868 hr = D3D_OK; 869 } 870 else 871 { 872 *lplpDirect3DLight = NULL; 873 hr = DDERR_INVALIDPARAMS; 874 } 875 876 wined3d_mutex_unlock(); 877 878 return hr; 879 } 880 881 /***************************************************************************** 882 * IDirect3DViewport2 Methods. 883 *****************************************************************************/ 884 885 /***************************************************************************** 886 * IDirect3DViewport3::GetViewport2 887 * 888 * Returns the currently set viewport in a D3DVIEWPORT2 structure. 889 * Similar to IDirect3DViewport3::GetViewport 890 * 891 * Params: 892 * lpData: Pointer to the structure to fill 893 * 894 * Returns: 895 * D3D_OK on success 896 * DDERR_INVALIDPARAMS if the viewport was set with 897 * IDirect3DViewport3::SetViewport 898 * DDERR_INVALIDPARAMS if Data is NULL 899 * 900 *****************************************************************************/ 901 static HRESULT WINAPI d3d_viewport_GetViewport2(IDirect3DViewport3 *iface, D3DVIEWPORT2 *lpData) 902 { 903 struct d3d_viewport *This = impl_from_IDirect3DViewport3(iface); 904 DWORD dwSize; 905 906 TRACE("iface %p, data %p.\n", iface, lpData); 907 908 wined3d_mutex_lock(); 909 dwSize = lpData->dwSize; 910 if (This->use_vp2) 911 memcpy(lpData, &(This->viewports.vp2), dwSize); 912 else { 913 D3DVIEWPORT2 vp2; 914 vp2.dwSize = sizeof(vp2); 915 vp2.dwX = This->viewports.vp1.dwX; 916 vp2.dwY = This->viewports.vp1.dwY; 917 vp2.dwWidth = This->viewports.vp1.dwWidth; 918 vp2.dwHeight = This->viewports.vp1.dwHeight; 919 vp2.dvClipX = 0.0; 920 vp2.dvClipY = 0.0; 921 vp2.dvClipWidth = 0.0; 922 vp2.dvClipHeight = 0.0; 923 vp2.dvMinZ = This->viewports.vp1.dvMinZ; 924 vp2.dvMaxZ = This->viewports.vp1.dvMaxZ; 925 memcpy(lpData, &vp2, dwSize); 926 } 927 928 if (TRACE_ON(ddraw)) 929 { 930 TRACE(" returning D3DVIEWPORT2 :\n"); 931 _dump_D3DVIEWPORT2(lpData); 932 } 933 934 wined3d_mutex_unlock(); 935 936 return D3D_OK; 937 } 938 939 /***************************************************************************** 940 * IDirect3DViewport3::SetViewport2 941 * 942 * Sets the viewport from a D3DVIEWPORT2 structure 943 * 944 * Params: 945 * lpData: Viewport to set 946 * 947 * Returns: 948 * D3D_OK on success 949 * 950 *****************************************************************************/ 951 static HRESULT WINAPI d3d_viewport_SetViewport2(IDirect3DViewport3 *iface, D3DVIEWPORT2 *lpData) 952 { 953 struct d3d_viewport *This = impl_from_IDirect3DViewport3(iface); 954 IDirect3DViewport3 *current_viewport; 955 956 TRACE("iface %p, data %p.\n", iface, lpData); 957 958 if (TRACE_ON(ddraw)) 959 { 960 TRACE(" getting D3DVIEWPORT2 :\n"); 961 _dump_D3DVIEWPORT2(lpData); 962 } 963 964 wined3d_mutex_lock(); 965 966 This->use_vp2 = 1; 967 memset(&(This->viewports.vp2), 0, sizeof(This->viewports.vp2)); 968 memcpy(&(This->viewports.vp2), lpData, lpData->dwSize); 969 970 if (This->active_device) 971 { 972 IDirect3DDevice3 *d3d_device3 = &This->active_device->IDirect3DDevice3_iface; 973 if (SUCCEEDED(IDirect3DDevice3_GetCurrentViewport(d3d_device3, ¤t_viewport))) 974 { 975 if (current_viewport == iface) viewport_activate(This, FALSE); 976 IDirect3DViewport3_Release(current_viewport); 977 } 978 } 979 980 wined3d_mutex_unlock(); 981 982 return D3D_OK; 983 } 984 985 /***************************************************************************** 986 * IDirect3DViewport3 Methods. 987 *****************************************************************************/ 988 989 /***************************************************************************** 990 * IDirect3DViewport3::SetBackgroundDepth2 991 * 992 * Sets a IDirectDrawSurface4 surface as the background depth surface 993 * 994 * Params: 995 * lpDDS: Surface to set 996 * 997 * Returns: 998 * D3D_OK, because it's stub 999 * 1000 *****************************************************************************/ 1001 static HRESULT WINAPI d3d_viewport_SetBackgroundDepth2(IDirect3DViewport3 *iface, 1002 IDirectDrawSurface4 *surface) 1003 { 1004 FIXME("iface %p, surface %p stub!\n", iface, surface); 1005 1006 return D3D_OK; 1007 } 1008 1009 /***************************************************************************** 1010 * IDirect3DViewport3::GetBackgroundDepth2 1011 * 1012 * Returns the IDirect3DSurface4 interface to the background depth surface 1013 * 1014 * Params: 1015 * lplpDDS: Address to store the interface pointer at 1016 * lpValid: Set to true if a surface is assigned 1017 * 1018 * Returns: 1019 * D3D_OK because it's a stub 1020 * 1021 *****************************************************************************/ 1022 static HRESULT WINAPI d3d_viewport_GetBackgroundDepth2(IDirect3DViewport3 *iface, 1023 IDirectDrawSurface4 **surface, BOOL *valid) 1024 { 1025 FIXME("iface %p, surface %p, valid %p stub!\n", iface, surface, valid); 1026 1027 return D3D_OK; 1028 } 1029 1030 /***************************************************************************** 1031 * IDirect3DViewport3::Clear2 1032 * 1033 * Another clearing method 1034 * 1035 * Params: 1036 * Count: Number of rectangles to clear 1037 * Rects: Rectangle array to clear 1038 * Flags: Some flags :) 1039 * Color: Color to fill the render target with 1040 * Z: Value to fill the depth buffer with 1041 * Stencil: Value to fill the stencil bits with 1042 * 1043 * Returns: 1044 * 1045 *****************************************************************************/ 1046 static HRESULT WINAPI d3d_viewport_Clear2(IDirect3DViewport3 *iface, DWORD rect_count, 1047 D3DRECT *rects, DWORD flags, DWORD color, D3DVALUE depth, DWORD stencil) 1048 { 1049 struct d3d_viewport *viewport = impl_from_IDirect3DViewport3(iface); 1050 HRESULT hr; 1051 IDirect3DViewport3 *current_viewport; 1052 IDirect3DDevice3 *d3d_device3; 1053 1054 TRACE("iface %p, rect_count %u, rects %p, flags %#x, color 0x%08x, depth %.8e, stencil %u.\n", 1055 iface, rect_count, rects, flags, color, depth, stencil); 1056 1057 if (!rects || !rect_count) 1058 { 1059 WARN("rect_count = %u, rects = %p, ignoring clear\n", rect_count, rects); 1060 return D3D_OK; 1061 } 1062 1063 wined3d_mutex_lock(); 1064 1065 if (!viewport->active_device) 1066 { 1067 WARN("Trying to clear a viewport not attached to a device.\n"); 1068 wined3d_mutex_unlock(); 1069 return D3DERR_VIEWPORTHASNODEVICE; 1070 } 1071 d3d_device3 = &viewport->active_device->IDirect3DDevice3_iface; 1072 /* Need to temporarily activate viewport to clear it. Previously active 1073 * one will be restored afterwards. */ 1074 viewport_activate(viewport, TRUE); 1075 1076 hr = IDirect3DDevice7_Clear(&viewport->active_device->IDirect3DDevice7_iface, 1077 rect_count, rects, flags, color, depth, stencil); 1078 if (SUCCEEDED(IDirect3DDevice3_GetCurrentViewport(d3d_device3, ¤t_viewport))) 1079 { 1080 struct d3d_viewport *vp = impl_from_IDirect3DViewport3(current_viewport); 1081 viewport_activate(vp, TRUE); 1082 IDirect3DViewport3_Release(current_viewport); 1083 } 1084 1085 wined3d_mutex_unlock(); 1086 1087 return hr; 1088 } 1089 1090 /***************************************************************************** 1091 * The VTable 1092 *****************************************************************************/ 1093 1094 static const struct IDirect3DViewport3Vtbl d3d_viewport_vtbl = 1095 { 1096 /*** IUnknown Methods ***/ 1097 d3d_viewport_QueryInterface, 1098 d3d_viewport_AddRef, 1099 d3d_viewport_Release, 1100 /*** IDirect3DViewport Methods */ 1101 d3d_viewport_Initialize, 1102 d3d_viewport_GetViewport, 1103 d3d_viewport_SetViewport, 1104 d3d_viewport_TransformVertices, 1105 d3d_viewport_LightElements, 1106 d3d_viewport_SetBackground, 1107 d3d_viewport_GetBackground, 1108 d3d_viewport_SetBackgroundDepth, 1109 d3d_viewport_GetBackgroundDepth, 1110 d3d_viewport_Clear, 1111 d3d_viewport_AddLight, 1112 d3d_viewport_DeleteLight, 1113 d3d_viewport_NextLight, 1114 /*** IDirect3DViewport2 Methods ***/ 1115 d3d_viewport_GetViewport2, 1116 d3d_viewport_SetViewport2, 1117 /*** IDirect3DViewport3 Methods ***/ 1118 d3d_viewport_SetBackgroundDepth2, 1119 d3d_viewport_GetBackgroundDepth2, 1120 d3d_viewport_Clear2, 1121 }; 1122 1123 struct d3d_viewport *unsafe_impl_from_IDirect3DViewport3(IDirect3DViewport3 *iface) 1124 { 1125 if (!iface) return NULL; 1126 assert(iface->lpVtbl == &d3d_viewport_vtbl); 1127 return CONTAINING_RECORD(iface, struct d3d_viewport, IDirect3DViewport3_iface); 1128 } 1129 1130 struct d3d_viewport *unsafe_impl_from_IDirect3DViewport2(IDirect3DViewport2 *iface) 1131 { 1132 /* IDirect3DViewport and IDirect3DViewport3 use the same iface. */ 1133 if (!iface) return NULL; 1134 assert(iface->lpVtbl == (IDirect3DViewport2Vtbl *)&d3d_viewport_vtbl); 1135 return CONTAINING_RECORD((IDirect3DViewport3 *)iface, struct d3d_viewport, IDirect3DViewport3_iface); 1136 } 1137 1138 struct d3d_viewport *unsafe_impl_from_IDirect3DViewport(IDirect3DViewport *iface) 1139 { 1140 /* IDirect3DViewport and IDirect3DViewport3 use the same iface. */ 1141 if (!iface) return NULL; 1142 assert(iface->lpVtbl == (IDirect3DViewportVtbl *)&d3d_viewport_vtbl); 1143 return CONTAINING_RECORD((IDirect3DViewport3 *)iface, struct d3d_viewport, IDirect3DViewport3_iface); 1144 } 1145 1146 void d3d_viewport_init(struct d3d_viewport *viewport, struct ddraw *ddraw) 1147 { 1148 viewport->IDirect3DViewport3_iface.lpVtbl = &d3d_viewport_vtbl; 1149 viewport->ref = 1; 1150 viewport->ddraw = ddraw; 1151 viewport->use_vp2 = 0xff; 1152 list_init(&viewport->light_list); 1153 } 1154