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