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