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 static HRESULT WINAPI d3d_viewport_GetViewport(IDirect3DViewport3 *iface, D3DVIEWPORT *vp) 253 { 254 struct d3d_viewport *viewport = impl_from_IDirect3DViewport3(iface); 255 DWORD size; 256 257 TRACE("iface %p, vp %p.\n", iface, vp); 258 259 if (!vp) 260 return DDERR_INVALIDPARAMS; 261 262 wined3d_mutex_lock(); 263 264 size = vp->dwSize; 265 if (!viewport->use_vp2) 266 { 267 memcpy(vp, &viewport->viewports.vp1, size); 268 } 269 else 270 { 271 D3DVIEWPORT vp1; 272 273 vp1.dwSize = sizeof(vp1); 274 vp1.dwX = viewport->viewports.vp2.dwX; 275 vp1.dwY = viewport->viewports.vp2.dwY; 276 vp1.dwWidth = viewport->viewports.vp2.dwWidth; 277 vp1.dwHeight = viewport->viewports.vp2.dwHeight; 278 vp1.dvMaxX = 0.0; 279 vp1.dvMaxY = 0.0; 280 vp1.dvScaleX = 0.0; 281 vp1.dvScaleY = 0.0; 282 vp1.dvMinZ = viewport->viewports.vp2.dvMinZ; 283 vp1.dvMaxZ = viewport->viewports.vp2.dvMaxZ; 284 memcpy(vp, &vp1, size); 285 } 286 287 if (TRACE_ON(ddraw)) 288 { 289 TRACE(" returning D3DVIEWPORT :\n"); 290 _dump_D3DVIEWPORT(vp); 291 } 292 293 wined3d_mutex_unlock(); 294 295 return D3D_OK; 296 } 297 298 static HRESULT WINAPI d3d_viewport_SetViewport(IDirect3DViewport3 *iface, D3DVIEWPORT *vp) 299 { 300 struct d3d_viewport *viewport = impl_from_IDirect3DViewport3(iface); 301 struct d3d_device *device = viewport->active_device; 302 struct wined3d_sub_resource_desc rt_desc; 303 struct wined3d_rendertarget_view *rtv; 304 IDirect3DViewport3 *current_viewport; 305 struct ddraw_surface *surface; 306 307 TRACE("iface %p, vp %p.\n", iface, vp); 308 309 if (!vp) 310 return DDERR_INVALIDPARAMS; 311 312 if (TRACE_ON(ddraw)) 313 { 314 TRACE(" getting D3DVIEWPORT :\n"); 315 _dump_D3DVIEWPORT(vp); 316 } 317 318 if (!device) 319 { 320 WARN("Viewport not bound to a device, returning D3DERR_VIEWPORTHASNODEVICE.\n"); 321 return D3DERR_VIEWPORTHASNODEVICE; 322 } 323 324 wined3d_mutex_lock(); 325 326 if (device->version > 1) 327 { 328 if (!(rtv = wined3d_device_get_rendertarget_view(device->wined3d_device, 0))) 329 { 330 wined3d_mutex_unlock(); 331 return DDERR_INVALIDCAPS; 332 } 333 surface = wined3d_rendertarget_view_get_sub_resource_parent(rtv); 334 wined3d_texture_get_sub_resource_desc(surface->wined3d_texture, surface->sub_resource_idx, &rt_desc); 335 336 if (vp->dwX > rt_desc.width || vp->dwWidth > rt_desc.width - vp->dwX 337 || vp->dwY > rt_desc.height || vp->dwHeight > rt_desc.height - vp->dwY) 338 { 339 WARN("Invalid viewport, returning DDERR_INVALIDPARAMS.\n"); 340 wined3d_mutex_unlock(); 341 return DDERR_INVALIDPARAMS; 342 } 343 } 344 345 viewport->use_vp2 = 0; 346 memset(&viewport->viewports.vp1, 0, sizeof(viewport->viewports.vp1)); 347 memcpy(&viewport->viewports.vp1, vp, vp->dwSize); 348 349 /* Empirical testing on a couple of d3d1 games showed that these values 350 * should be ignored. */ 351 viewport->viewports.vp1.dvMinZ = 0.0; 352 viewport->viewports.vp1.dvMaxZ = 1.0; 353 354 if (SUCCEEDED(IDirect3DDevice3_GetCurrentViewport(&device->IDirect3DDevice3_iface, ¤t_viewport))) 355 { 356 if (current_viewport == iface) 357 viewport_activate(viewport, FALSE); 358 IDirect3DViewport3_Release(current_viewport); 359 } 360 361 wined3d_mutex_unlock(); 362 363 return D3D_OK; 364 } 365 366 /***************************************************************************** 367 * IDirect3DViewport3::TransformVertices 368 * 369 * Transforms vertices by the transformation matrix. 370 * 371 * This function is pretty similar to IDirect3DVertexBuffer7::ProcessVertices, 372 * so it's tempting to forward it to there. However, there are some 373 * tiny differences. First, the lpOffscreen flag that is reported back, 374 * then there is the homogeneous vertex that is generated. Also there's a lack 375 * of FVFs, but still a custom stride. Last, the d3d1 - d3d3 viewport has some 376 * settings (scale) that d3d7 and wined3d do not have. All in all wrapping to 377 * ProcessVertices doesn't pay of in terms of wrapper code needed and code 378 * reused. 379 * 380 * Params: 381 * dwVertexCount: The number of vertices to be transformed 382 * data: Pointer to the vertex input / output data. 383 * dwFlags: D3DTRANSFORM_CLIPPED or D3DTRANSFORM_UNCLIPPED 384 * offscreen: Logical AND of the planes that clipped the vertices if clipping 385 * is on. 0 if clipping is off. 386 * 387 * Returns: 388 * D3D_OK on success 389 * D3DERR_VIEWPORTHASNODEVICE if the viewport is not assigned to a device 390 * DDERR_INVALIDPARAMS if no clipping flag is specified 391 * 392 *****************************************************************************/ 393 struct transform_vertices_vertex 394 { 395 float x, y, z, w; /* w is unused in input data. */ 396 struct 397 { 398 DWORD p[4]; 399 } payload; 400 }; 401 402 static HRESULT WINAPI d3d_viewport_TransformVertices(IDirect3DViewport3 *iface, 403 DWORD dwVertexCount, D3DTRANSFORMDATA *data, DWORD dwFlags, DWORD *offscreen) 404 { 405 struct d3d_viewport *viewport = impl_from_IDirect3DViewport3(iface); 406 D3DVIEWPORT vp = viewport->viewports.vp1; 407 D3DMATRIX view_mat, world_mat, proj_mat, mat; 408 struct transform_vertices_vertex *in, *out; 409 float x, y, z, w; 410 unsigned int i; 411 D3DHVERTEX *outH; 412 struct d3d_device *device = viewport->active_device; 413 BOOL activate = device->current_viewport != viewport; 414 415 TRACE("iface %p, vertex_count %u, data %p, flags %#x, offscreen %p.\n", 416 iface, dwVertexCount, data, dwFlags, offscreen); 417 418 /* Tests on windows show that Windows crashes when this occurs, 419 * so don't return the (intuitive) return value 420 if (!device) 421 { 422 WARN("No device active, returning D3DERR_VIEWPORTHASNODEVICE\n"); 423 return D3DERR_VIEWPORTHASNODEVICE; 424 } 425 */ 426 427 if (!data || data->dwSize != sizeof(*data)) 428 { 429 WARN("Transform data is NULL or size is incorrect, returning DDERR_INVALIDPARAMS\n"); 430 return DDERR_INVALIDPARAMS; 431 } 432 if (!(dwFlags & (D3DTRANSFORM_UNCLIPPED | D3DTRANSFORM_CLIPPED))) 433 { 434 WARN("No clipping flag passed, returning DDERR_INVALIDPARAMS\n"); 435 return DDERR_INVALIDPARAMS; 436 } 437 438 wined3d_mutex_lock(); 439 if (activate) 440 viewport_activate(viewport, TRUE); 441 442 wined3d_device_get_transform(device->wined3d_device, 443 D3DTRANSFORMSTATE_VIEW, (struct wined3d_matrix *)&view_mat); 444 wined3d_device_get_transform(device->wined3d_device, 445 WINED3D_TS_WORLD_MATRIX(0), (struct wined3d_matrix *)&world_mat); 446 wined3d_device_get_transform(device->wined3d_device, 447 WINED3D_TS_PROJECTION, (struct wined3d_matrix *)&proj_mat); 448 multiply_matrix(&mat, &view_mat, &world_mat); 449 multiply_matrix(&mat, &proj_mat, &mat); 450 451 /* The pointer is not tested against NULL on Windows. */ 452 if (dwFlags & D3DTRANSFORM_CLIPPED) 453 *offscreen = ~0U; 454 else 455 *offscreen = 0; 456 457 outH = data->lpHOut; 458 for(i = 0; i < dwVertexCount; i++) 459 { 460 in = (struct transform_vertices_vertex *)((char *)data->lpIn + data->dwInSize * i); 461 out = (struct transform_vertices_vertex *)((char *)data->lpOut + data->dwOutSize * i); 462 463 x = (in->x * mat._11) + (in->y * mat._21) + (in->z * mat._31) + mat._41; 464 y = (in->x * mat._12) + (in->y * mat._22) + (in->z * mat._32) + mat._42; 465 z = (in->x * mat._13) + (in->y * mat._23) + (in->z * mat._33) + mat._43; 466 w = (in->x * mat._14) + (in->y * mat._24) + (in->z * mat._34) + mat._44; 467 468 if(dwFlags & D3DTRANSFORM_CLIPPED) 469 { 470 /* If clipping is enabled, Windows assumes that outH is 471 * a valid pointer. */ 472 outH[i].u1.hx = (x - device->legacy_clipspace._41 * w) / device->legacy_clipspace._11; 473 outH[i].u2.hy = (y - device->legacy_clipspace._42 * w) / device->legacy_clipspace._22; 474 outH[i].u3.hz = (z - device->legacy_clipspace._43 * w) / device->legacy_clipspace._33; 475 476 outH[i].dwFlags = 0; 477 if (x > w) 478 outH[i].dwFlags |= D3DCLIP_RIGHT; 479 if (x < -w) 480 outH[i].dwFlags |= D3DCLIP_LEFT; 481 if (y > w) 482 outH[i].dwFlags |= D3DCLIP_TOP; 483 if (y < -w) 484 outH[i].dwFlags |= D3DCLIP_BOTTOM; 485 if (z < 0.0f) 486 outH[i].dwFlags |= D3DCLIP_FRONT; 487 if (z > w) 488 outH[i].dwFlags |= D3DCLIP_BACK; 489 490 *offscreen &= outH[i].dwFlags; 491 492 if(outH[i].dwFlags) 493 { 494 /* Looks like native just drops the vertex, leaves whatever data 495 * it has in the output buffer and goes on with the next vertex. 496 * The exact scheme hasn't been figured out yet, but windows 497 * definitely writes something there. 498 */ 499 out->x = x; 500 out->y = y; 501 out->z = z; 502 out->w = w; 503 continue; 504 } 505 } 506 507 w = 1 / w; 508 x *= w; y *= w; z *= w; 509 510 out->x = (x + 1.0f) * vp.dwWidth * 0.5 + vp.dwX; 511 out->y = (-y + 1.0f) * vp.dwHeight * 0.5 + vp.dwY; 512 out->z = z; 513 out->w = w; 514 out->payload = in->payload; 515 } 516 517 if (activate && device->current_viewport) 518 viewport_activate(device->current_viewport, TRUE); 519 520 wined3d_mutex_unlock(); 521 522 TRACE("All done\n"); 523 return DD_OK; 524 } 525 526 /***************************************************************************** 527 * IDirect3DViewport3::LightElements 528 * 529 * The DirectX 5.0 sdk says that it's not implemented 530 * 531 * Params: 532 * ? 533 * 534 * Returns: 535 * DDERR_UNSUPPORTED 536 * 537 *****************************************************************************/ 538 static HRESULT WINAPI d3d_viewport_LightElements(IDirect3DViewport3 *iface, 539 DWORD element_count, D3DLIGHTDATA *data) 540 { 541 TRACE("iface %p, element_count %u, data %p.\n", iface, element_count, data); 542 543 return DDERR_UNSUPPORTED; 544 } 545 546 static HRESULT WINAPI d3d_viewport_SetBackground(IDirect3DViewport3 *iface, D3DMATERIALHANDLE material) 547 { 548 struct d3d_viewport *viewport = impl_from_IDirect3DViewport3(iface); 549 struct d3d_material *m; 550 551 TRACE("iface %p, material %#x.\n", iface, material); 552 553 wined3d_mutex_lock(); 554 555 if (!(m = ddraw_get_object(&viewport->ddraw->d3ddevice->handle_table, material - 1, DDRAW_HANDLE_MATERIAL))) 556 { 557 WARN("Invalid material handle %#x.\n", material); 558 wined3d_mutex_unlock(); 559 return DDERR_INVALIDPARAMS; 560 } 561 562 TRACE("Setting background color : %.8e %.8e %.8e %.8e.\n", 563 m->mat.u.diffuse.u1.r, m->mat.u.diffuse.u2.g, 564 m->mat.u.diffuse.u3.b, m->mat.u.diffuse.u4.a); 565 viewport->background = m; 566 567 wined3d_mutex_unlock(); 568 569 return D3D_OK; 570 } 571 572 /***************************************************************************** 573 * IDirect3DViewport3::GetBackground 574 * 575 * Returns the material handle assigned to the background of the viewport 576 * 577 * Params: 578 * lphMat: Address to store the handle 579 * lpValid: is set to FALSE if no background is set, TRUE if one is set 580 * 581 * Returns: 582 * D3D_OK 583 * 584 *****************************************************************************/ 585 static HRESULT WINAPI d3d_viewport_GetBackground(IDirect3DViewport3 *iface, 586 D3DMATERIALHANDLE *material, BOOL *valid) 587 { 588 struct d3d_viewport *viewport = impl_from_IDirect3DViewport3(iface); 589 590 TRACE("iface %p, material %p, valid %p.\n", iface, material, valid); 591 592 wined3d_mutex_lock(); 593 if (valid) 594 *valid = !!viewport->background; 595 if (material) 596 *material = viewport->background ? viewport->background->Handle : 0; 597 wined3d_mutex_unlock(); 598 599 return D3D_OK; 600 } 601 602 /***************************************************************************** 603 * IDirect3DViewport3::SetBackgroundDepth 604 * 605 * Sets a surface that represents the background depth. Its contents are 606 * used to set the depth buffer in IDirect3DViewport3::Clear 607 * 608 * Params: 609 * lpDDSurface: Surface to set 610 * 611 * Returns: D3D_OK, because it's a stub 612 * 613 *****************************************************************************/ 614 static HRESULT WINAPI d3d_viewport_SetBackgroundDepth(IDirect3DViewport3 *iface, IDirectDrawSurface *surface) 615 { 616 FIXME("iface %p, surface %p stub!\n", iface, surface); 617 618 return D3D_OK; 619 } 620 621 /***************************************************************************** 622 * IDirect3DViewport3::GetBackgroundDepth 623 * 624 * Returns the surface that represents the depth field 625 * 626 * Params: 627 * lplpDDSurface: Address to store the interface pointer 628 * lpValid: Set to TRUE if a depth is assigned, FALSE otherwise 629 * 630 * Returns: 631 * D3D_OK, because it's a stub 632 * (DDERR_INVALIDPARAMS if DDSurface of Valid is NULL) 633 * 634 *****************************************************************************/ 635 static HRESULT WINAPI d3d_viewport_GetBackgroundDepth(IDirect3DViewport3 *iface, 636 IDirectDrawSurface **surface, BOOL *valid) 637 { 638 FIXME("iface %p, surface %p, valid %p stub!\n", iface, surface, valid); 639 640 return DD_OK; 641 } 642 643 /***************************************************************************** 644 * IDirect3DViewport3::Clear 645 * 646 * Clears the render target and / or the z buffer 647 * 648 * Params: 649 * dwCount: The amount of rectangles to clear. If 0, the whole buffer is 650 * cleared 651 * lpRects: Pointer to the array of rectangles. If NULL, Count must be 0 652 * dwFlags: D3DCLEAR_ZBUFFER and / or D3DCLEAR_TARGET 653 * 654 * Returns: 655 * D3D_OK on success 656 * D3DERR_VIEWPORTHASNODEVICE if there's no active device 657 * The return value of IDirect3DDevice7::Clear 658 * 659 *****************************************************************************/ 660 static HRESULT WINAPI d3d_viewport_Clear(IDirect3DViewport3 *iface, 661 DWORD rect_count, D3DRECT *rects, DWORD flags) 662 { 663 struct d3d_viewport *This = impl_from_IDirect3DViewport3(iface); 664 DWORD color = 0x00000000; 665 HRESULT hr; 666 IDirect3DViewport3 *current_viewport; 667 IDirect3DDevice3 *d3d_device3; 668 669 TRACE("iface %p, rect_count %u, rects %p, flags %#x.\n", iface, rect_count, rects, flags); 670 671 if (!rects || !rect_count) 672 { 673 WARN("rect_count = %u, rects = %p, ignoring clear\n", rect_count, rects); 674 return D3D_OK; 675 } 676 677 if (This->active_device == NULL) { 678 ERR(" Trying to clear a viewport not attached to a device!\n"); 679 return D3DERR_VIEWPORTHASNODEVICE; 680 } 681 d3d_device3 = &This->active_device->IDirect3DDevice3_iface; 682 683 wined3d_mutex_lock(); 684 685 if (flags & D3DCLEAR_TARGET) 686 { 687 if (!This->background) 688 WARN("No background material set.\n"); 689 else 690 color = D3DRGBA(This->background->mat.u.diffuse.u1.r, 691 This->background->mat.u.diffuse.u2.g, 692 This->background->mat.u.diffuse.u3.b, 693 This->background->mat.u.diffuse.u4.a); 694 } 695 696 /* Need to temporarily activate the viewport to clear it. The previously 697 * active one will be restored afterwards. */ 698 viewport_activate(This, TRUE); 699 700 hr = IDirect3DDevice7_Clear(&This->active_device->IDirect3DDevice7_iface, rect_count, rects, 701 flags & (D3DCLEAR_ZBUFFER | D3DCLEAR_TARGET), color, 1.0, 0x00000000); 702 703 if (SUCCEEDED(IDirect3DDevice3_GetCurrentViewport(d3d_device3, ¤t_viewport))) 704 { 705 struct d3d_viewport *vp = impl_from_IDirect3DViewport3(current_viewport); 706 viewport_activate(vp, TRUE); 707 IDirect3DViewport3_Release(current_viewport); 708 } 709 710 wined3d_mutex_unlock(); 711 712 return hr; 713 } 714 715 /***************************************************************************** 716 * IDirect3DViewport3::AddLight 717 * 718 * Adds an light to the viewport 719 * 720 * Params: 721 * lpDirect3DLight: Interface of the light to add 722 * 723 * Returns: 724 * D3D_OK on success 725 * DDERR_INVALIDPARAMS if Direct3DLight is NULL 726 * DDERR_INVALIDPARAMS if there are 8 lights or more 727 * 728 *****************************************************************************/ 729 static HRESULT WINAPI d3d_viewport_AddLight(IDirect3DViewport3 *iface, IDirect3DLight *lpDirect3DLight) 730 { 731 struct d3d_viewport *This = impl_from_IDirect3DViewport3(iface); 732 struct d3d_light *light_impl = unsafe_impl_from_IDirect3DLight(lpDirect3DLight); 733 DWORD i = 0; 734 DWORD map = This->map_lights; 735 736 TRACE("iface %p, light %p.\n", iface, lpDirect3DLight); 737 738 wined3d_mutex_lock(); 739 740 if (This->num_lights >= 8) 741 { 742 wined3d_mutex_unlock(); 743 return DDERR_INVALIDPARAMS; 744 } 745 746 /* Find a light number and update both light and viewports objects accordingly */ 747 while (map & 1) 748 { 749 map >>= 1; 750 ++i; 751 } 752 light_impl->dwLightIndex = i; 753 This->num_lights++; 754 This->map_lights |= 1<<i; 755 756 /* Add the light in the 'linked' chain */ 757 list_add_head(&This->light_list, &light_impl->entry); 758 IDirect3DLight_AddRef(lpDirect3DLight); 759 760 /* Attach the light to the viewport */ 761 light_impl->active_viewport = This; 762 763 /* If active, activate the light */ 764 if (This->active_device && light_impl->light.dwFlags & D3DLIGHT_ACTIVE) 765 { 766 /* Disable the flag so that light_activate actually does its job. */ 767 light_impl->light.dwFlags &= ~D3DLIGHT_ACTIVE; 768 light_activate(light_impl); 769 } 770 771 wined3d_mutex_unlock(); 772 773 return D3D_OK; 774 } 775 776 /***************************************************************************** 777 * IDirect3DViewport3::DeleteLight 778 * 779 * Deletes a light from the viewports' light list 780 * 781 * Params: 782 * lpDirect3DLight: Light to delete 783 * 784 * Returns: 785 * D3D_OK on success 786 * DDERR_INVALIDPARAMS if the light wasn't found 787 * 788 *****************************************************************************/ 789 static HRESULT WINAPI d3d_viewport_DeleteLight(IDirect3DViewport3 *iface, IDirect3DLight *lpDirect3DLight) 790 { 791 struct d3d_viewport *viewport = impl_from_IDirect3DViewport3(iface); 792 struct d3d_light *l = unsafe_impl_from_IDirect3DLight(lpDirect3DLight); 793 794 TRACE("iface %p, light %p.\n", iface, lpDirect3DLight); 795 796 wined3d_mutex_lock(); 797 798 if (l->active_viewport != viewport) 799 { 800 WARN("Light %p active viewport is %p.\n", l, l->active_viewport); 801 wined3d_mutex_unlock(); 802 return DDERR_INVALIDPARAMS; 803 } 804 805 light_deactivate(l); 806 list_remove(&l->entry); 807 l->active_viewport = NULL; 808 IDirect3DLight_Release(lpDirect3DLight); 809 --viewport->num_lights; 810 viewport->map_lights &= ~(1 << l->dwLightIndex); 811 812 wined3d_mutex_unlock(); 813 814 return D3D_OK; 815 } 816 817 /***************************************************************************** 818 * IDirect3DViewport::NextLight 819 * 820 * Enumerates the lights associated with the viewport 821 * 822 * Params: 823 * lpDirect3DLight: Light to start with 824 * lplpDirect3DLight: Address to store the successor to 825 * 826 * Returns: 827 * D3D_OK, because it's a stub 828 * 829 *****************************************************************************/ 830 static HRESULT WINAPI d3d_viewport_NextLight(IDirect3DViewport3 *iface, 831 IDirect3DLight *lpDirect3DLight, IDirect3DLight **lplpDirect3DLight, DWORD flags) 832 { 833 struct d3d_viewport *viewport = impl_from_IDirect3DViewport3(iface); 834 struct d3d_light *l = unsafe_impl_from_IDirect3DLight(lpDirect3DLight); 835 struct list *entry; 836 HRESULT hr; 837 838 TRACE("iface %p, light %p, next_light %p, flags %#x.\n", 839 iface, lpDirect3DLight, lplpDirect3DLight, flags); 840 841 if (!lplpDirect3DLight) 842 return DDERR_INVALIDPARAMS; 843 844 wined3d_mutex_lock(); 845 846 switch (flags) 847 { 848 case D3DNEXT_NEXT: 849 if (!l || l->active_viewport != viewport) 850 { 851 if (l) 852 WARN("Light %p active viewport is %p.\n", l, l->active_viewport); 853 entry = NULL; 854 } 855 else 856 entry = list_next(&viewport->light_list, &l->entry); 857 break; 858 859 case D3DNEXT_HEAD: 860 entry = list_head(&viewport->light_list); 861 break; 862 863 case D3DNEXT_TAIL: 864 entry = list_tail(&viewport->light_list); 865 break; 866 867 default: 868 entry = NULL; 869 WARN("Invalid flags %#x.\n", flags); 870 break; 871 } 872 873 if (entry) 874 { 875 *lplpDirect3DLight = (IDirect3DLight *)LIST_ENTRY(entry, struct d3d_light, entry); 876 IDirect3DLight_AddRef(*lplpDirect3DLight); 877 hr = D3D_OK; 878 } 879 else 880 { 881 *lplpDirect3DLight = NULL; 882 hr = DDERR_INVALIDPARAMS; 883 } 884 885 wined3d_mutex_unlock(); 886 887 return hr; 888 } 889 890 /***************************************************************************** 891 * IDirect3DViewport2 Methods. 892 *****************************************************************************/ 893 894 static HRESULT WINAPI d3d_viewport_GetViewport2(IDirect3DViewport3 *iface, D3DVIEWPORT2 *vp) 895 { 896 struct d3d_viewport *viewport = impl_from_IDirect3DViewport3(iface); 897 DWORD size; 898 899 TRACE("iface %p, vp %p.\n", iface, vp); 900 901 if (!vp) 902 return DDERR_INVALIDPARAMS; 903 904 wined3d_mutex_lock(); 905 size = vp->dwSize; 906 if (viewport->use_vp2) 907 { 908 memcpy(vp, &viewport->viewports.vp2, size); 909 } 910 else 911 { 912 D3DVIEWPORT2 vp2; 913 914 vp2.dwSize = sizeof(vp2); 915 vp2.dwX = viewport->viewports.vp1.dwX; 916 vp2.dwY = viewport->viewports.vp1.dwY; 917 vp2.dwWidth = viewport->viewports.vp1.dwWidth; 918 vp2.dwHeight = viewport->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 = viewport->viewports.vp1.dvMinZ; 924 vp2.dvMaxZ = viewport->viewports.vp1.dvMaxZ; 925 memcpy(vp, &vp2, size); 926 } 927 928 if (TRACE_ON(ddraw)) 929 { 930 TRACE(" returning D3DVIEWPORT2 :\n"); 931 _dump_D3DVIEWPORT2(vp); 932 } 933 934 wined3d_mutex_unlock(); 935 936 return D3D_OK; 937 } 938 939 static HRESULT WINAPI d3d_viewport_SetViewport2(IDirect3DViewport3 *iface, D3DVIEWPORT2 *vp) 940 { 941 struct d3d_viewport *viewport = impl_from_IDirect3DViewport3(iface); 942 struct d3d_device *device = viewport->active_device; 943 struct wined3d_sub_resource_desc rt_desc; 944 struct wined3d_rendertarget_view *rtv; 945 IDirect3DViewport3 *current_viewport; 946 struct ddraw_surface *surface; 947 948 TRACE("iface %p, vp %p.\n", iface, vp); 949 950 if (!vp) 951 return DDERR_INVALIDPARAMS; 952 953 if (TRACE_ON(ddraw)) 954 { 955 TRACE(" getting D3DVIEWPORT2 :\n"); 956 _dump_D3DVIEWPORT2(vp); 957 } 958 959 if (!device) 960 { 961 WARN("Viewport not bound to a device, returning D3DERR_VIEWPORTHASNODEVICE.\n"); 962 return D3DERR_VIEWPORTHASNODEVICE; 963 } 964 965 wined3d_mutex_lock(); 966 967 if (device->version > 1) 968 { 969 if (!(rtv = wined3d_device_get_rendertarget_view(device->wined3d_device, 0))) 970 { 971 wined3d_mutex_unlock(); 972 return DDERR_INVALIDCAPS; 973 } 974 surface = wined3d_rendertarget_view_get_sub_resource_parent(rtv); 975 wined3d_texture_get_sub_resource_desc(surface->wined3d_texture, surface->sub_resource_idx, &rt_desc); 976 977 if (vp->dwX > rt_desc.width || vp->dwWidth > rt_desc.width - vp->dwX 978 || vp->dwY > rt_desc.height || vp->dwHeight > rt_desc.height - vp->dwY) 979 { 980 WARN("Invalid viewport, returning DDERR_INVALIDPARAMS.\n"); 981 wined3d_mutex_unlock(); 982 return DDERR_INVALIDPARAMS; 983 } 984 } 985 986 viewport->use_vp2 = 1; 987 memset(&viewport->viewports.vp2, 0, sizeof(viewport->viewports.vp2)); 988 memcpy(&viewport->viewports.vp2, vp, vp->dwSize); 989 990 if (SUCCEEDED(IDirect3DDevice3_GetCurrentViewport(&device->IDirect3DDevice3_iface, ¤t_viewport))) 991 { 992 if (current_viewport == iface) 993 viewport_activate(viewport, FALSE); 994 IDirect3DViewport3_Release(current_viewport); 995 } 996 997 wined3d_mutex_unlock(); 998 999 return D3D_OK; 1000 } 1001 1002 /***************************************************************************** 1003 * IDirect3DViewport3 Methods. 1004 *****************************************************************************/ 1005 1006 /***************************************************************************** 1007 * IDirect3DViewport3::SetBackgroundDepth2 1008 * 1009 * Sets a IDirectDrawSurface4 surface as the background depth surface 1010 * 1011 * Params: 1012 * lpDDS: Surface to set 1013 * 1014 * Returns: 1015 * D3D_OK, because it's stub 1016 * 1017 *****************************************************************************/ 1018 static HRESULT WINAPI d3d_viewport_SetBackgroundDepth2(IDirect3DViewport3 *iface, 1019 IDirectDrawSurface4 *surface) 1020 { 1021 FIXME("iface %p, surface %p stub!\n", iface, surface); 1022 1023 return D3D_OK; 1024 } 1025 1026 /***************************************************************************** 1027 * IDirect3DViewport3::GetBackgroundDepth2 1028 * 1029 * Returns the IDirect3DSurface4 interface to the background depth surface 1030 * 1031 * Params: 1032 * lplpDDS: Address to store the interface pointer at 1033 * lpValid: Set to true if a surface is assigned 1034 * 1035 * Returns: 1036 * D3D_OK because it's a stub 1037 * 1038 *****************************************************************************/ 1039 static HRESULT WINAPI d3d_viewport_GetBackgroundDepth2(IDirect3DViewport3 *iface, 1040 IDirectDrawSurface4 **surface, BOOL *valid) 1041 { 1042 FIXME("iface %p, surface %p, valid %p stub!\n", iface, surface, valid); 1043 1044 return D3D_OK; 1045 } 1046 1047 /***************************************************************************** 1048 * IDirect3DViewport3::Clear2 1049 * 1050 * Another clearing method 1051 * 1052 * Params: 1053 * Count: Number of rectangles to clear 1054 * Rects: Rectangle array to clear 1055 * Flags: Some flags :) 1056 * Color: Color to fill the render target with 1057 * Z: Value to fill the depth buffer with 1058 * Stencil: Value to fill the stencil bits with 1059 * 1060 * Returns: 1061 * 1062 *****************************************************************************/ 1063 static HRESULT WINAPI d3d_viewport_Clear2(IDirect3DViewport3 *iface, DWORD rect_count, 1064 D3DRECT *rects, DWORD flags, DWORD color, D3DVALUE depth, DWORD stencil) 1065 { 1066 struct d3d_viewport *viewport = impl_from_IDirect3DViewport3(iface); 1067 HRESULT hr; 1068 IDirect3DViewport3 *current_viewport; 1069 IDirect3DDevice3 *d3d_device3; 1070 1071 TRACE("iface %p, rect_count %u, rects %p, flags %#x, color 0x%08x, depth %.8e, stencil %u.\n", 1072 iface, rect_count, rects, flags, color, depth, stencil); 1073 1074 if (!rects || !rect_count) 1075 { 1076 WARN("rect_count = %u, rects = %p, ignoring clear\n", rect_count, rects); 1077 return D3D_OK; 1078 } 1079 1080 wined3d_mutex_lock(); 1081 1082 if (!viewport->active_device) 1083 { 1084 WARN("Trying to clear a viewport not attached to a device.\n"); 1085 wined3d_mutex_unlock(); 1086 return D3DERR_VIEWPORTHASNODEVICE; 1087 } 1088 d3d_device3 = &viewport->active_device->IDirect3DDevice3_iface; 1089 /* Need to temporarily activate viewport to clear it. Previously active 1090 * one will be restored afterwards. */ 1091 viewport_activate(viewport, TRUE); 1092 1093 hr = IDirect3DDevice7_Clear(&viewport->active_device->IDirect3DDevice7_iface, 1094 rect_count, rects, flags, color, depth, stencil); 1095 if (SUCCEEDED(IDirect3DDevice3_GetCurrentViewport(d3d_device3, ¤t_viewport))) 1096 { 1097 struct d3d_viewport *vp = impl_from_IDirect3DViewport3(current_viewport); 1098 viewport_activate(vp, TRUE); 1099 IDirect3DViewport3_Release(current_viewport); 1100 } 1101 1102 wined3d_mutex_unlock(); 1103 1104 return hr; 1105 } 1106 1107 /***************************************************************************** 1108 * The VTable 1109 *****************************************************************************/ 1110 1111 static const struct IDirect3DViewport3Vtbl d3d_viewport_vtbl = 1112 { 1113 /*** IUnknown Methods ***/ 1114 d3d_viewport_QueryInterface, 1115 d3d_viewport_AddRef, 1116 d3d_viewport_Release, 1117 /*** IDirect3DViewport Methods */ 1118 d3d_viewport_Initialize, 1119 d3d_viewport_GetViewport, 1120 d3d_viewport_SetViewport, 1121 d3d_viewport_TransformVertices, 1122 d3d_viewport_LightElements, 1123 d3d_viewport_SetBackground, 1124 d3d_viewport_GetBackground, 1125 d3d_viewport_SetBackgroundDepth, 1126 d3d_viewport_GetBackgroundDepth, 1127 d3d_viewport_Clear, 1128 d3d_viewport_AddLight, 1129 d3d_viewport_DeleteLight, 1130 d3d_viewport_NextLight, 1131 /*** IDirect3DViewport2 Methods ***/ 1132 d3d_viewport_GetViewport2, 1133 d3d_viewport_SetViewport2, 1134 /*** IDirect3DViewport3 Methods ***/ 1135 d3d_viewport_SetBackgroundDepth2, 1136 d3d_viewport_GetBackgroundDepth2, 1137 d3d_viewport_Clear2, 1138 }; 1139 1140 struct d3d_viewport *unsafe_impl_from_IDirect3DViewport3(IDirect3DViewport3 *iface) 1141 { 1142 if (!iface) return NULL; 1143 assert(iface->lpVtbl == &d3d_viewport_vtbl); 1144 return CONTAINING_RECORD(iface, struct d3d_viewport, IDirect3DViewport3_iface); 1145 } 1146 1147 struct d3d_viewport *unsafe_impl_from_IDirect3DViewport2(IDirect3DViewport2 *iface) 1148 { 1149 /* IDirect3DViewport and IDirect3DViewport3 use the same iface. */ 1150 if (!iface) return NULL; 1151 assert(iface->lpVtbl == (IDirect3DViewport2Vtbl *)&d3d_viewport_vtbl); 1152 return CONTAINING_RECORD((IDirect3DViewport3 *)iface, struct d3d_viewport, IDirect3DViewport3_iface); 1153 } 1154 1155 struct d3d_viewport *unsafe_impl_from_IDirect3DViewport(IDirect3DViewport *iface) 1156 { 1157 /* IDirect3DViewport and IDirect3DViewport3 use the same iface. */ 1158 if (!iface) return NULL; 1159 assert(iface->lpVtbl == (IDirect3DViewportVtbl *)&d3d_viewport_vtbl); 1160 return CONTAINING_RECORD((IDirect3DViewport3 *)iface, struct d3d_viewport, IDirect3DViewport3_iface); 1161 } 1162 1163 void d3d_viewport_init(struct d3d_viewport *viewport, struct ddraw *ddraw) 1164 { 1165 viewport->IDirect3DViewport3_iface.lpVtbl = &d3d_viewport_vtbl; 1166 viewport->ref = 1; 1167 viewport->ddraw = ddraw; 1168 viewport->use_vp2 = 0xff; 1169 list_init(&viewport->light_list); 1170 } 1171