ddraw: Get rid of ICOM_INTERFACE.
[wine] / dlls / ddraw / texture.c
1 /* Direct3D Texture
2  * Copyright (c) 1998 Lionel ULMER
3  * Copyright (c) 2006 Stefan DÖSINGER
4  *
5  * This file contains the implementation of interface Direct3DTexture2.
6  *
7  * This library is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU Lesser General Public
9  * License as published by the Free Software Foundation; either
10  * version 2.1 of the License, or (at your option) any later version.
11  *
12  * This library is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15  * Lesser General Public License for more details.
16  *
17  * You should have received a copy of the GNU Lesser General Public
18  * License along with this library; if not, write to the Free Software
19  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
20  */
21
22 #include "config.h"
23 #include "wine/port.h"
24
25 #include <assert.h>
26 #include <stdarg.h>
27 #include <string.h>
28 #include <stdlib.h>
29
30 #define COBJMACROS
31 #define NONAMELESSUNION
32
33 #include "windef.h"
34 #include "winbase.h"
35 #include "winerror.h"
36 #include "wingdi.h"
37 #include "wine/exception.h"
38
39 #include "ddraw.h"
40 #include "d3d.h"
41
42 #include "ddraw_private.h"
43 #include "wine/debug.h"
44
45 WINE_DEFAULT_DEBUG_CHANNEL(d3d7);
46 WINE_DECLARE_DEBUG_CHANNEL(ddraw_thunk);
47
48 /*****************************************************************************
49  * IUnknown interfaces. They are thunks to IDirectDrawSurface7
50  *****************************************************************************/
51 static HRESULT WINAPI
52 Thunk_IDirect3DTextureImpl_2_QueryInterface(IDirect3DTexture2 *iface,
53                                             REFIID riid,
54                                             void **obj)
55 {
56     ICOM_THIS_FROM(IDirectDrawSurfaceImpl, IDirect3DTexture2, iface);
57     TRACE("(%p)->(%s,%p) thunking to IDirectDrawSurface7 interface.\n", This, debugstr_guid(riid), obj);
58     return IDirectDrawSurface7_QueryInterface((IDirectDrawSurface7 *)This, riid, obj);
59 }
60
61 static HRESULT WINAPI
62 Thunk_IDirect3DTextureImpl_1_QueryInterface(IDirect3DTexture *iface,
63                                             REFIID riid,
64                                             void **obj)
65 {
66     ICOM_THIS_FROM(IDirectDrawSurfaceImpl, IDirect3DTexture, iface);
67     TRACE("(%p)->(%s,%p) thunking to IDirectDrawSurface7 interface.\n", This, debugstr_guid(riid), obj);
68
69     return IDirectDrawSurface7_QueryInterface((IDirectDrawSurface7 *)This, riid, obj);
70 }
71
72 static ULONG WINAPI
73 Thunk_IDirect3DTextureImpl_2_AddRef(IDirect3DTexture2 *iface)
74 {
75     ICOM_THIS_FROM(IDirectDrawSurfaceImpl, IDirect3DTexture2, iface);
76     TRACE("(%p)->() thunking to IDirectDrawSurface7 interface.\n", This);
77
78     return IDirectDrawSurface7_AddRef((IDirectDrawSurface7 *)This);
79 }
80
81 static ULONG WINAPI
82 Thunk_IDirect3DTextureImpl_1_AddRef(IDirect3DTexture *iface)
83 {
84     ICOM_THIS_FROM(IDirectDrawSurfaceImpl, IDirect3DTexture, iface);
85     TRACE("(%p)->() thunking to IDirectDrawSurface7 interface.\n", This);
86
87     return IDirectDrawSurface7_AddRef(COM_INTERFACE_CAST(IDirectDrawSurfaceImpl, IDirect3DTexture, IDirectDrawSurface7, iface));
88 }
89
90 static ULONG WINAPI
91 Thunk_IDirect3DTextureImpl_2_Release(IDirect3DTexture2 *iface)
92 {
93     ICOM_THIS_FROM(IDirectDrawSurfaceImpl, IDirect3DTexture2, iface);
94     TRACE("(%p)->() thunking to IDirectDrawSurface7 interface.\n", This);
95
96     return IDirectDrawSurface7_Release((IDirectDrawSurface7 *)This);
97 }
98
99
100 static ULONG WINAPI
101 Thunk_IDirect3DTextureImpl_1_Release(IDirect3DTexture *iface)
102 {
103     ICOM_THIS_FROM(IDirectDrawSurfaceImpl, IDirect3DTexture, iface);
104     TRACE("(%p)->() thunking to IDirectDrawSurface7 interface.\n", This);
105
106     return IDirectDrawSurface7_Release(COM_INTERFACE_CAST(IDirectDrawSurfaceImpl, IDirect3DTexture, IDirectDrawSurface7, iface));
107 }
108
109 /*****************************************************************************
110  * IDirect3DTexture interface
111  *****************************************************************************/
112
113 /*****************************************************************************
114  * IDirect3DTexture1::Initialize
115  *
116  * The sdk says it's not implemented
117  *
118  * Params:
119  *  ?
120  *
121  * Returns
122  *  DDERR_UNSUPPORTED
123  *
124  *****************************************************************************/
125 static HRESULT WINAPI
126 IDirect3DTextureImpl_1_Initialize(IDirect3DTexture *iface,
127                                   IDirect3DDevice *Direct3DDevice,
128                                   IDirectDrawSurface *DDSurface)
129 {
130     ICOM_THIS_FROM(IDirectDrawSurfaceImpl, IDirect3DTexture, iface);
131     IDirect3DDeviceImpl *d3d = ICOM_OBJECT(IDirect3DDeviceImpl, IDirect3DDevice, Direct3DDevice);
132     IDirectDrawSurfaceImpl *surf = ICOM_OBJECT(IDirectDrawSurfaceImpl, IDirectDrawSurface3, DDSurface);
133     TRACE("(%p)->(%p,%p) Not implemented\n", This, d3d, surf);
134     return DDERR_UNSUPPORTED; /* Unchecked */
135 }
136
137 /*****************************************************************************
138  * IDirect3DTexture2::PaletteChanged
139  *
140  * Informs the texture about a palette change
141  *
142  * Params:
143  *  Start: Start index of the change
144  *  Count: The number of changed entries
145  *
146  * Returns
147  *  D3D_OK, because it's a stub
148  *
149  *****************************************************************************/
150 static HRESULT WINAPI
151 IDirect3DTextureImpl_PaletteChanged(IDirect3DTexture2 *iface,
152                                          DWORD Start,
153                                          DWORD Count)
154 {
155     ICOM_THIS_FROM(IDirectDrawSurfaceImpl, IDirect3DTexture2, iface);
156     FIXME("(%p)->(%08x,%08x): stub!\n", This, Start, Count);
157     return D3D_OK;
158 }
159
160 static HRESULT WINAPI
161 Thunk_IDirect3DTextureImpl_1_PaletteChanged(IDirect3DTexture *iface,
162                                             DWORD Start,
163                                             DWORD Count)
164 {
165     ICOM_THIS_FROM(IDirectDrawSurfaceImpl, IDirect3DTexture, iface);
166     TRACE("(%p)->(%08x,%08x) thunking to IDirect3DTexture2 interface.\n", This, Start, Count);
167
168     return IDirect3DTexture2_PaletteChanged(COM_INTERFACE_CAST(IDirectDrawSurfaceImpl, IDirect3DTexture, IDirect3DTexture2, iface),
169                                             Start,
170                                             Count);
171 }
172
173
174 /*****************************************************************************
175  * IDirect3DTexture::Unload
176  *
177  * DX5 SDK: "The IDirect3DTexture2::Unload method is not implemented
178  *
179  *
180  * Returns:
181  *  DDERR_UNSUPPORTED
182  *
183  *****************************************************************************/
184 static HRESULT WINAPI
185 IDirect3DTextureImpl_1_Unload(IDirect3DTexture *iface)
186 {
187     ICOM_THIS_FROM(IDirectDrawSurfaceImpl, IDirect3DTexture, iface);
188     TRACE("(%p)->(): not implemented!\n", This);
189     return DDERR_UNSUPPORTED;
190 }
191
192 /*****************************************************************************
193  * IDirect3DTexture2::GetHandle
194  *
195  * Returns handle for the texture. At the moment, the interface
196  * to the IWineD3DTexture is used.
197  *
198  * Params:
199  *  Direct3DDevice2: Device this handle is assigned to
200  *  Handle: Address to store the handle at.
201  *
202  * Returns:
203  *  D3D_OK
204  *
205  *****************************************************************************/
206 static HRESULT WINAPI
207 IDirect3DTextureImpl_GetHandle(IDirect3DTexture2 *iface,
208                                     IDirect3DDevice2 *Direct3DDevice2,
209                                     D3DTEXTUREHANDLE *lpHandle)
210 {
211     ICOM_THIS_FROM(IDirectDrawSurfaceImpl, IDirect3DTexture2, iface);
212     IDirect3DDeviceImpl *d3d = ICOM_OBJECT(IDirect3DDeviceImpl, IDirect3DDevice2, Direct3DDevice2);
213
214     TRACE("(%p)->(%p,%p)\n", This, d3d, lpHandle);
215
216     EnterCriticalSection(&ddraw_cs);
217     if(!This->Handle)
218     {
219         This->Handle = IDirect3DDeviceImpl_CreateHandle(d3d);
220         if(This->Handle)
221         {
222             d3d->Handles[This->Handle - 1].ptr = This;
223             d3d->Handles[This->Handle - 1].type = DDrawHandle_Texture;
224         }
225     }
226     *lpHandle = This->Handle;
227
228     TRACE(" returning handle %08x.\n", *lpHandle);
229
230     LeaveCriticalSection(&ddraw_cs);
231     return D3D_OK;
232 }
233
234 static HRESULT WINAPI
235 Thunk_IDirect3DTextureImpl_1_GetHandle(IDirect3DTexture *iface,
236                                        LPDIRECT3DDEVICE lpDirect3DDevice,
237                                        LPD3DTEXTUREHANDLE lpHandle)
238 {
239     ICOM_THIS_FROM(IDirectDrawSurfaceImpl, IDirect3DTexture, iface);
240     IDirect3DDeviceImpl *d3d = ICOM_OBJECT(IDirect3DDeviceImpl, IDirect3DDevice, lpDirect3DDevice);
241     IDirect3DTexture2 *d3d_texture2 = (IDirect3DTexture2 *)&This->IDirect3DTexture2_vtbl;
242     IDirect3DDevice2 *d3d_device2 = (IDirect3DDevice2 *)&d3d->IDirect3DDevice2_vtbl;
243
244     TRACE_(ddraw_thunk)("(%p)->(%p,%p) thunking to IDirect3DTexture2 interface.\n", This, d3d, lpHandle);
245
246     return IDirect3DTexture2_GetHandle(d3d_texture2, d3d_device2, lpHandle);
247 }
248
249
250 /*****************************************************************************
251  * get_sub_mimaplevel
252  *
253  * Helper function that returns the next mipmap level
254  *
255  * tex_ptr: Surface of which to return the next level
256  *
257  *****************************************************************************/
258 static IDirectDrawSurfaceImpl *
259 get_sub_mimaplevel(IDirectDrawSurfaceImpl *tex_ptr)
260 {
261     /* Now go down the mipmap chain to the next surface */
262     static DDSCAPS2 mipmap_caps = { DDSCAPS_MIPMAP | DDSCAPS_TEXTURE, 0, 0, 0 };
263     LPDIRECTDRAWSURFACE7 next_level;
264     IDirectDrawSurfaceImpl *surf_ptr;
265     HRESULT hr;
266
267     hr = IDirectDrawSurface7_GetAttachedSurface((IDirectDrawSurface7 *)tex_ptr, &mipmap_caps, &next_level);
268     if (FAILED(hr)) return NULL;
269
270     surf_ptr = ICOM_OBJECT(IDirectDrawSurfaceImpl, IDirectDrawSurface7, next_level);
271     IDirectDrawSurface7_Release(next_level);
272
273     return surf_ptr;
274 }
275
276 /*****************************************************************************
277  * IDirect3DTexture2::Load
278  *
279  * Loads a texture created with the DDSCAPS_ALLOCONLOAD
280  *
281  * This function isn't relayed to WineD3D because the whole interface is
282  * implemented in DDraw only. For speed improvements a implementation which
283  * takes OpenGL more into account could be placed into WineD3D.
284  *
285  * Params:
286  *  D3DTexture2: Address of the texture to load
287  *
288  * Returns:
289  *  D3D_OK on success
290  *  D3DERR_TEXTURE_LOAD_FAILED.
291  *
292  *****************************************************************************/
293 static HRESULT WINAPI
294 IDirect3DTextureImpl_Load(IDirect3DTexture2 *iface,
295                           IDirect3DTexture2 *D3DTexture2)
296 {
297     ICOM_THIS_FROM(IDirectDrawSurfaceImpl, IDirect3DTexture2, iface);
298     IDirectDrawSurfaceImpl *src_ptr = ICOM_OBJECT(IDirectDrawSurfaceImpl, IDirect3DTexture2, D3DTexture2);
299     HRESULT ret_value = D3D_OK;
300     if(src_ptr == This)
301     {
302         TRACE("copying surface %p to surface %p, why?\n", src_ptr, This);
303         return ret_value;
304     }
305
306     TRACE("(%p)->(%p)\n", This, src_ptr);
307     EnterCriticalSection(&ddraw_cs);
308
309     if (((src_ptr->surface_desc.ddsCaps.dwCaps & DDSCAPS_MIPMAP) != (This->surface_desc.ddsCaps.dwCaps & DDSCAPS_MIPMAP)) ||
310         (src_ptr->surface_desc.u2.dwMipMapCount != This->surface_desc.u2.dwMipMapCount))
311     {
312         ERR("Trying to load surfaces with different mip-map counts !\n");
313     }
314
315     while(1)
316     {
317         IWineD3DPalette *wine_pal, *wine_pal_src;
318         IDirectDrawPalette *pal = NULL, *pal_src = NULL;
319         DDSURFACEDESC *src_d, *dst_d;
320
321         TRACE(" copying surface %p to surface %p (mipmap level %d)\n", src_ptr, This, src_ptr->mipmap_level);
322
323         /* Suppress the ALLOCONLOAD flag */
324         This->surface_desc.ddsCaps.dwCaps &= ~DDSCAPS_ALLOCONLOAD;
325
326         /* Get the palettes */
327         ret_value = IWineD3DSurface_GetPalette(This->WineD3DSurface, &wine_pal);
328         if( ret_value != D3D_OK)
329         {
330             ERR("IWineD3DSurface::GetPalette failed! This is unexpected\n");
331             LeaveCriticalSection(&ddraw_cs);
332             return D3DERR_TEXTURE_LOAD_FAILED;
333         }
334         if(wine_pal)
335         {
336             ret_value = IWineD3DPalette_GetParent(wine_pal, (IUnknown **) &pal);
337             if(ret_value != D3D_OK)
338             {
339                 ERR("IWineD3DPalette::GetParent failed! This is unexpected\n");
340                 LeaveCriticalSection(&ddraw_cs);
341                 return D3DERR_TEXTURE_LOAD_FAILED;
342             }
343         }
344
345         ret_value = IWineD3DSurface_GetPalette(src_ptr->WineD3DSurface, &wine_pal_src);
346         if( ret_value != D3D_OK)
347         {
348             ERR("IWineD3DSurface::GetPalette failed! This is unexpected\n");
349             LeaveCriticalSection(&ddraw_cs);
350             return D3DERR_TEXTURE_LOAD_FAILED;
351         }
352         if(wine_pal_src)
353         {
354             ret_value = IWineD3DPalette_GetParent(wine_pal_src, (IUnknown **) &pal_src);
355             if(ret_value != D3D_OK)
356             {
357                 ERR("IWineD3DPalette::GetParent failed! This is unexpected\n");
358                 if (pal) IDirectDrawPalette_Release(pal);
359                 LeaveCriticalSection(&ddraw_cs);
360                 return D3DERR_TEXTURE_LOAD_FAILED;
361             }
362         }
363
364         if (pal_src != NULL)
365         {
366             PALETTEENTRY palent[256];
367
368             if (pal == NULL)
369             {
370                 IDirectDrawPalette_Release(pal_src);
371                 LeaveCriticalSection(&ddraw_cs);
372                 return DDERR_NOPALETTEATTACHED;
373             }
374             IDirectDrawPalette_GetEntries(pal_src, 0, 0, 256, palent);
375             IDirectDrawPalette_SetEntries(pal, 0, 0, 256, palent);
376         }
377
378         if (pal) IDirectDrawPalette_Release(pal);
379         if (pal_src) IDirectDrawPalette_Release(pal_src);
380
381         /* Copy one surface on the other */
382         dst_d = (DDSURFACEDESC *)&(This->surface_desc);
383         src_d = (DDSURFACEDESC *)&(src_ptr->surface_desc);
384
385         if ((src_d->dwWidth != dst_d->dwWidth) || (src_d->dwHeight != dst_d->dwHeight))
386         {
387             /* Should also check for same pixel format, u1.lPitch, ... */
388             ERR("Error in surface sizes\n");
389             LeaveCriticalSection(&ddraw_cs);
390             return D3DERR_TEXTURE_LOAD_FAILED;
391         }
392         else
393         {
394             WINED3DLOCKED_RECT pSrcRect, pDstRect;
395
396             /* LPDIRECT3DDEVICE2 d3dd = (LPDIRECT3DDEVICE2) This->D3Ddevice; */
397             /* I should put a macro for the calculus of bpp */
398
399             /* Copy also the ColorKeying stuff */
400             if (src_d->dwFlags & DDSD_CKSRCBLT)
401             {
402                 dst_d->dwFlags |= DDSD_CKSRCBLT;
403                 dst_d->ddckCKSrcBlt.dwColorSpaceLowValue = src_d->ddckCKSrcBlt.dwColorSpaceLowValue;
404                 dst_d->ddckCKSrcBlt.dwColorSpaceHighValue = src_d->ddckCKSrcBlt.dwColorSpaceHighValue;
405             }
406
407             /* Copy the main memory texture into the surface that corresponds to the OpenGL
408               texture object. */
409
410             ret_value = IWineD3DSurface_LockRect(src_ptr->WineD3DSurface, &pSrcRect, NULL, 0);
411             if(ret_value != D3D_OK)
412             {
413                 ERR(" (%p) Locking the source surface failed\n", This);
414                 LeaveCriticalSection(&ddraw_cs);
415                 return D3DERR_TEXTURE_LOAD_FAILED;
416             }
417
418             ret_value = IWineD3DSurface_LockRect(This->WineD3DSurface, &pDstRect, NULL, 0);
419             if(ret_value != D3D_OK)
420             {
421                 ERR(" (%p) Locking the destination surface failed\n", This);
422                 IWineD3DSurface_UnlockRect(src_ptr->WineD3DSurface);
423                 LeaveCriticalSection(&ddraw_cs);
424                 return D3DERR_TEXTURE_LOAD_FAILED;
425             }
426
427             if (This->surface_desc.u4.ddpfPixelFormat.dwFlags & DDPF_FOURCC)
428                 memcpy(pDstRect.pBits, pSrcRect.pBits, src_ptr->surface_desc.u1.dwLinearSize);
429             else
430                 memcpy(pDstRect.pBits, pSrcRect.pBits, pSrcRect.Pitch * src_d->dwHeight);
431
432             IWineD3DSurface_UnlockRect(src_ptr->WineD3DSurface);
433             IWineD3DSurface_UnlockRect(This->WineD3DSurface);
434         }
435
436         if (src_ptr->surface_desc.ddsCaps.dwCaps & DDSCAPS_MIPMAP)
437         {
438             src_ptr = get_sub_mimaplevel(src_ptr);
439         }
440         else
441         {
442             src_ptr = NULL;
443         }
444         if (This->surface_desc.ddsCaps.dwCaps & DDSCAPS_MIPMAP)
445         {
446             This = get_sub_mimaplevel(This);
447         }
448         else
449         {
450             This = NULL;
451         }
452
453         if ((src_ptr == NULL) || (This == NULL))
454         {
455             if (src_ptr != This)
456             {
457                 ERR(" Loading surface with different mipmap structure !!!\n");
458             }
459             break;
460         }
461     }
462
463     LeaveCriticalSection(&ddraw_cs);
464     return ret_value;
465 }
466
467 static HRESULT WINAPI
468 Thunk_IDirect3DTextureImpl_1_Load(IDirect3DTexture *iface,
469                                   IDirect3DTexture *D3DTexture)
470 {
471     ICOM_THIS_FROM(IDirectDrawSurfaceImpl, IDirect3DTexture, iface);
472     IDirectDrawSurfaceImpl *Texture = ICOM_OBJECT(IDirectDrawSurfaceImpl, IDirect3DTexture, D3DTexture);
473     TRACE("(%p)->(%p) thunking to IDirect3DTexture2 interface.\n", This, Texture);
474
475     return IDirect3DTexture2_Load(COM_INTERFACE_CAST(IDirectDrawSurfaceImpl, IDirect3DTexture, IDirect3DTexture2, iface),
476                                   COM_INTERFACE_CAST(IDirectDrawSurfaceImpl, IDirect3DTexture, IDirect3DTexture2, D3DTexture));
477 }
478
479 /*****************************************************************************
480  * The VTables
481  *****************************************************************************/
482 const IDirect3DTexture2Vtbl IDirect3DTexture2_Vtbl =
483 {
484     Thunk_IDirect3DTextureImpl_2_QueryInterface,
485     Thunk_IDirect3DTextureImpl_2_AddRef,
486     Thunk_IDirect3DTextureImpl_2_Release,
487     IDirect3DTextureImpl_GetHandle,
488     IDirect3DTextureImpl_PaletteChanged,
489     IDirect3DTextureImpl_Load,
490 };
491
492
493 const IDirect3DTextureVtbl IDirect3DTexture1_Vtbl =
494 {
495     Thunk_IDirect3DTextureImpl_1_QueryInterface,
496     Thunk_IDirect3DTextureImpl_1_AddRef,
497     Thunk_IDirect3DTextureImpl_1_Release,
498     IDirect3DTextureImpl_1_Initialize,
499     Thunk_IDirect3DTextureImpl_1_GetHandle,
500     Thunk_IDirect3DTextureImpl_1_PaletteChanged,
501     Thunk_IDirect3DTextureImpl_1_Load,
502     IDirect3DTextureImpl_1_Unload,
503 };