[D3DX9_36]
[reactos.git] / reactos / dll / directx / wine / d3dx9_36 / render.c
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 }