d3dx9: Add ID3DXRenderToEnvMap interface stub.
[wine] / dlls / 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 "wine/debug.h"
21 #include "d3dx9_36_private.h"
22
23 WINE_DEFAULT_DEBUG_CHANNEL(d3dx);
24
25 struct render_to_surface
26 {
27     ID3DXRenderToSurface ID3DXRenderToSurface_iface;
28     LONG ref;
29
30     IDirect3DDevice9 *device;
31     D3DXRTS_DESC desc;
32
33     IDirect3DSurface9 *dst_surface;
34
35     IDirect3DSurface9 *render_target;
36     IDirect3DSurface9 *depth_stencil;
37
38     DWORD num_render_targets;
39     D3DVIEWPORT9 previous_viewport;
40     IDirect3DSurface9 **previous_render_targets;
41     IDirect3DSurface9 *previous_depth_stencil;
42 };
43
44 static inline struct render_to_surface *impl_from_ID3DXRenderToSurface(ID3DXRenderToSurface *iface)
45 {
46     return CONTAINING_RECORD(iface, struct render_to_surface, ID3DXRenderToSurface_iface);
47 }
48
49 static void restore_previous_device_state(struct render_to_surface *render)
50 {
51     unsigned int i;
52
53     for (i = 0; i < render->num_render_targets; i++)
54     {
55         IDirect3DDevice9_SetRenderTarget(render->device, i, render->previous_render_targets[i]);
56         if (render->previous_render_targets[i])
57             IDirect3DSurface9_Release(render->previous_render_targets[i]);
58         render->previous_render_targets[i] = NULL;
59     }
60
61     IDirect3DDevice9_SetDepthStencilSurface(render->device, render->previous_depth_stencil);
62     if (render->previous_depth_stencil)
63     {
64         IDirect3DSurface9_Release(render->previous_depth_stencil);
65         render->previous_depth_stencil = NULL;
66     }
67
68     IDirect3DDevice9_SetViewport(render->device, &render->previous_viewport);
69 }
70
71 static HRESULT WINAPI D3DXRenderToSurface_QueryInterface(ID3DXRenderToSurface *iface,
72                                                          REFIID riid,
73                                                          void **out)
74 {
75     TRACE("iface %p, riid %s, out %p\n", iface, debugstr_guid(riid), out);
76
77     if (IsEqualGUID(riid, &IID_ID3DXRenderToSurface)
78             || IsEqualGUID(riid, &IID_IUnknown))
79     {
80         IUnknown_AddRef(iface);
81         *out = iface;
82         return S_OK;
83     }
84
85     WARN("%s not implemented, returning E_NOINTERFACE\n", debugstr_guid(riid));
86
87     *out = NULL;
88     return E_NOINTERFACE;
89 }
90
91 static ULONG WINAPI D3DXRenderToSurface_AddRef(ID3DXRenderToSurface *iface)
92 {
93     struct render_to_surface *render = impl_from_ID3DXRenderToSurface(iface);
94     ULONG ref = InterlockedIncrement(&render->ref);
95
96     TRACE("%p increasing refcount to %u\n", iface, ref);
97
98     return ref;
99 }
100
101 static ULONG WINAPI D3DXRenderToSurface_Release(ID3DXRenderToSurface *iface)
102 {
103     struct render_to_surface *render = impl_from_ID3DXRenderToSurface(iface);
104     ULONG ref = InterlockedDecrement(&render->ref);
105     unsigned int i;
106
107     TRACE("%p decreasing refcount to %u\n", iface, ref);
108
109     if (!ref)
110     {
111         if (render->dst_surface) IDirect3DSurface9_Release(render->dst_surface);
112
113         if (render->render_target) IDirect3DSurface9_Release(render->render_target);
114         if (render->depth_stencil) IDirect3DSurface9_Release(render->depth_stencil);
115
116         for (i = 0; i < render->num_render_targets; i++)
117         {
118             if (render->previous_render_targets[i])
119                 IDirect3DSurface9_Release(render->previous_render_targets[i]);
120         }
121
122         HeapFree(GetProcessHeap(), 0, render->previous_render_targets);
123
124         if (render->previous_depth_stencil) IDirect3DSurface9_Release(render->previous_depth_stencil);
125
126         IDirect3DDevice9_Release(render->device);
127
128         HeapFree(GetProcessHeap(), 0, render);
129     }
130
131     return ref;
132 }
133
134 static HRESULT WINAPI D3DXRenderToSurface_GetDevice(ID3DXRenderToSurface *iface,
135                                                     IDirect3DDevice9 **device)
136 {
137     struct render_to_surface *render = impl_from_ID3DXRenderToSurface(iface);
138
139     TRACE("(%p)->(%p)\n", iface, device);
140
141     if (!device) return D3DERR_INVALIDCALL;
142
143     IDirect3DDevice9_AddRef(render->device);
144     *device = render->device;
145     return D3D_OK;
146 }
147
148 static HRESULT WINAPI D3DXRenderToSurface_GetDesc(ID3DXRenderToSurface *iface,
149                                                   D3DXRTS_DESC *desc)
150 {
151     struct render_to_surface *render = impl_from_ID3DXRenderToSurface(iface);
152
153     TRACE("(%p)->(%p)\n", iface, desc);
154
155     if (!desc) return D3DERR_INVALIDCALL;
156
157     *desc = render->desc;
158     return D3D_OK;
159 }
160
161 static HRESULT WINAPI D3DXRenderToSurface_BeginScene(ID3DXRenderToSurface *iface,
162                                                      IDirect3DSurface9 *surface,
163                                                      const D3DVIEWPORT9 *viewport)
164 {
165     struct render_to_surface *render = impl_from_ID3DXRenderToSurface(iface);
166     unsigned int i;
167     IDirect3DDevice9 *device;
168     D3DSURFACE_DESC surface_desc;
169     HRESULT hr = D3DERR_INVALIDCALL;
170     D3DMULTISAMPLE_TYPE multi_sample_type = D3DMULTISAMPLE_NONE;
171     DWORD multi_sample_quality = 0;
172
173     TRACE("(%p)->(%p, %p)\n", iface, surface, viewport);
174
175     if (!surface || render->dst_surface) return D3DERR_INVALIDCALL;
176
177     IDirect3DSurface9_GetDesc(surface, &surface_desc);
178     if (surface_desc.Format != render->desc.Format
179             || surface_desc.Width != render->desc.Width
180             || surface_desc.Height != render->desc.Height)
181         return D3DERR_INVALIDCALL;
182
183     if (viewport)
184     {
185         if (viewport->X > render->desc.Width || viewport->Y > render->desc.Height
186                 || viewport->X + viewport->Width > render->desc.Width
187                 || viewport->Y + viewport->Height > render->desc.Height)
188             return D3DERR_INVALIDCALL;
189
190         if (!(surface_desc.Usage & D3DUSAGE_RENDERTARGET)
191                 && (viewport->X != 0 || viewport->Y != 0
192                 || viewport->Width != render->desc.Width
193                 || viewport->Height != render->desc.Height))
194             return D3DERR_INVALIDCALL;
195     }
196
197     device = render->device;
198
199     /* save device state */
200     IDirect3DDevice9_GetViewport(device, &render->previous_viewport);
201
202     for (i = 0; i < render->num_render_targets; i++)
203     {
204         hr = IDirect3DDevice9_GetRenderTarget(device, i, &render->previous_render_targets[i]);
205         if (FAILED(hr)) render->previous_render_targets[i] = NULL;
206     }
207
208     hr = IDirect3DDevice9_GetDepthStencilSurface(device, &render->previous_depth_stencil);
209     if (FAILED(hr)) render->previous_depth_stencil = NULL;
210
211     /* prepare for rendering to surface */
212     for (i = 1; i < render->num_render_targets; i++)
213         IDirect3DDevice9_SetRenderTarget(device, i, NULL);
214
215     if (surface_desc.Usage & D3DUSAGE_RENDERTARGET)
216     {
217         hr = IDirect3DDevice9_SetRenderTarget(device, 0, surface);
218         multi_sample_type = surface_desc.MultiSampleType;
219         multi_sample_quality = surface_desc.MultiSampleQuality;
220     }
221     else
222     {
223         hr = IDirect3DDevice9_CreateRenderTarget(device, render->desc.Width, render->desc.Height,
224                 render->desc.Format, multi_sample_type, multi_sample_quality, FALSE,
225                 &render->render_target, NULL);
226         if (FAILED(hr)) goto cleanup;
227         hr = IDirect3DDevice9_SetRenderTarget(device, 0, render->render_target);
228     }
229
230     if (FAILED(hr)) goto cleanup;
231
232     if (render->desc.DepthStencil)
233     {
234         hr = IDirect3DDevice9_CreateDepthStencilSurface(device, render->desc.Width, render->desc.Height,
235                 render->desc.DepthStencilFormat, multi_sample_type, multi_sample_quality, TRUE,
236                 &render->depth_stencil, NULL);
237     }
238     else render->depth_stencil = NULL;
239
240     if (FAILED(hr)) goto cleanup;
241
242     hr = IDirect3DDevice9_SetDepthStencilSurface(device, render->depth_stencil);
243     if (FAILED(hr)) goto cleanup;
244
245     if (viewport) IDirect3DDevice9_SetViewport(device, viewport);
246
247     IDirect3DSurface9_AddRef(surface);
248     render->dst_surface = surface;
249     return IDirect3DDevice9_BeginScene(device);
250
251 cleanup:
252     restore_previous_device_state(render);
253
254     if (render->dst_surface) IDirect3DSurface9_Release(render->dst_surface);
255     render->dst_surface = NULL;
256
257     if (render->render_target) IDirect3DSurface9_Release(render->render_target);
258     render->render_target = NULL;
259     if (render->depth_stencil) IDirect3DSurface9_Release(render->depth_stencil);
260     render->depth_stencil = NULL;
261
262     return hr;
263 }
264
265 static HRESULT WINAPI D3DXRenderToSurface_EndScene(ID3DXRenderToSurface *iface,
266                                                    DWORD filter)
267 {
268     struct render_to_surface *render = impl_from_ID3DXRenderToSurface(iface);
269     HRESULT hr;
270
271     TRACE("(%p)->(%#x)\n", iface, filter);
272
273     if (!render->dst_surface) return D3DERR_INVALIDCALL;
274
275     hr = IDirect3DDevice9_EndScene(render->device);
276
277     /* copy render target data to destination surface, if needed */
278     if (render->render_target)
279     {
280         hr = D3DXLoadSurfaceFromSurface(render->dst_surface, NULL, NULL,
281                 render->render_target, NULL, NULL, filter, 0);
282         if (FAILED(hr)) ERR("Copying render target data to surface failed %#x\n", hr);
283     }
284
285     restore_previous_device_state(render);
286
287     /* release resources */
288     if (render->render_target)
289     {
290         IDirect3DSurface9_Release(render->render_target);
291         render->render_target = NULL;
292     }
293
294     if (render->depth_stencil)
295     {
296         IDirect3DSurface9_Release(render->depth_stencil);
297         render->depth_stencil = NULL;
298     }
299
300     IDirect3DSurface9_Release(render->dst_surface);
301     render->dst_surface = NULL;
302
303     return hr;
304 }
305
306 static HRESULT WINAPI D3DXRenderToSurface_OnLostDevice(ID3DXRenderToSurface *iface)
307 {
308     FIXME("(%p)->(): stub\n", iface);
309     return D3D_OK;
310 }
311
312 static HRESULT WINAPI D3DXRenderToSurface_OnResetDevice(ID3DXRenderToSurface *iface)
313 {
314     FIXME("(%p)->(): stub\n", iface);
315     return D3D_OK;
316 }
317
318 static const ID3DXRenderToSurfaceVtbl render_to_surface_vtbl =
319 {
320     /* IUnknown methods */
321     D3DXRenderToSurface_QueryInterface,
322     D3DXRenderToSurface_AddRef,
323     D3DXRenderToSurface_Release,
324     /* ID3DXRenderToSurface methods */
325     D3DXRenderToSurface_GetDevice,
326     D3DXRenderToSurface_GetDesc,
327     D3DXRenderToSurface_BeginScene,
328     D3DXRenderToSurface_EndScene,
329     D3DXRenderToSurface_OnLostDevice,
330     D3DXRenderToSurface_OnResetDevice
331 };
332
333 HRESULT WINAPI D3DXCreateRenderToSurface(IDirect3DDevice9 *device,
334                                          UINT width,
335                                          UINT height,
336                                          D3DFORMAT format,
337                                          BOOL depth_stencil,
338                                          D3DFORMAT depth_stencil_format,
339                                          ID3DXRenderToSurface **out)
340 {
341     HRESULT hr;
342     D3DCAPS9 caps;
343     struct render_to_surface *render;
344     unsigned int i;
345
346     TRACE("(%p, %u, %u, %#x, %d, %#x, %p)\n", device, width, height, format,
347             depth_stencil, depth_stencil_format, out);
348
349     if (!device || !out) return D3DERR_INVALIDCALL;
350
351     hr = IDirect3DDevice9_GetDeviceCaps(device, &caps);
352     if (FAILED(hr)) return hr;
353
354     render = HeapAlloc(GetProcessHeap(), 0, sizeof(struct render_to_surface));
355     if (!render) return E_OUTOFMEMORY;
356
357     render->ID3DXRenderToSurface_iface.lpVtbl = &render_to_surface_vtbl;
358     render->ref = 1;
359
360     render->desc.Width = width;
361     render->desc.Height = height;
362     render->desc.Format = format;
363     render->desc.DepthStencil = depth_stencil;
364     render->desc.DepthStencilFormat = depth_stencil_format;
365
366     render->dst_surface = NULL;
367     render->render_target = NULL;
368     render->depth_stencil = NULL;
369
370     render->num_render_targets = caps.NumSimultaneousRTs;
371     render->previous_render_targets = HeapAlloc(GetProcessHeap(), 0,
372             render->num_render_targets * sizeof(IDirect3DSurface9 *));
373     if (!render->previous_render_targets)
374     {
375         HeapFree(GetProcessHeap(), 0, render);
376         return E_OUTOFMEMORY;
377     }
378
379     for (i = 0; i < render->num_render_targets; i++)
380         render->previous_render_targets[i] = NULL;
381     render->previous_depth_stencil = NULL;
382
383     IDirect3DDevice9_AddRef(device);
384     render->device = device;
385
386     *out = &render->ID3DXRenderToSurface_iface;
387     return D3D_OK;
388 }
389
390
391 struct render_to_envmap
392 {
393     ID3DXRenderToEnvMap ID3DXRenderToEnvMap_iface;
394     LONG ref;
395
396     IDirect3DDevice9 *device;
397     D3DXRTE_DESC desc;
398 };
399
400 static inline struct render_to_envmap *impl_from_ID3DXRenderToEnvMap(ID3DXRenderToEnvMap *iface)
401 {
402     return CONTAINING_RECORD(iface, struct render_to_envmap, ID3DXRenderToEnvMap_iface);
403 }
404
405 static HRESULT WINAPI D3DXRenderToEnvMap_QueryInterface(ID3DXRenderToEnvMap *iface,
406                                                         REFIID riid,
407                                                         void **out)
408 {
409     TRACE("iface %p, riid %s, out %p\n", iface, debugstr_guid(riid), out);
410
411     if (IsEqualGUID(riid, &IID_ID3DXRenderToEnvMap)
412             || IsEqualGUID(riid, &IID_IUnknown))
413     {
414         IUnknown_AddRef(iface);
415         *out = iface;
416         return S_OK;
417     }
418
419     WARN("%s not implemented, returning E_NOINTERFACE\n", debugstr_guid(riid));
420
421     *out = NULL;
422     return E_NOINTERFACE;
423 }
424
425 static ULONG WINAPI D3DXRenderToEnvMap_AddRef(ID3DXRenderToEnvMap *iface)
426 {
427     struct render_to_envmap *render = impl_from_ID3DXRenderToEnvMap(iface);
428     ULONG ref = InterlockedIncrement(&render->ref);
429
430     TRACE("%p increasing refcount to %u\n", iface, ref);
431
432     return ref;
433 }
434
435 static ULONG WINAPI D3DXRenderToEnvMap_Release(ID3DXRenderToEnvMap *iface)
436 {
437     struct render_to_envmap *render = impl_from_ID3DXRenderToEnvMap(iface);
438     ULONG ref = InterlockedDecrement(&render->ref);
439
440     TRACE("%p decreasing refcount to %u\n", iface, ref);
441
442     if (!ref)
443     {
444         IDirect3DDevice9_Release(render->device);
445
446         HeapFree(GetProcessHeap(), 0, render);
447     }
448
449     return ref;
450 }
451
452 static HRESULT WINAPI D3DXRenderToEnvMap_GetDevice(ID3DXRenderToEnvMap *iface,
453                                                    IDirect3DDevice9 **device)
454 {
455     struct render_to_envmap *render = impl_from_ID3DXRenderToEnvMap(iface);
456
457     TRACE("(%p)->(%p)\n", iface, device);
458
459     if (!device) return D3DERR_INVALIDCALL;
460
461     IDirect3DDevice9_AddRef(render->device);
462     *device = render->device;
463     return D3D_OK;
464 }
465
466 static HRESULT WINAPI D3DXRenderToEnvMap_GetDesc(ID3DXRenderToEnvMap *iface,
467                                                  D3DXRTE_DESC *desc)
468 {
469     struct render_to_envmap *render = impl_from_ID3DXRenderToEnvMap(iface);
470
471     TRACE("(%p)->(%p)\n", iface, desc);
472
473     if (!desc) return D3DERR_INVALIDCALL;
474
475     *desc = render->desc;
476     return D3D_OK;
477 }
478
479 static HRESULT WINAPI D3DXRenderToEnvMap_BeginCube(ID3DXRenderToEnvMap *iface,
480                                                    IDirect3DCubeTexture9 *texture)
481 {
482     FIXME("(%p)->(%p): stub\n", iface, texture);
483     return E_NOTIMPL;
484 }
485
486 static HRESULT WINAPI D3DXRenderToEnvMap_BeginSphere(ID3DXRenderToEnvMap *iface,
487                                                      IDirect3DTexture9 *texture)
488 {
489     FIXME("(%p)->(%p): stub\n", iface, texture);
490     return E_NOTIMPL;
491 }
492
493 static HRESULT WINAPI D3DXRenderToEnvMap_BeginHemisphere(ID3DXRenderToEnvMap *iface,
494                                                          IDirect3DTexture9 *pos_z_texture,
495                                                          IDirect3DTexture9 *neg_z_texture)
496 {
497     FIXME("(%p)->(%p, %p): stub\n", iface, pos_z_texture, neg_z_texture);
498     return E_NOTIMPL;
499 }
500
501 static HRESULT WINAPI D3DXRenderToEnvMap_BeginParabolic(ID3DXRenderToEnvMap *iface,
502                                                         IDirect3DTexture9 *pos_z_texture,
503                                                         IDirect3DTexture9 *neg_z_texture)
504 {
505     FIXME("(%p)->(%p, %p): stub\n", iface, pos_z_texture, neg_z_texture);
506     return E_NOTIMPL;
507 }
508
509 static HRESULT WINAPI D3DXRenderToEnvMap_Face(ID3DXRenderToEnvMap *iface,
510                                               D3DCUBEMAP_FACES face,
511                                               DWORD filter)
512 {
513     FIXME("(%p)->(%u, %#x): stub\n", iface, face, filter);
514     return E_NOTIMPL;
515 }
516
517 static HRESULT WINAPI D3DXRenderToEnvMap_End(ID3DXRenderToEnvMap *iface,
518                                              DWORD filter)
519 {
520     FIXME("(%p)->(%#x): stub\n", iface, filter);
521     return E_NOTIMPL;
522 }
523
524
525 static HRESULT WINAPI D3DXRenderToEnvMap_OnLostDevice(ID3DXRenderToEnvMap *iface)
526 {
527     FIXME("(%p)->(): stub\n", iface);
528     return D3D_OK;
529 }
530
531 static HRESULT WINAPI D3DXRenderToEnvMap_OnResetDevice(ID3DXRenderToEnvMap *iface)
532 {
533     FIXME("(%p)->(): stub\n", iface);
534     return D3D_OK;
535 }
536
537 static const ID3DXRenderToEnvMapVtbl render_to_envmap_vtbl =
538 {
539     /* IUnknown methods */
540     D3DXRenderToEnvMap_QueryInterface,
541     D3DXRenderToEnvMap_AddRef,
542     D3DXRenderToEnvMap_Release,
543     /* ID3DXRenderToEnvMap methods */
544     D3DXRenderToEnvMap_GetDevice,
545     D3DXRenderToEnvMap_GetDesc,
546     D3DXRenderToEnvMap_BeginCube,
547     D3DXRenderToEnvMap_BeginSphere,
548     D3DXRenderToEnvMap_BeginHemisphere,
549     D3DXRenderToEnvMap_BeginParabolic,
550     D3DXRenderToEnvMap_Face,
551     D3DXRenderToEnvMap_End,
552     D3DXRenderToEnvMap_OnLostDevice,
553     D3DXRenderToEnvMap_OnResetDevice
554 };
555
556 HRESULT WINAPI D3DXCreateRenderToEnvMap(IDirect3DDevice9 *device,
557                                         UINT size,
558                                         UINT mip_levels,
559                                         D3DFORMAT format,
560                                         BOOL depth_stencil,
561                                         D3DFORMAT depth_stencil_format,
562                                         ID3DXRenderToEnvMap **out)
563 {
564     HRESULT hr;
565     struct render_to_envmap *render;
566
567     TRACE("(%p, %u, %u, %#x, %d, %#x, %p)\n", device, size, mip_levels,
568             format, depth_stencil, depth_stencil_format, out);
569
570     if (!device || !out) return D3DERR_INVALIDCALL;
571
572     hr = D3DXCheckTextureRequirements(device, &size, &size, &mip_levels,
573             D3DUSAGE_RENDERTARGET, &format, D3DPOOL_DEFAULT);
574     if (FAILED(hr)) return hr;
575
576     render = HeapAlloc(GetProcessHeap(), 0, sizeof(struct render_to_envmap));
577     if (!render) return E_OUTOFMEMORY;
578
579     render->ID3DXRenderToEnvMap_iface.lpVtbl = &render_to_envmap_vtbl;
580     render->ref = 1;
581
582     render->desc.Size = size;
583     render->desc.MipLevels = mip_levels;
584     render->desc.Format = format;
585     render->desc.DepthStencil = depth_stencil;
586     render->desc.DepthStencilFormat = depth_stencil_format;
587
588     IDirect3DDevice9_AddRef(device);
589     render->device = device;
590
591     *out = &render->ID3DXRenderToEnvMap_iface;
592     return D3D_OK;
593 }