1 /* 2 * Copyright (C) 2012 Józef Kucia 3 * 4 * This library is free software; you can redistribute it and/or 5 * modify it under the terms of the GNU Lesser General Public 6 * License as published by the Free Software Foundation; either 7 * version 2.1 of the License, or (at your option) any later version. 8 * 9 * This library is distributed in the hope that it will be useful, 10 * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12 * Lesser General Public License for more details. 13 * 14 * You should have received a copy of the GNU Lesser General Public 15 * License along with this library; if not, write to the Free Software 16 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA 17 * 18 */ 19 20 #include "config.h" 21 #include "wine/port.h" 22 23 #include "d3dx9_private.h" 24 25 WINE_DEFAULT_DEBUG_CHANNEL(d3dx); 26 27 struct device_state 28 { 29 DWORD num_render_targets; 30 IDirect3DSurface9 **render_targets; 31 IDirect3DSurface9 *depth_stencil; 32 D3DVIEWPORT9 viewport; 33 }; 34 35 static HRESULT device_state_init(IDirect3DDevice9 *device, struct device_state *state) 36 { 37 HRESULT hr; 38 D3DCAPS9 caps; 39 unsigned int i; 40 41 hr = IDirect3DDevice9_GetDeviceCaps(device, &caps); 42 if (FAILED(hr)) return hr; 43 44 state->num_render_targets = caps.NumSimultaneousRTs; 45 state->render_targets = HeapAlloc(GetProcessHeap(), 0, 46 state->num_render_targets * sizeof(IDirect3DSurface9 *)); 47 if (!state->render_targets) 48 return E_OUTOFMEMORY; 49 50 for (i = 0; i < state->num_render_targets; i++) 51 state->render_targets[i] = NULL; 52 state->depth_stencil = NULL; 53 return D3D_OK; 54 } 55 56 static void device_state_capture(IDirect3DDevice9 *device, struct device_state *state) 57 { 58 HRESULT hr; 59 unsigned int i; 60 61 IDirect3DDevice9_GetViewport(device, &state->viewport); 62 63 for (i = 0; i < state->num_render_targets; i++) 64 { 65 hr = IDirect3DDevice9_GetRenderTarget(device, i, &state->render_targets[i]); 66 if (FAILED(hr)) state->render_targets[i] = NULL; 67 } 68 69 hr = IDirect3DDevice9_GetDepthStencilSurface(device, &state->depth_stencil); 70 if (FAILED(hr)) state->depth_stencil = NULL; 71 } 72 73 static void device_state_restore(IDirect3DDevice9 *device, struct device_state *state) 74 { 75 unsigned int i; 76 77 for (i = 0; i < state->num_render_targets; i++) 78 { 79 IDirect3DDevice9_SetRenderTarget(device, i, state->render_targets[i]); 80 if (state->render_targets[i]) 81 IDirect3DSurface9_Release(state->render_targets[i]); 82 state->render_targets[i] = NULL; 83 } 84 85 IDirect3DDevice9_SetDepthStencilSurface(device, state->depth_stencil); 86 if (state->depth_stencil) 87 { 88 IDirect3DSurface9_Release(state->depth_stencil); 89 state->depth_stencil = NULL; 90 } 91 92 IDirect3DDevice9_SetViewport(device, &state->viewport); 93 } 94 95 static void device_state_release(struct device_state *state) 96 { 97 unsigned int i; 98 99 for (i = 0; i < state->num_render_targets; i++) 100 { 101 if (state->render_targets[i]) 102 IDirect3DSurface9_Release(state->render_targets[i]); 103 } 104 105 HeapFree(GetProcessHeap(), 0, state->render_targets); 106 107 if (state->depth_stencil) IDirect3DSurface9_Release(state->depth_stencil); 108 } 109 110 struct render_to_surface 111 { 112 ID3DXRenderToSurface ID3DXRenderToSurface_iface; 113 LONG ref; 114 115 IDirect3DDevice9 *device; 116 D3DXRTS_DESC desc; 117 118 IDirect3DSurface9 *dst_surface; 119 120 IDirect3DSurface9 *render_target; 121 IDirect3DSurface9 *depth_stencil; 122 123 struct device_state previous_state; 124 }; 125 126 static inline struct render_to_surface *impl_from_ID3DXRenderToSurface(ID3DXRenderToSurface *iface) 127 { 128 return CONTAINING_RECORD(iface, struct render_to_surface, ID3DXRenderToSurface_iface); 129 } 130 131 static HRESULT WINAPI D3DXRenderToSurface_QueryInterface(ID3DXRenderToSurface *iface, 132 REFIID riid, 133 void **out) 134 { 135 TRACE("iface %p, riid %s, out %p\n", iface, debugstr_guid(riid), out); 136 137 if (IsEqualGUID(riid, &IID_ID3DXRenderToSurface) 138 || IsEqualGUID(riid, &IID_IUnknown)) 139 { 140 IUnknown_AddRef(iface); 141 *out = iface; 142 return S_OK; 143 } 144 145 WARN("%s not implemented, returning E_NOINTERFACE\n", debugstr_guid(riid)); 146 147 *out = NULL; 148 return E_NOINTERFACE; 149 } 150 151 static ULONG WINAPI D3DXRenderToSurface_AddRef(ID3DXRenderToSurface *iface) 152 { 153 struct render_to_surface *render = impl_from_ID3DXRenderToSurface(iface); 154 ULONG ref = InterlockedIncrement(&render->ref); 155 156 TRACE("%p increasing refcount to %u\n", iface, ref); 157 158 return ref; 159 } 160 161 static ULONG WINAPI D3DXRenderToSurface_Release(ID3DXRenderToSurface *iface) 162 { 163 struct render_to_surface *render = impl_from_ID3DXRenderToSurface(iface); 164 ULONG ref = InterlockedDecrement(&render->ref); 165 166 TRACE("%p decreasing refcount to %u\n", iface, ref); 167 168 if (!ref) 169 { 170 if (render->dst_surface) IDirect3DSurface9_Release(render->dst_surface); 171 172 if (render->render_target) IDirect3DSurface9_Release(render->render_target); 173 if (render->depth_stencil) IDirect3DSurface9_Release(render->depth_stencil); 174 175 device_state_release(&render->previous_state); 176 177 IDirect3DDevice9_Release(render->device); 178 179 HeapFree(GetProcessHeap(), 0, render); 180 } 181 182 return ref; 183 } 184 185 static HRESULT WINAPI D3DXRenderToSurface_GetDevice(ID3DXRenderToSurface *iface, 186 IDirect3DDevice9 **device) 187 { 188 struct render_to_surface *render = impl_from_ID3DXRenderToSurface(iface); 189 190 TRACE("(%p)->(%p)\n", iface, device); 191 192 if (!device) return D3DERR_INVALIDCALL; 193 194 IDirect3DDevice9_AddRef(render->device); 195 *device = render->device; 196 return D3D_OK; 197 } 198 199 static HRESULT WINAPI D3DXRenderToSurface_GetDesc(ID3DXRenderToSurface *iface, 200 D3DXRTS_DESC *desc) 201 { 202 struct render_to_surface *render = impl_from_ID3DXRenderToSurface(iface); 203 204 TRACE("(%p)->(%p)\n", iface, desc); 205 206 if (!desc) return D3DERR_INVALIDCALL; 207 208 *desc = render->desc; 209 return D3D_OK; 210 } 211 212 static HRESULT WINAPI D3DXRenderToSurface_BeginScene(ID3DXRenderToSurface *iface, 213 IDirect3DSurface9 *surface, 214 const D3DVIEWPORT9 *viewport) 215 { 216 struct render_to_surface *render = impl_from_ID3DXRenderToSurface(iface); 217 unsigned int i; 218 IDirect3DDevice9 *device; 219 D3DSURFACE_DESC surface_desc; 220 HRESULT hr = D3DERR_INVALIDCALL; 221 D3DMULTISAMPLE_TYPE multi_sample_type = D3DMULTISAMPLE_NONE; 222 DWORD multi_sample_quality = 0; 223 224 TRACE("(%p)->(%p, %p)\n", iface, surface, viewport); 225 226 if (!surface || render->dst_surface) return D3DERR_INVALIDCALL; 227 228 IDirect3DSurface9_GetDesc(surface, &surface_desc); 229 if (surface_desc.Format != render->desc.Format 230 || surface_desc.Width != render->desc.Width 231 || surface_desc.Height != render->desc.Height) 232 return D3DERR_INVALIDCALL; 233 234 if (viewport) 235 { 236 if (viewport->X > render->desc.Width || viewport->Y > render->desc.Height 237 || viewport->X + viewport->Width > render->desc.Width 238 || viewport->Y + viewport->Height > render->desc.Height) 239 return D3DERR_INVALIDCALL; 240 241 if (!(surface_desc.Usage & D3DUSAGE_RENDERTARGET) 242 && (viewport->X != 0 || viewport->Y != 0 243 || viewport->Width != render->desc.Width 244 || viewport->Height != render->desc.Height)) 245 return D3DERR_INVALIDCALL; 246 } 247 248 device = render->device; 249 250 device_state_capture(device, &render->previous_state); 251 252 /* prepare for rendering to surface */ 253 for (i = 1; i < render->previous_state.num_render_targets; i++) 254 IDirect3DDevice9_SetRenderTarget(device, i, NULL); 255 256 if (surface_desc.Usage & D3DUSAGE_RENDERTARGET) 257 { 258 hr = IDirect3DDevice9_SetRenderTarget(device, 0, surface); 259 multi_sample_type = surface_desc.MultiSampleType; 260 multi_sample_quality = surface_desc.MultiSampleQuality; 261 } 262 else 263 { 264 hr = IDirect3DDevice9_CreateRenderTarget(device, render->desc.Width, render->desc.Height, 265 render->desc.Format, multi_sample_type, multi_sample_quality, FALSE, 266 &render->render_target, NULL); 267 if (FAILED(hr)) goto cleanup; 268 hr = IDirect3DDevice9_SetRenderTarget(device, 0, render->render_target); 269 } 270 271 if (FAILED(hr)) goto cleanup; 272 273 if (render->desc.DepthStencil) 274 { 275 hr = IDirect3DDevice9_CreateDepthStencilSurface(device, render->desc.Width, render->desc.Height, 276 render->desc.DepthStencilFormat, multi_sample_type, multi_sample_quality, TRUE, 277 &render->depth_stencil, NULL); 278 } 279 else render->depth_stencil = NULL; 280 281 if (FAILED(hr)) goto cleanup; 282 283 hr = IDirect3DDevice9_SetDepthStencilSurface(device, render->depth_stencil); 284 if (FAILED(hr)) goto cleanup; 285 286 if (viewport) IDirect3DDevice9_SetViewport(device, viewport); 287 288 IDirect3DSurface9_AddRef(surface); 289 render->dst_surface = surface; 290 return IDirect3DDevice9_BeginScene(device); 291 292 cleanup: 293 device_state_restore(device, &render->previous_state); 294 295 if (render->dst_surface) IDirect3DSurface9_Release(render->dst_surface); 296 render->dst_surface = NULL; 297 298 if (render->render_target) IDirect3DSurface9_Release(render->render_target); 299 render->render_target = NULL; 300 if (render->depth_stencil) IDirect3DSurface9_Release(render->depth_stencil); 301 render->depth_stencil = NULL; 302 303 return hr; 304 } 305 306 static HRESULT WINAPI D3DXRenderToSurface_EndScene(ID3DXRenderToSurface *iface, 307 DWORD filter) 308 { 309 struct render_to_surface *render = impl_from_ID3DXRenderToSurface(iface); 310 HRESULT hr; 311 312 TRACE("(%p)->(%#x)\n", iface, filter); 313 314 if (!render->dst_surface) return D3DERR_INVALIDCALL; 315 316 hr = IDirect3DDevice9_EndScene(render->device); 317 318 /* copy render target data to destination surface, if needed */ 319 if (render->render_target) 320 { 321 hr = D3DXLoadSurfaceFromSurface(render->dst_surface, NULL, NULL, 322 render->render_target, NULL, NULL, filter, 0); 323 if (FAILED(hr)) ERR("Copying render target data to surface failed %#x\n", hr); 324 } 325 326 device_state_restore(render->device, &render->previous_state); 327 328 /* release resources */ 329 if (render->render_target) 330 { 331 IDirect3DSurface9_Release(render->render_target); 332 render->render_target = NULL; 333 } 334 335 if (render->depth_stencil) 336 { 337 IDirect3DSurface9_Release(render->depth_stencil); 338 render->depth_stencil = NULL; 339 } 340 341 IDirect3DSurface9_Release(render->dst_surface); 342 render->dst_surface = NULL; 343 344 return hr; 345 } 346 347 static HRESULT WINAPI D3DXRenderToSurface_OnLostDevice(ID3DXRenderToSurface *iface) 348 { 349 FIXME("(%p)->(): stub\n", iface); 350 return D3D_OK; 351 } 352 353 static HRESULT WINAPI D3DXRenderToSurface_OnResetDevice(ID3DXRenderToSurface *iface) 354 { 355 FIXME("(%p)->(): stub\n", iface); 356 return D3D_OK; 357 } 358 359 static const ID3DXRenderToSurfaceVtbl render_to_surface_vtbl = 360 { 361 /* IUnknown methods */ 362 D3DXRenderToSurface_QueryInterface, 363 D3DXRenderToSurface_AddRef, 364 D3DXRenderToSurface_Release, 365 /* ID3DXRenderToSurface methods */ 366 D3DXRenderToSurface_GetDevice, 367 D3DXRenderToSurface_GetDesc, 368 D3DXRenderToSurface_BeginScene, 369 D3DXRenderToSurface_EndScene, 370 D3DXRenderToSurface_OnLostDevice, 371 D3DXRenderToSurface_OnResetDevice 372 }; 373 374 HRESULT WINAPI D3DXCreateRenderToSurface(IDirect3DDevice9 *device, 375 UINT width, 376 UINT height, 377 D3DFORMAT format, 378 BOOL depth_stencil, 379 D3DFORMAT depth_stencil_format, 380 ID3DXRenderToSurface **out) 381 { 382 HRESULT hr; 383 struct render_to_surface *render; 384 385 TRACE("(%p, %u, %u, %#x, %d, %#x, %p)\n", device, width, height, format, 386 depth_stencil, depth_stencil_format, out); 387 388 if (!device || !out) return D3DERR_INVALIDCALL; 389 390 render = HeapAlloc(GetProcessHeap(), 0, sizeof(struct render_to_surface)); 391 if (!render) return E_OUTOFMEMORY; 392 393 render->ID3DXRenderToSurface_iface.lpVtbl = &render_to_surface_vtbl; 394 render->ref = 1; 395 396 render->desc.Width = width; 397 render->desc.Height = height; 398 render->desc.Format = format; 399 render->desc.DepthStencil = depth_stencil; 400 render->desc.DepthStencilFormat = depth_stencil_format; 401 402 render->dst_surface = NULL; 403 render->render_target = NULL; 404 render->depth_stencil = NULL; 405 406 hr = device_state_init(device, &render->previous_state); 407 if (FAILED(hr)) 408 { 409 HeapFree(GetProcessHeap(), 0, render); 410 return hr; 411 } 412 413 IDirect3DDevice9_AddRef(device); 414 render->device = device; 415 416 *out = &render->ID3DXRenderToSurface_iface; 417 return D3D_OK; 418 } 419 420 421 enum render_state 422 { 423 INITIAL, 424 425 CUBE_BEGIN, 426 CUBE_FACE 427 }; 428 429 struct render_to_envmap 430 { 431 ID3DXRenderToEnvMap ID3DXRenderToEnvMap_iface; 432 LONG ref; 433 434 IDirect3DDevice9 *device; 435 D3DXRTE_DESC desc; 436 437 enum render_state state; 438 struct device_state previous_device_state; 439 440 D3DCUBEMAP_FACES face; 441 DWORD filter; 442 443 IDirect3DSurface9 *render_target; 444 IDirect3DSurface9 *depth_stencil; 445 446 IDirect3DCubeTexture9 *dst_cube_texture; 447 }; 448 449 static void copy_render_target_to_cube_texture_face(IDirect3DCubeTexture9 *cube_texture, 450 D3DCUBEMAP_FACES face, IDirect3DSurface9 *render_target, DWORD filter) 451 { 452 HRESULT hr; 453 IDirect3DSurface9 *cube_surface; 454 455 IDirect3DCubeTexture9_GetCubeMapSurface(cube_texture, face, 0, &cube_surface); 456 457 hr = D3DXLoadSurfaceFromSurface(cube_surface, NULL, NULL, render_target, NULL, NULL, filter, 0); 458 if (FAILED(hr)) ERR("Copying render target data to surface failed %#x\n", hr); 459 460 IDirect3DSurface9_Release(cube_surface); 461 } 462 463 static inline struct render_to_envmap *impl_from_ID3DXRenderToEnvMap(ID3DXRenderToEnvMap *iface) 464 { 465 return CONTAINING_RECORD(iface, struct render_to_envmap, ID3DXRenderToEnvMap_iface); 466 } 467 468 static HRESULT WINAPI D3DXRenderToEnvMap_QueryInterface(ID3DXRenderToEnvMap *iface, 469 REFIID riid, 470 void **out) 471 { 472 TRACE("iface %p, riid %s, out %p\n", iface, debugstr_guid(riid), out); 473 474 if (IsEqualGUID(riid, &IID_ID3DXRenderToEnvMap) 475 || IsEqualGUID(riid, &IID_IUnknown)) 476 { 477 IUnknown_AddRef(iface); 478 *out = iface; 479 return S_OK; 480 } 481 482 WARN("%s not implemented, returning E_NOINTERFACE\n", debugstr_guid(riid)); 483 484 *out = NULL; 485 return E_NOINTERFACE; 486 } 487 488 static ULONG WINAPI D3DXRenderToEnvMap_AddRef(ID3DXRenderToEnvMap *iface) 489 { 490 struct render_to_envmap *render = impl_from_ID3DXRenderToEnvMap(iface); 491 ULONG ref = InterlockedIncrement(&render->ref); 492 493 TRACE("%p increasing refcount to %u\n", iface, ref); 494 495 return ref; 496 } 497 498 static ULONG WINAPI D3DXRenderToEnvMap_Release(ID3DXRenderToEnvMap *iface) 499 { 500 struct render_to_envmap *render = impl_from_ID3DXRenderToEnvMap(iface); 501 ULONG ref = InterlockedDecrement(&render->ref); 502 503 TRACE("%p decreasing refcount to %u\n", iface, ref); 504 505 if (!ref) 506 { 507 if (render->dst_cube_texture) IDirect3DSurface9_Release(render->dst_cube_texture); 508 509 if (render->render_target) IDirect3DSurface9_Release(render->render_target); 510 if (render->depth_stencil) IDirect3DSurface9_Release(render->depth_stencil); 511 512 device_state_release(&render->previous_device_state); 513 514 IDirect3DDevice9_Release(render->device); 515 516 HeapFree(GetProcessHeap(), 0, render); 517 } 518 519 return ref; 520 } 521 522 static HRESULT WINAPI D3DXRenderToEnvMap_GetDevice(ID3DXRenderToEnvMap *iface, 523 IDirect3DDevice9 **device) 524 { 525 struct render_to_envmap *render = impl_from_ID3DXRenderToEnvMap(iface); 526 527 TRACE("(%p)->(%p)\n", iface, device); 528 529 if (!device) return D3DERR_INVALIDCALL; 530 531 IDirect3DDevice9_AddRef(render->device); 532 *device = render->device; 533 return D3D_OK; 534 } 535 536 static HRESULT WINAPI D3DXRenderToEnvMap_GetDesc(ID3DXRenderToEnvMap *iface, 537 D3DXRTE_DESC *desc) 538 { 539 struct render_to_envmap *render = impl_from_ID3DXRenderToEnvMap(iface); 540 541 TRACE("(%p)->(%p)\n", iface, desc); 542 543 if (!desc) return D3DERR_INVALIDCALL; 544 545 *desc = render->desc; 546 return D3D_OK; 547 } 548 549 static HRESULT WINAPI D3DXRenderToEnvMap_BeginCube(ID3DXRenderToEnvMap *iface, 550 IDirect3DCubeTexture9 *texture) 551 { 552 struct render_to_envmap *render = impl_from_ID3DXRenderToEnvMap(iface); 553 HRESULT hr; 554 D3DSURFACE_DESC level_desc; 555 556 TRACE("(%p)->(%p)\n", iface, texture); 557 558 if (!texture) return D3DERR_INVALIDCALL; 559 560 if (render->state != INITIAL) return D3DERR_INVALIDCALL; 561 562 IDirect3DCubeTexture9_GetLevelDesc(texture, 0, &level_desc); 563 if (level_desc.Format != render->desc.Format || level_desc.Width != render->desc.Size) 564 return D3DERR_INVALIDCALL; 565 566 if (!(level_desc.Usage & D3DUSAGE_RENDERTARGET)) 567 { 568 hr = IDirect3DDevice9_CreateRenderTarget(render->device, level_desc.Width, level_desc.Height, 569 level_desc.Format, level_desc.MultiSampleType, level_desc.MultiSampleQuality, 570 TRUE, &render->render_target, NULL); 571 if (FAILED(hr)) goto cleanup; 572 IDirect3DCubeTexture9_GetLevelDesc(texture, 0, &level_desc); 573 } 574 575 if (render->desc.DepthStencil) 576 { 577 hr = IDirect3DDevice9_CreateDepthStencilSurface(render->device, level_desc.Width, level_desc.Height, 578 render->desc.DepthStencilFormat, level_desc.MultiSampleType, level_desc.MultiSampleQuality, 579 TRUE, &render->depth_stencil, NULL); 580 if (FAILED(hr)) goto cleanup; 581 } 582 583 IDirect3DCubeTexture9_AddRef(texture); 584 render->dst_cube_texture = texture; 585 render->state = CUBE_BEGIN; 586 return D3D_OK; 587 588 cleanup: 589 if (render->dst_cube_texture) IDirect3DSurface9_Release(render->dst_cube_texture); 590 render->dst_cube_texture = NULL; 591 592 if (render->render_target) IDirect3DSurface9_Release(render->render_target); 593 render->render_target = NULL; 594 if (render->depth_stencil) IDirect3DSurface9_Release(render->depth_stencil); 595 render->depth_stencil = NULL; 596 597 return hr; 598 } 599 600 static HRESULT WINAPI D3DXRenderToEnvMap_BeginSphere(ID3DXRenderToEnvMap *iface, 601 IDirect3DTexture9 *texture) 602 { 603 FIXME("(%p)->(%p): stub\n", iface, texture); 604 return E_NOTIMPL; 605 } 606 607 static HRESULT WINAPI D3DXRenderToEnvMap_BeginHemisphere(ID3DXRenderToEnvMap *iface, 608 IDirect3DTexture9 *pos_z_texture, 609 IDirect3DTexture9 *neg_z_texture) 610 { 611 FIXME("(%p)->(%p, %p): stub\n", iface, pos_z_texture, neg_z_texture); 612 return E_NOTIMPL; 613 } 614 615 static HRESULT WINAPI D3DXRenderToEnvMap_BeginParabolic(ID3DXRenderToEnvMap *iface, 616 IDirect3DTexture9 *pos_z_texture, 617 IDirect3DTexture9 *neg_z_texture) 618 { 619 FIXME("(%p)->(%p, %p): stub\n", iface, pos_z_texture, neg_z_texture); 620 return E_NOTIMPL; 621 } 622 623 static HRESULT WINAPI D3DXRenderToEnvMap_Face(ID3DXRenderToEnvMap *iface, 624 D3DCUBEMAP_FACES face, 625 DWORD filter) 626 { 627 struct render_to_envmap *render = impl_from_ID3DXRenderToEnvMap(iface); 628 HRESULT hr; 629 unsigned int i; 630 631 TRACE("(%p)->(%u, %#x)\n", iface, face, filter); 632 633 if (render->state == CUBE_FACE) 634 { 635 IDirect3DDevice9_EndScene(render->device); 636 if (render->render_target) 637 copy_render_target_to_cube_texture_face(render->dst_cube_texture, render->face, 638 render->render_target, render->filter); 639 640 device_state_restore(render->device, &render->previous_device_state); 641 642 render->state = CUBE_BEGIN; 643 } 644 else if (render->state != CUBE_BEGIN) 645 return D3DERR_INVALIDCALL; 646 647 device_state_capture(render->device, &render->previous_device_state); 648 649 for (i = 1; i < render->previous_device_state.num_render_targets; i++) 650 IDirect3DDevice9_SetRenderTarget(render->device, i, NULL); 651 652 if (!render->render_target) 653 { 654 IDirect3DSurface9 *render_target; 655 IDirect3DCubeTexture9_GetCubeMapSurface(render->dst_cube_texture, face, 0, &render_target); 656 hr = IDirect3DDevice9_SetRenderTarget(render->device, 0, render_target); 657 IDirect3DSurface9_Release(render_target); 658 } 659 else hr = IDirect3DDevice9_SetRenderTarget(render->device, 0, render->render_target); 660 661 if (FAILED(hr)) goto cleanup; 662 663 hr = IDirect3DDevice9_SetDepthStencilSurface(render->device, render->depth_stencil); 664 if (FAILED(hr)) goto cleanup; 665 666 render->state = CUBE_FACE; 667 render->face = face; 668 render->filter = filter; 669 return IDirect3DDevice9_BeginScene(render->device); 670 671 cleanup: 672 device_state_restore(render->device, &render->previous_device_state); 673 return hr; 674 } 675 676 static HRESULT WINAPI D3DXRenderToEnvMap_End(ID3DXRenderToEnvMap *iface, 677 DWORD filter) 678 { 679 struct render_to_envmap *render = impl_from_ID3DXRenderToEnvMap(iface); 680 681 TRACE("(%p)->(%#x)\n", iface, filter); 682 683 if (render->state == INITIAL) return D3DERR_INVALIDCALL; 684 685 if (render->state == CUBE_FACE) 686 { 687 IDirect3DDevice9_EndScene(render->device); 688 if (render->render_target) 689 copy_render_target_to_cube_texture_face(render->dst_cube_texture, render->face, 690 render->render_target, render->filter); 691 692 device_state_restore(render->device, &render->previous_device_state); 693 } 694 695 D3DXFilterTexture((IDirect3DBaseTexture9 *)render->dst_cube_texture, NULL, 0, filter); 696 697 if (render->render_target) 698 { 699 IDirect3DSurface9_Release(render->render_target); 700 render->render_target = NULL; 701 } 702 703 if (render->depth_stencil) 704 { 705 IDirect3DSurface9_Release(render->depth_stencil); 706 render->depth_stencil = NULL; 707 } 708 709 IDirect3DSurface9_Release(render->dst_cube_texture); 710 render->dst_cube_texture = NULL; 711 712 render->state = INITIAL; 713 return D3D_OK; 714 } 715 716 static HRESULT WINAPI D3DXRenderToEnvMap_OnLostDevice(ID3DXRenderToEnvMap *iface) 717 { 718 FIXME("(%p)->(): stub\n", iface); 719 return D3D_OK; 720 } 721 722 static HRESULT WINAPI D3DXRenderToEnvMap_OnResetDevice(ID3DXRenderToEnvMap *iface) 723 { 724 FIXME("(%p)->(): stub\n", iface); 725 return D3D_OK; 726 } 727 728 static const ID3DXRenderToEnvMapVtbl render_to_envmap_vtbl = 729 { 730 /* IUnknown methods */ 731 D3DXRenderToEnvMap_QueryInterface, 732 D3DXRenderToEnvMap_AddRef, 733 D3DXRenderToEnvMap_Release, 734 /* ID3DXRenderToEnvMap methods */ 735 D3DXRenderToEnvMap_GetDevice, 736 D3DXRenderToEnvMap_GetDesc, 737 D3DXRenderToEnvMap_BeginCube, 738 D3DXRenderToEnvMap_BeginSphere, 739 D3DXRenderToEnvMap_BeginHemisphere, 740 D3DXRenderToEnvMap_BeginParabolic, 741 D3DXRenderToEnvMap_Face, 742 D3DXRenderToEnvMap_End, 743 D3DXRenderToEnvMap_OnLostDevice, 744 D3DXRenderToEnvMap_OnResetDevice 745 }; 746 747 HRESULT WINAPI D3DXCreateRenderToEnvMap(IDirect3DDevice9 *device, 748 UINT size, 749 UINT mip_levels, 750 D3DFORMAT format, 751 BOOL depth_stencil, 752 D3DFORMAT depth_stencil_format, 753 ID3DXRenderToEnvMap **out) 754 { 755 HRESULT hr; 756 struct render_to_envmap *render; 757 758 TRACE("(%p, %u, %u, %#x, %d, %#x, %p)\n", device, size, mip_levels, 759 format, depth_stencil, depth_stencil_format, out); 760 761 if (!device || !out) return D3DERR_INVALIDCALL; 762 763 hr = D3DXCheckTextureRequirements(device, &size, &size, &mip_levels, 764 D3DUSAGE_RENDERTARGET, &format, D3DPOOL_DEFAULT); 765 if (FAILED(hr)) return hr; 766 767 render = HeapAlloc(GetProcessHeap(), 0, sizeof(struct render_to_envmap)); 768 if (!render) return E_OUTOFMEMORY; 769 770 render->ID3DXRenderToEnvMap_iface.lpVtbl = &render_to_envmap_vtbl; 771 render->ref = 1; 772 773 render->desc.Size = size; 774 render->desc.MipLevels = mip_levels; 775 render->desc.Format = format; 776 render->desc.DepthStencil = depth_stencil; 777 render->desc.DepthStencilFormat = depth_stencil_format; 778 779 render->state = INITIAL; 780 render->render_target = NULL; 781 render->depth_stencil = NULL; 782 render->dst_cube_texture = NULL; 783 784 hr = device_state_init(device, &render->previous_device_state); 785 if (FAILED(hr)) 786 { 787 HeapFree(GetProcessHeap(), 0, render); 788 return hr; 789 } 790 791 IDirect3DDevice9_AddRef(device); 792 render->device = device; 793 794 *out = &render->ID3DXRenderToEnvMap_iface; 795 return D3D_OK; 796 } 797