hlink: Implement HLINKGETREF flags handling.
[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     IDirectDrawSurfaceImpl *This = surface_from_texture2(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     IDirectDrawSurfaceImpl *This = surface_from_texture1(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     IDirectDrawSurfaceImpl *This = surface_from_texture2(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     IDirectDrawSurfaceImpl *This = surface_from_texture1(iface);
85     TRACE("(%p)->() thunking to IDirectDrawSurface7 interface.\n", This);
86
87     return IDirectDrawSurface7_AddRef((IDirectDrawSurface7 *)This);
88 }
89
90 static ULONG WINAPI
91 Thunk_IDirect3DTextureImpl_2_Release(IDirect3DTexture2 *iface)
92 {
93     IDirectDrawSurfaceImpl *This = surface_from_texture2(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     IDirectDrawSurfaceImpl *This = surface_from_texture1(iface);
104     TRACE("(%p)->() thunking to IDirectDrawSurface7 interface.\n", This);
105
106     return IDirectDrawSurface7_Release((IDirectDrawSurface7 *)This);
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     TRACE("(%p)->(%p,%p) Not implemented\n", iface, Direct3DDevice, DDSurface);
131     return DDERR_UNSUPPORTED; /* Unchecked */
132 }
133
134 /*****************************************************************************
135  * IDirect3DTexture2::PaletteChanged
136  *
137  * Informs the texture about a palette change
138  *
139  * Params:
140  *  Start: Start index of the change
141  *  Count: The number of changed entries
142  *
143  * Returns
144  *  D3D_OK, because it's a stub
145  *
146  *****************************************************************************/
147 static HRESULT WINAPI
148 IDirect3DTextureImpl_PaletteChanged(IDirect3DTexture2 *iface,
149                                          DWORD Start,
150                                          DWORD Count)
151 {
152     IDirectDrawSurfaceImpl *This = surface_from_texture2(iface);
153     FIXME("(%p)->(%08x,%08x): stub!\n", This, Start, Count);
154     return D3D_OK;
155 }
156
157 static HRESULT WINAPI
158 Thunk_IDirect3DTextureImpl_1_PaletteChanged(IDirect3DTexture *iface,
159                                             DWORD Start,
160                                             DWORD Count)
161 {
162     IDirectDrawSurfaceImpl *This = surface_from_texture1(iface);
163     TRACE("(%p)->(%08x,%08x) thunking to IDirect3DTexture2 interface.\n", This, Start, Count);
164
165     return IDirect3DTexture2_PaletteChanged((IDirect3DTexture2 *)&This->IDirect3DTexture2_vtbl, Start, Count);
166 }
167
168
169 /*****************************************************************************
170  * IDirect3DTexture::Unload
171  *
172  * DX5 SDK: "The IDirect3DTexture2::Unload method is not implemented
173  *
174  *
175  * Returns:
176  *  DDERR_UNSUPPORTED
177  *
178  *****************************************************************************/
179 static HRESULT WINAPI
180 IDirect3DTextureImpl_1_Unload(IDirect3DTexture *iface)
181 {
182     IDirectDrawSurfaceImpl *This = surface_from_texture1(iface);
183     TRACE("(%p)->(): not implemented!\n", This);
184     return DDERR_UNSUPPORTED;
185 }
186
187 /*****************************************************************************
188  * IDirect3DTexture2::GetHandle
189  *
190  * Returns handle for the texture. At the moment, the interface
191  * to the IWineD3DTexture is used.
192  *
193  * Params:
194  *  Direct3DDevice2: Device this handle is assigned to
195  *  Handle: Address to store the handle at.
196  *
197  * Returns:
198  *  D3D_OK
199  *
200  *****************************************************************************/
201 static HRESULT WINAPI
202 IDirect3DTextureImpl_GetHandle(IDirect3DTexture2 *iface,
203                                     IDirect3DDevice2 *Direct3DDevice2,
204                                     D3DTEXTUREHANDLE *lpHandle)
205 {
206     IDirectDrawSurfaceImpl *This = surface_from_texture2(iface);
207     IDirect3DDeviceImpl *d3d = device_from_device2(Direct3DDevice2);
208
209     TRACE("(%p)->(%p,%p)\n", This, d3d, lpHandle);
210
211     EnterCriticalSection(&ddraw_cs);
212     if(!This->Handle)
213     {
214         DWORD h = ddraw_allocate_handle(&d3d->handle_table, This, DDRAW_HANDLE_SURFACE);
215         if (h == DDRAW_INVALID_HANDLE)
216         {
217             ERR("Failed to allocate a texture handle.\n");
218             LeaveCriticalSection(&ddraw_cs);
219             return DDERR_OUTOFMEMORY;
220         }
221
222         This->Handle = h + 1;
223     }
224     *lpHandle = This->Handle;
225
226     TRACE(" returning handle %08x.\n", *lpHandle);
227
228     LeaveCriticalSection(&ddraw_cs);
229     return D3D_OK;
230 }
231
232 static HRESULT WINAPI
233 Thunk_IDirect3DTextureImpl_1_GetHandle(IDirect3DTexture *iface,
234                                        LPDIRECT3DDEVICE lpDirect3DDevice,
235                                        LPD3DTEXTUREHANDLE lpHandle)
236 {
237     IDirectDrawSurfaceImpl *This = surface_from_texture1(iface);
238     IDirect3DDeviceImpl *d3d = device_from_device1(lpDirect3DDevice);
239     IDirect3DTexture2 *d3d_texture2 = (IDirect3DTexture2 *)&This->IDirect3DTexture2_vtbl;
240     IDirect3DDevice2 *d3d_device2 = (IDirect3DDevice2 *)&d3d->IDirect3DDevice2_vtbl;
241
242     TRACE_(ddraw_thunk)("(%p)->(%p,%p) thunking to IDirect3DTexture2 interface.\n", This, d3d, lpHandle);
243
244     return IDirect3DTexture2_GetHandle(d3d_texture2, d3d_device2, lpHandle);
245 }
246
247
248 /*****************************************************************************
249  * get_sub_mimaplevel
250  *
251  * Helper function that returns the next mipmap level
252  *
253  * tex_ptr: Surface of which to return the next level
254  *
255  *****************************************************************************/
256 static IDirectDrawSurfaceImpl *
257 get_sub_mimaplevel(IDirectDrawSurfaceImpl *tex_ptr)
258 {
259     /* Now go down the mipmap chain to the next surface */
260     static DDSCAPS2 mipmap_caps = { DDSCAPS_MIPMAP | DDSCAPS_TEXTURE, 0, 0, 0 };
261     LPDIRECTDRAWSURFACE7 next_level;
262     IDirectDrawSurfaceImpl *surf_ptr;
263     HRESULT hr;
264
265     hr = IDirectDrawSurface7_GetAttachedSurface((IDirectDrawSurface7 *)tex_ptr, &mipmap_caps, &next_level);
266     if (FAILED(hr)) return NULL;
267
268     surf_ptr = (IDirectDrawSurfaceImpl *)next_level;
269     IDirectDrawSurface7_Release(next_level);
270
271     return surf_ptr;
272 }
273
274 /*****************************************************************************
275  * IDirect3DTexture2::Load
276  *
277  * Loads a texture created with the DDSCAPS_ALLOCONLOAD
278  *
279  * This function isn't relayed to WineD3D because the whole interface is
280  * implemented in DDraw only. For speed improvements a implementation which
281  * takes OpenGL more into account could be placed into WineD3D.
282  *
283  * Params:
284  *  D3DTexture2: Address of the texture to load
285  *
286  * Returns:
287  *  D3D_OK on success
288  *  D3DERR_TEXTURE_LOAD_FAILED.
289  *
290  *****************************************************************************/
291 static HRESULT WINAPI
292 IDirect3DTextureImpl_Load(IDirect3DTexture2 *iface,
293                           IDirect3DTexture2 *D3DTexture2)
294 {
295     IDirectDrawSurfaceImpl *This = surface_from_texture2(iface);
296     IDirectDrawSurfaceImpl *src_ptr = surface_from_texture2(D3DTexture2);
297     HRESULT ret_value = D3D_OK;
298     if(src_ptr == This)
299     {
300         TRACE("copying surface %p to surface %p, why?\n", src_ptr, This);
301         return ret_value;
302     }
303
304     TRACE("(%p)->(%p)\n", This, src_ptr);
305     EnterCriticalSection(&ddraw_cs);
306
307     if (((src_ptr->surface_desc.ddsCaps.dwCaps & DDSCAPS_MIPMAP) != (This->surface_desc.ddsCaps.dwCaps & DDSCAPS_MIPMAP)) ||
308         (src_ptr->surface_desc.u2.dwMipMapCount != This->surface_desc.u2.dwMipMapCount))
309     {
310         ERR("Trying to load surfaces with different mip-map counts !\n");
311     }
312
313     while(1)
314     {
315         IWineD3DPalette *wine_pal, *wine_pal_src;
316         IDirectDrawPalette *pal = NULL, *pal_src = NULL;
317         DDSURFACEDESC *src_d, *dst_d;
318
319         TRACE(" copying surface %p to surface %p (mipmap level %d)\n", src_ptr, This, src_ptr->mipmap_level);
320
321         /* Suppress the ALLOCONLOAD flag */
322         This->surface_desc.ddsCaps.dwCaps &= ~DDSCAPS_ALLOCONLOAD;
323
324         /* Get the palettes */
325         ret_value = IWineD3DSurface_GetPalette(This->WineD3DSurface, &wine_pal);
326         if( ret_value != D3D_OK)
327         {
328             ERR("IWineD3DSurface::GetPalette failed! This is unexpected\n");
329             LeaveCriticalSection(&ddraw_cs);
330             return D3DERR_TEXTURE_LOAD_FAILED;
331         }
332         if(wine_pal)
333         {
334             ret_value = IWineD3DPalette_GetParent(wine_pal, (IUnknown **) &pal);
335             if(ret_value != D3D_OK)
336             {
337                 ERR("IWineD3DPalette::GetParent failed! This is unexpected\n");
338                 LeaveCriticalSection(&ddraw_cs);
339                 return D3DERR_TEXTURE_LOAD_FAILED;
340             }
341         }
342
343         ret_value = IWineD3DSurface_GetPalette(src_ptr->WineD3DSurface, &wine_pal_src);
344         if( ret_value != D3D_OK)
345         {
346             ERR("IWineD3DSurface::GetPalette failed! This is unexpected\n");
347             LeaveCriticalSection(&ddraw_cs);
348             return D3DERR_TEXTURE_LOAD_FAILED;
349         }
350         if(wine_pal_src)
351         {
352             ret_value = IWineD3DPalette_GetParent(wine_pal_src, (IUnknown **) &pal_src);
353             if(ret_value != D3D_OK)
354             {
355                 ERR("IWineD3DPalette::GetParent failed! This is unexpected\n");
356                 if (pal) IDirectDrawPalette_Release(pal);
357                 LeaveCriticalSection(&ddraw_cs);
358                 return D3DERR_TEXTURE_LOAD_FAILED;
359             }
360         }
361
362         if (pal_src != NULL)
363         {
364             PALETTEENTRY palent[256];
365
366             if (pal == NULL)
367             {
368                 IDirectDrawPalette_Release(pal_src);
369                 LeaveCriticalSection(&ddraw_cs);
370                 return DDERR_NOPALETTEATTACHED;
371             }
372             IDirectDrawPalette_GetEntries(pal_src, 0, 0, 256, palent);
373             IDirectDrawPalette_SetEntries(pal, 0, 0, 256, palent);
374         }
375
376         if (pal) IDirectDrawPalette_Release(pal);
377         if (pal_src) IDirectDrawPalette_Release(pal_src);
378
379         /* Copy one surface on the other */
380         dst_d = (DDSURFACEDESC *)&(This->surface_desc);
381         src_d = (DDSURFACEDESC *)&(src_ptr->surface_desc);
382
383         if ((src_d->dwWidth != dst_d->dwWidth) || (src_d->dwHeight != dst_d->dwHeight))
384         {
385             /* Should also check for same pixel format, u1.lPitch, ... */
386             ERR("Error in surface sizes\n");
387             LeaveCriticalSection(&ddraw_cs);
388             return D3DERR_TEXTURE_LOAD_FAILED;
389         }
390         else
391         {
392             WINED3DLOCKED_RECT pSrcRect, pDstRect;
393
394             /* LPDIRECT3DDEVICE2 d3dd = (LPDIRECT3DDEVICE2) This->D3Ddevice; */
395             /* I should put a macro for the calculus of bpp */
396
397             /* Copy also the ColorKeying stuff */
398             if (src_d->dwFlags & DDSD_CKSRCBLT)
399             {
400                 dst_d->dwFlags |= DDSD_CKSRCBLT;
401                 dst_d->ddckCKSrcBlt.dwColorSpaceLowValue = src_d->ddckCKSrcBlt.dwColorSpaceLowValue;
402                 dst_d->ddckCKSrcBlt.dwColorSpaceHighValue = src_d->ddckCKSrcBlt.dwColorSpaceHighValue;
403             }
404
405             /* Copy the main memory texture into the surface that corresponds to the OpenGL
406               texture object. */
407
408             ret_value = IWineD3DSurface_LockRect(src_ptr->WineD3DSurface, &pSrcRect, NULL, 0);
409             if(ret_value != D3D_OK)
410             {
411                 ERR(" (%p) Locking the source surface failed\n", This);
412                 LeaveCriticalSection(&ddraw_cs);
413                 return D3DERR_TEXTURE_LOAD_FAILED;
414             }
415
416             ret_value = IWineD3DSurface_LockRect(This->WineD3DSurface, &pDstRect, NULL, 0);
417             if(ret_value != D3D_OK)
418             {
419                 ERR(" (%p) Locking the destination surface failed\n", This);
420                 IWineD3DSurface_UnlockRect(src_ptr->WineD3DSurface);
421                 LeaveCriticalSection(&ddraw_cs);
422                 return D3DERR_TEXTURE_LOAD_FAILED;
423             }
424
425             if (This->surface_desc.u4.ddpfPixelFormat.dwFlags & DDPF_FOURCC)
426                 memcpy(pDstRect.pBits, pSrcRect.pBits, src_ptr->surface_desc.u1.dwLinearSize);
427             else
428                 memcpy(pDstRect.pBits, pSrcRect.pBits, pSrcRect.Pitch * src_d->dwHeight);
429
430             IWineD3DSurface_UnlockRect(src_ptr->WineD3DSurface);
431             IWineD3DSurface_UnlockRect(This->WineD3DSurface);
432         }
433
434         if (src_ptr->surface_desc.ddsCaps.dwCaps & DDSCAPS_MIPMAP)
435         {
436             src_ptr = get_sub_mimaplevel(src_ptr);
437         }
438         else
439         {
440             src_ptr = NULL;
441         }
442         if (This->surface_desc.ddsCaps.dwCaps & DDSCAPS_MIPMAP)
443         {
444             This = get_sub_mimaplevel(This);
445         }
446         else
447         {
448             This = NULL;
449         }
450
451         if ((src_ptr == NULL) || (This == NULL))
452         {
453             if (src_ptr != This)
454             {
455                 ERR(" Loading surface with different mipmap structure !!!\n");
456             }
457             break;
458         }
459     }
460
461     LeaveCriticalSection(&ddraw_cs);
462     return ret_value;
463 }
464
465 static HRESULT WINAPI
466 Thunk_IDirect3DTextureImpl_1_Load(IDirect3DTexture *iface,
467                                   IDirect3DTexture *D3DTexture)
468 {
469     IDirectDrawSurfaceImpl *This = surface_from_texture1(iface);
470     IDirectDrawSurfaceImpl *Texture = surface_from_texture1(D3DTexture);
471     TRACE("(%p)->(%p) thunking to IDirect3DTexture2 interface.\n", This, Texture);
472
473     return IDirect3DTexture2_Load((IDirect3DTexture2 *)&This->IDirect3DTexture2_vtbl,
474             D3DTexture ? (IDirect3DTexture2 *)&surface_from_texture1(D3DTexture)->IDirect3DTexture2_vtbl : NULL);
475 }
476
477 /*****************************************************************************
478  * The VTables
479  *****************************************************************************/
480 const IDirect3DTexture2Vtbl IDirect3DTexture2_Vtbl =
481 {
482     Thunk_IDirect3DTextureImpl_2_QueryInterface,
483     Thunk_IDirect3DTextureImpl_2_AddRef,
484     Thunk_IDirect3DTextureImpl_2_Release,
485     IDirect3DTextureImpl_GetHandle,
486     IDirect3DTextureImpl_PaletteChanged,
487     IDirect3DTextureImpl_Load,
488 };
489
490
491 const IDirect3DTextureVtbl IDirect3DTexture1_Vtbl =
492 {
493     Thunk_IDirect3DTextureImpl_1_QueryInterface,
494     Thunk_IDirect3DTextureImpl_1_AddRef,
495     Thunk_IDirect3DTextureImpl_1_Release,
496     IDirect3DTextureImpl_1_Initialize,
497     Thunk_IDirect3DTextureImpl_1_GetHandle,
498     Thunk_IDirect3DTextureImpl_1_PaletteChanged,
499     Thunk_IDirect3DTextureImpl_1_Load,
500     IDirect3DTextureImpl_1_Unload,
501 };