Header files must not include config.h.
[wine] / dlls / ddraw / d3dtexture.c
1 /* Direct3D Texture
2  * Copyright (c) 1998 Lionel ULMER
3  *
4  * This file contains the implementation of interface Direct3DTexture2.
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public
8  * License as published by the Free Software Foundation; either
9  * version 2.1 of the License, or (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with this library; if not, write to the Free Software
18  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
19  */
20
21 #include "config.h"
22
23 #include <string.h>
24
25 #define NONAMELESSUNION
26 #define NONAMELESSSTRUCT
27 #include "windef.h"
28 #include "winerror.h"
29 #include "objbase.h"
30 #include "ddraw.h"
31 #include "d3d.h"
32 #include "wine/debug.h"
33
34 #include "mesa_private.h"
35
36 WINE_DEFAULT_DEBUG_CHANNEL(ddraw);
37
38 /* Define this if you want to save to a file all the textures used by a game
39    (can be funny to see how they managed to cram all the pictures in
40    texture memory) */
41 #undef TEXTURE_SNOOP
42
43 #ifdef TEXTURE_SNOOP
44 #include <stdio.h>
45
46 static void 
47 snoop_texture(IDirectDrawSurfaceImpl *This) {
48     IDirect3DTextureGLImpl *glThis = (IDirect3DTextureGLImpl *) This->tex_private;
49     char buf[128];
50     FILE *f;
51     
52     sprintf(buf, "tex_%05d.pnm", glThis->tex_name);
53     f = fopen(buf, "wb");
54     DDRAW_dump_surface_to_disk(This, f);
55 }
56
57 #else
58
59 #define snoop_texture(a)
60
61 #endif
62
63 /*******************************************************************************
64  *                         IDirectSurface callback methods
65  */
66 HRESULT
67 gltex_upload_texture(IDirectDrawSurfaceImpl *This) {
68     IDirect3DTextureGLImpl *glThis = (IDirect3DTextureGLImpl *) This->tex_private;
69 #if 0
70     static BOOL color_table_queried = FALSE;
71 #endif
72     void (*ptr_ColorTableEXT) (GLenum target, GLenum internalformat,
73                                GLsizei width, GLenum format, GLenum type, const GLvoid *table) = NULL;
74     BOOL upload_done = FALSE;
75     BOOL error = FALSE;
76     GLenum format = GL_RGBA, pixel_format = GL_UNSIGNED_BYTE; /* This is only to prevent warnings.. */
77     VOID *surface = NULL;
78
79     DDSURFACEDESC *src_d = (DDSURFACEDESC *)&(This->surface_desc);
80
81     glBindTexture(GL_TEXTURE_2D, glThis->tex_name);
82
83     if (glThis->dirty_flag == FALSE) {
84         TRACE(" activating OpenGL texture id %d.\n", glThis->tex_name);
85         return DD_OK;
86     } else {
87         TRACE(" activating and uploading texture id %d (initial done = %d).\n", glThis->tex_name, glThis->initial_upload_done);
88     }
89
90     /* Texture snooping for the curious :-) */
91     snoop_texture(This);
92     
93     if (src_d->ddpfPixelFormat.dwFlags & DDPF_PALETTEINDEXED8) {
94           /* ****************
95              Paletted Texture
96              **************** */
97         IDirectDrawPaletteImpl* pal = This->palette;
98         BYTE table[256][4];
99         int i;
100
101 #if 0
102         if (color_table_queried == FALSE) {
103             ptr_ColorTableEXT =
104                 ((Mesa_DeviceCapabilities *) ((x11_dd_private *) This->surface->s.ddraw->d->private)->device_capabilities)->ptr_ColorTableEXT;
105         }
106 #endif
107         
108         if (pal == NULL) {
109             /* Upload a black texture. The real one will be uploaded on palette change */
110             WARN("Palettized texture Loading with a NULL palette !\n");
111             memset(table, 0, 256 * 4);
112         } else {
113             /* Get the surface's palette */
114             for (i = 0; i < 256; i++) {
115                 table[i][0] = pal->palents[i].peRed;
116                 table[i][1] = pal->palents[i].peGreen;
117                 table[i][2] = pal->palents[i].peBlue;
118                 if ((src_d->dwFlags & DDSD_CKSRCBLT) &&
119                     (i >= src_d->ddckCKSrcBlt.dwColorSpaceLowValue) &&
120                     (i <= src_d->ddckCKSrcBlt.dwColorSpaceHighValue))
121                     /* We should maybe here put a more 'neutral' color than the standard bright purple
122                        one often used by application to prevent the nice purple borders when bi-linear
123                        filtering is on */
124                     table[i][3] = 0x00;
125                 else
126                     table[i][3] = 0xFF;
127             }
128         }
129
130         if (ptr_ColorTableEXT != NULL) {
131             /* use Paletted Texture Extension */
132             ptr_ColorTableEXT(GL_TEXTURE_2D,    /* target */
133                               GL_RGBA,          /* internal format */
134                               256,              /* table size */
135                               GL_RGBA,          /* table format */
136                               GL_UNSIGNED_BYTE, /* table type */
137                               table);           /* the color table */
138             
139             glTexImage2D(GL_TEXTURE_2D,       /* target */
140                          This->mipmap_level,                   /* level */
141                          GL_COLOR_INDEX8_EXT, /* internal format */
142                          src_d->dwWidth, src_d->dwHeight, /* width, height */
143                          0,                   /* border */
144                          GL_COLOR_INDEX,      /* texture format */
145                          GL_UNSIGNED_BYTE,    /* texture type */
146                          src_d->lpSurface); /* the texture */
147
148             upload_done = TRUE;
149         } else {
150             DWORD i;
151             BYTE *src = (BYTE *) src_d->lpSurface, *dst;
152
153             surface = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, src_d->dwWidth * src_d->dwHeight * sizeof(DWORD));
154             dst = (BYTE *) surface;
155             
156             for (i = 0; i < src_d->dwHeight * src_d->dwWidth; i++) {
157                 BYTE color = *src++;
158                 *dst++ = table[color][0];
159                 *dst++ = table[color][1];
160                 *dst++ = table[color][2];
161                 *dst++ = table[color][3];
162             }
163             
164             format = GL_RGBA;
165             pixel_format = GL_UNSIGNED_BYTE;
166         }
167     } else if (src_d->ddpfPixelFormat.dwFlags & DDPF_RGB) {
168             /* ************
169                RGB Textures
170                ************ */
171         if (src_d->ddpfPixelFormat.u1.dwRGBBitCount == 8) {
172             if ((src_d->ddpfPixelFormat.u2.dwRBitMask == 0xE0) &&
173                 (src_d->ddpfPixelFormat.u3.dwGBitMask == 0x1C) &&
174                 (src_d->ddpfPixelFormat.u4.dwBBitMask == 0x03)) {
175                 /* **********************
176                    GL_UNSIGNED_BYTE_3_3_2
177                    ********************** */
178                 if (src_d->dwFlags & DDSD_CKSRCBLT) {
179                     /* This texture format will never be used.. So do not care about color keying
180                        up until the point in time it will be needed :-) */
181                     error = TRUE;
182                 } else {
183                     format = GL_RGB;
184                     pixel_format = GL_UNSIGNED_BYTE_3_3_2;
185                 }
186             } else {
187                 error = TRUE;
188             }
189         } else if (src_d->ddpfPixelFormat.u1.dwRGBBitCount == 16) {
190             if ((src_d->ddpfPixelFormat.u2.dwRBitMask ==        0xF800) &&
191                 (src_d->ddpfPixelFormat.u3.dwGBitMask ==        0x07E0) &&
192                 (src_d->ddpfPixelFormat.u4.dwBBitMask ==        0x001F) &&
193                 (src_d->ddpfPixelFormat.u5.dwRGBAlphaBitMask == 0x0000)) {
194                 if (src_d->dwFlags & DDSD_CKSRCBLT) {
195                     /* Converting the 565 format in 5551 packed to emulate color-keying.
196
197                        Note : in all these conversion, it would be best to average the averaging
198                               pixels to get the color of the pixel that will be color-keyed to
199                               prevent 'color bleeding'. This will be done later on if ever it is
200                               too visible.
201
202                        Note2: when using color-keying + alpha, are the alpha bits part of the
203                               color-space or not ?
204                     */
205                     DWORD i;
206                     WORD *src = (WORD *) src_d->lpSurface, *dst;
207                     
208                     surface = (WORD *) HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, src_d->dwWidth * src_d->dwHeight * sizeof(WORD));
209                     dst = (WORD *) surface;
210                     for (i = 0; i < src_d->dwHeight * src_d->dwWidth; i++) {
211                         WORD color = *src++;
212                         *dst = ((color & 0xFFC0) | ((color & 0x1F) << 1));
213                         if ((color < src_d->ddckCKSrcBlt.dwColorSpaceLowValue) ||
214                             (color > src_d->ddckCKSrcBlt.dwColorSpaceHighValue))
215                             *dst |= 0x0001;
216                         dst++;
217                     }
218                 
219                     format = GL_RGBA;
220                     pixel_format = GL_UNSIGNED_SHORT_5_5_5_1;
221                 } else {
222                     format = GL_RGB;
223                     pixel_format = GL_UNSIGNED_SHORT_5_6_5;
224                 }
225             } else if ((src_d->ddpfPixelFormat.u2.dwRBitMask ==        0xF800) &&
226                        (src_d->ddpfPixelFormat.u3.dwGBitMask ==        0x07C0) &&
227                        (src_d->ddpfPixelFormat.u4.dwBBitMask ==        0x003E) &&
228                        (src_d->ddpfPixelFormat.u5.dwRGBAlphaBitMask == 0x0001)) {
229                 format = GL_RGBA;
230                 pixel_format = GL_UNSIGNED_SHORT_5_5_5_1;               
231                 if (src_d->dwFlags & DDSD_CKSRCBLT) {
232                     /* Change the alpha value of the color-keyed pixels to emulate color-keying. */
233                     DWORD i;
234                     WORD *src = (WORD *) src_d->lpSurface, *dst;
235                     
236                     surface = (WORD *) HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, src_d->dwWidth * src_d->dwHeight * sizeof(WORD));
237                     dst = (WORD *) surface;
238                     for (i = 0; i < src_d->dwHeight * src_d->dwWidth; i++) {
239                         WORD color = *src++;
240                         *dst = color & 0xFFFE;
241                         if ((color < src_d->ddckCKSrcBlt.dwColorSpaceLowValue) ||
242                             (color > src_d->ddckCKSrcBlt.dwColorSpaceHighValue))
243                             *dst |= color & 0x0001;
244                         dst++;
245                     }
246                 }
247             } else if ((src_d->ddpfPixelFormat.u2.dwRBitMask ==        0xF000) &&
248                        (src_d->ddpfPixelFormat.u3.dwGBitMask ==        0x0F00) &&
249                        (src_d->ddpfPixelFormat.u4.dwBBitMask ==        0x00F0) &&
250                        (src_d->ddpfPixelFormat.u5.dwRGBAlphaBitMask == 0x000F)) {
251                 format = GL_RGBA;
252                 pixel_format = GL_UNSIGNED_SHORT_4_4_4_4;             
253                 if (src_d->dwFlags & DDSD_CKSRCBLT) {
254                     /* Change the alpha value of the color-keyed pixels to emulate color-keying. */
255                     DWORD i;
256                     WORD *src = (WORD *) src_d->lpSurface, *dst;
257                     
258                     surface = (WORD *) HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, src_d->dwWidth * src_d->dwHeight * sizeof(WORD));
259                     dst = (WORD *) surface;
260                     for (i = 0; i < src_d->dwHeight * src_d->dwWidth; i++) {
261                         WORD color = *src++;
262                         *dst = color & 0xFFF0;
263                         if ((color < src_d->ddckCKSrcBlt.dwColorSpaceLowValue) ||
264                             (color > src_d->ddckCKSrcBlt.dwColorSpaceHighValue))
265                             *dst |= color & 0x000F;
266                         dst++;
267                     }
268                 }
269             } else if ((src_d->ddpfPixelFormat.u2.dwRBitMask ==        0x0F00) &&
270                        (src_d->ddpfPixelFormat.u3.dwGBitMask ==        0x00F0) &&
271                        (src_d->ddpfPixelFormat.u4.dwBBitMask ==        0x000F) &&
272                        (src_d->ddpfPixelFormat.u5.dwRGBAlphaBitMask == 0xF000)) {
273                 /* Move the four Alpha bits... */
274                 DWORD i;
275                 WORD *src = (WORD *) src_d->lpSurface, *dst;
276                 
277                 surface = (WORD *) HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, src_d->dwWidth * src_d->dwHeight * sizeof(WORD));
278                 dst = surface;
279                 
280                 if (src_d->dwFlags & DDSD_CKSRCBLT) {
281                     for (i = 0; i < src_d->dwHeight * src_d->dwWidth; i++) {
282                         WORD color = *src++;
283                         *dst = (color & 0x0FFF) << 4;
284                         if ((color < src_d->ddckCKSrcBlt.dwColorSpaceLowValue) ||
285                             (color > src_d->ddckCKSrcBlt.dwColorSpaceHighValue))
286                             *dst |= (color & 0xF000) >> 12;
287                         dst++;
288                     }
289                 } else {
290                     for (i = 0; i < src_d->dwHeight * src_d->dwWidth; i++) {
291                         WORD color = *src++;
292                         *dst++ = (((color & 0x0FFF) << 4) |
293                                   ((color & 0xF000) >> 12));
294                     }
295                 }
296
297                 format = GL_RGBA;
298                 pixel_format = GL_UNSIGNED_SHORT_4_4_4_4;               
299             } else if ((src_d->ddpfPixelFormat.u2.dwRBitMask ==        0x7C00) &&
300                        (src_d->ddpfPixelFormat.u3.dwGBitMask ==        0x03E0) &&
301                        (src_d->ddpfPixelFormat.u4.dwBBitMask ==        0x001F) &&
302                        (src_d->ddpfPixelFormat.u5.dwRGBAlphaBitMask == 0x8000)) {
303                 /* Converting the 1555 format in 5551 packed */
304                 DWORD i;
305                 WORD *src = (WORD *) src_d->lpSurface, *dst;
306                 
307                 surface = (WORD *) HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, src_d->dwWidth * src_d->dwHeight * sizeof(WORD));
308                 dst = (WORD *) surface;
309                 
310                 if (src_d->dwFlags & DDSD_CKSRCBLT) {
311                     for (i = 0; i < src_d->dwHeight * src_d->dwWidth; i++) {
312                         WORD color = *src++;
313                         *dst = (color & 0x7FFF) << 1;
314                         if ((color < src_d->ddckCKSrcBlt.dwColorSpaceLowValue) ||
315                             (color > src_d->ddckCKSrcBlt.dwColorSpaceHighValue))
316                             *dst |= (color & 0x8000) >> 15;
317                         dst++;
318                     }
319                 } else {
320                     for (i = 0; i < src_d->dwHeight * src_d->dwWidth; i++) {
321                         WORD color = *src++;
322                         *dst++ = (((color & 0x7FFF) << 1) |
323                                   ((color & 0x8000) >> 15));
324                     }             
325                 }
326                 
327                 format = GL_RGBA;
328                 pixel_format = GL_UNSIGNED_SHORT_5_5_5_1;
329             } else {
330                 error = TRUE;
331             }
332         } else if (src_d->ddpfPixelFormat.u1.dwRGBBitCount == 24) {
333             if ((src_d->ddpfPixelFormat.u2.dwRBitMask ==        0x00FF0000) &&
334                 (src_d->ddpfPixelFormat.u3.dwGBitMask ==        0x0000FF00) &&
335                 (src_d->ddpfPixelFormat.u4.dwBBitMask ==        0x000000FF) &&
336                 (src_d->ddpfPixelFormat.u5.dwRGBAlphaBitMask == 0x00000000)) {
337                 if (src_d->dwFlags & DDSD_CKSRCBLT) {
338                     /* This is a pain :-) */
339                     DWORD i;
340                     BYTE *src = (BYTE *) src_d->lpSurface;
341                     DWORD *dst;
342                     
343                     surface = (DWORD *) HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, src_d->dwWidth * src_d->dwHeight * sizeof(DWORD));
344                     dst = (DWORD *) surface;
345                     for (i = 0; i < src_d->dwHeight * src_d->dwWidth; i++) {
346                         DWORD color = *((DWORD *) src) & 0x00FFFFFF;
347                         src += 3;
348                         *dst = *src++ << 8;
349                         if ((color < src_d->ddckCKSrcBlt.dwColorSpaceLowValue) ||
350                             (color > src_d->ddckCKSrcBlt.dwColorSpaceHighValue))
351                             *dst |= 0xFF;
352                         dst++;
353                     }
354                     format = GL_RGBA;
355                     pixel_format = GL_UNSIGNED_INT_8_8_8_8;
356                 } else {
357                   format = GL_BGR;
358                   pixel_format = GL_UNSIGNED_BYTE;
359                 }
360             } else {
361                 error = TRUE;
362             }
363         } else if (src_d->ddpfPixelFormat.u1.dwRGBBitCount == 32) {
364             if ((src_d->ddpfPixelFormat.u2.dwRBitMask ==        0xFF000000) &&
365                 (src_d->ddpfPixelFormat.u3.dwGBitMask ==        0x00FF0000) &&
366                 (src_d->ddpfPixelFormat.u4.dwBBitMask ==        0x0000FF00) &&
367                 (src_d->ddpfPixelFormat.u5.dwRGBAlphaBitMask == 0x000000FF)) {
368                 if (src_d->dwFlags & DDSD_CKSRCBLT) {
369                     /* Just use the alpha component to handle color-keying... */
370                     DWORD i;
371                     DWORD *src = (DWORD *) src_d->lpSurface, *dst;
372                 
373                     surface = (DWORD *) HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, src_d->dwWidth * src_d->dwHeight * sizeof(DWORD));
374                     dst = (DWORD *) surface;
375                     for (i = 0; i < src_d->dwHeight * src_d->dwWidth; i++) {
376                         DWORD color = *src++;
377                         *dst = color & 0xFFFFFF00;
378                         if ((color < src_d->ddckCKSrcBlt.dwColorSpaceLowValue) ||
379                             (color > src_d->ddckCKSrcBlt.dwColorSpaceHighValue))
380                             *dst |= color & 0x000000FF;
381                         dst++;
382                     }
383                 }
384                 format = GL_RGBA;
385                 pixel_format = GL_UNSIGNED_INT_8_8_8_8;
386             } else if ((src_d->ddpfPixelFormat.u2.dwRBitMask ==        0x00FF0000) &&
387                        (src_d->ddpfPixelFormat.u3.dwGBitMask ==        0x0000FF00) &&
388                        (src_d->ddpfPixelFormat.u4.dwBBitMask ==        0x000000FF) &&
389                        (src_d->ddpfPixelFormat.u5.dwRGBAlphaBitMask == 0x00000000)) {
390                 /* Just add an alpha component and handle color-keying... */
391                 DWORD i;
392                 DWORD *src = (DWORD *) src_d->lpSurface, *dst;
393                 
394                 surface = (DWORD *) HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, src_d->dwWidth * src_d->dwHeight * sizeof(DWORD));
395                 dst = (DWORD *) surface;
396                 
397                 if (src_d->dwFlags & DDSD_CKSRCBLT) {
398                     for (i = 0; i < src_d->dwHeight * src_d->dwWidth; i++) {
399                         DWORD color = *src++;
400                         *dst = color << 8;
401                         if ((color < src_d->ddckCKSrcBlt.dwColorSpaceLowValue) ||
402                             (color > src_d->ddckCKSrcBlt.dwColorSpaceHighValue))
403                             *dst |= 0xFF;
404                         dst++;
405                     }
406                 } else {
407                     for (i = 0; i < src_d->dwHeight * src_d->dwWidth; i++) {
408                         *dst++ = (*src++ << 8) | 0xFF;
409                     }
410                 }
411                 format = GL_RGBA;
412                 pixel_format = GL_UNSIGNED_INT_8_8_8_8;
413             } else {
414                 error = TRUE;
415             }
416         } else {
417             error = TRUE;
418         }
419     } else {
420         error = TRUE;
421     } 
422
423     if ((upload_done == FALSE) && (error == FALSE)) {
424         if (glThis->initial_upload_done == FALSE) {
425             glTexImage2D(GL_TEXTURE_2D,
426                          This->mipmap_level,
427                          format,
428                          src_d->dwWidth, src_d->dwHeight,
429                          0,
430                          format,
431                          pixel_format,
432                          surface == NULL ? src_d->lpSurface : surface);
433             glThis->initial_upload_done = TRUE;
434         } else {
435             glTexSubImage2D(GL_TEXTURE_2D,
436                             This->mipmap_level,
437                             0, 0,
438                             src_d->dwWidth, src_d->dwHeight,
439                             format,
440                             pixel_format,
441                             surface == NULL ? src_d->lpSurface : surface);
442         }
443         
444         if (surface) HeapFree(GetProcessHeap(), 0, surface);
445     } else if (error == TRUE) {
446         if (ERR_ON(ddraw)) {
447             ERR("Unsupported pixel format for textures : \n");
448             DDRAW_dump_pixelformat(&src_d->ddpfPixelFormat);
449         }
450     }
451
452     glThis->dirty_flag = FALSE;
453
454     return DD_OK;
455 }
456
457 HRESULT WINAPI
458 Main_IDirect3DTextureImpl_1_Initialize(LPDIRECT3DTEXTURE iface,
459                                        LPDIRECT3DDEVICE lpDirect3DDevice,
460                                        LPDIRECTDRAWSURFACE lpDDSurface)
461 {
462     ICOM_THIS_FROM(IDirectDrawSurfaceImpl, IDirect3DTexture, iface);
463     FIXME("(%p/%p)->(%p,%p) no-op...\n", This, iface, lpDirect3DDevice, lpDDSurface);
464     return DD_OK;
465 }
466
467 static HRESULT
468 gltex_setcolorkey_cb(IDirectDrawSurfaceImpl *This, DWORD dwFlags, LPDDCOLORKEY ckey )
469 {
470     IDirect3DTextureGLImpl *glThis = (IDirect3DTextureGLImpl *) This->tex_private;
471
472     glThis->dirty_flag = TRUE;
473
474     return DD_OK;
475 }
476
477 HRESULT WINAPI
478 Main_IDirect3DTextureImpl_2_1T_PaletteChanged(LPDIRECT3DTEXTURE2 iface,
479                                               DWORD dwStart,
480                                               DWORD dwCount)
481 {
482     ICOM_THIS_FROM(IDirectDrawSurfaceImpl, IDirect3DTexture2, iface);
483     FIXME("(%p/%p)->(%08lx,%08lx): stub!\n", This, iface, dwStart, dwCount);
484     return DD_OK;
485 }
486
487 HRESULT WINAPI
488 Main_IDirect3DTextureImpl_1_Unload(LPDIRECT3DTEXTURE iface)
489 {
490     ICOM_THIS_FROM(IDirectDrawSurfaceImpl, IDirect3DTexture, iface);
491     FIXME("(%p/%p)->(): stub!\n", This, iface);
492     return DD_OK;
493 }
494
495 HRESULT WINAPI
496 Main_IDirect3DTextureImpl_2_1T_GetHandle(LPDIRECT3DTEXTURE2 iface,
497                                          LPDIRECT3DDEVICE2 lpDirect3DDevice2,
498                                          LPD3DTEXTUREHANDLE lpHandle)
499 {
500     ICOM_THIS_FROM(IDirectDrawSurfaceImpl, IDirect3DTexture2, iface);
501     IDirect3DDeviceImpl *lpDeviceImpl = ICOM_OBJECT(IDirect3DDeviceImpl, IDirect3DDevice2, lpDirect3DDevice2);
502     
503     TRACE("(%p/%p)->(%p,%p)\n", This, iface, lpDirect3DDevice2, lpHandle);
504
505     /* The handle is simply the pointer to the implementation structure */
506     *lpHandle = (D3DTEXTUREHANDLE) This;
507
508     TRACE(" returning handle %08lx.\n", *lpHandle);
509     
510     /* Now set the device for this texture */
511     This->d3ddevice = lpDeviceImpl;
512
513     return D3D_OK;
514 }
515
516 HRESULT WINAPI
517 Main_IDirect3DTextureImpl_2_1T_Load(LPDIRECT3DTEXTURE2 iface,
518                                     LPDIRECT3DTEXTURE2 lpD3DTexture2)
519 {
520     ICOM_THIS_FROM(IDirectDrawSurfaceImpl, IDirect3DTexture2, iface);
521     FIXME("(%p/%p)->(%p): stub!\n", This, iface, lpD3DTexture2);
522     return DD_OK;
523 }
524
525 static void gltex_set_palette(IDirectDrawSurfaceImpl* This, IDirectDrawPaletteImpl* pal)
526 {
527     IDirect3DTextureGLImpl *glThis = (IDirect3DTextureGLImpl *) This->tex_private;
528     
529     /* First call the previous set_palette function */
530     glThis->set_palette(This, pal);
531     
532     /* And set the dirty flag */
533     glThis->dirty_flag = TRUE;
534 }
535
536 static void
537 gltex_final_release(IDirectDrawSurfaceImpl *This)
538 {
539     IDirect3DTextureGLImpl *glThis = (IDirect3DTextureGLImpl *) This->tex_private;
540     DWORD mem_used;
541     int i;
542
543     TRACE(" deleting texture with GL id %d.\n", glThis->tex_name);
544
545     /* And delete texture handle */
546     ENTER_GL();
547     if (glThis->tex_name != 0)
548         glDeleteTextures(1, &(glThis->tex_name));
549     LEAVE_GL(); 
550
551     /* And if this texture was the current one, remove it at the device level */
552     if (This->d3ddevice != NULL)
553         for (i = 0; i < MAX_TEXTURES; i++)
554             if (This->d3ddevice->current_texture[i] == This)
555                 This->d3ddevice->current_texture[i] = NULL;
556
557     /* All this should be part of main surface management not just a hack for texture.. */
558     if (glThis->loaded) {
559         mem_used = This->surface_desc.dwHeight *
560                    This->surface_desc.u1.lPitch;
561         This->ddraw_owner->free_memory(This->ddraw_owner, mem_used);
562     }
563
564     glThis->final_release(This);
565 }
566
567 static void
568 gltex_lock_update(IDirectDrawSurfaceImpl* This, LPCRECT pRect, DWORD dwFlags)
569 {
570     IDirect3DTextureGLImpl *glThis = (IDirect3DTextureGLImpl *) This->tex_private;
571     
572     glThis->lock_update(This, pRect, dwFlags);
573 }
574
575 static void
576 gltex_unlock_update(IDirectDrawSurfaceImpl* This, LPCRECT pRect)
577 {
578     IDirect3DTextureGLImpl *glThis = (IDirect3DTextureGLImpl *) This->tex_private;
579
580     glThis->unlock_update(This, pRect);
581     
582     /* Set the dirty flag according to the lock type */
583     if ((This->lastlocktype & DDLOCK_READONLY) == 0)
584         glThis->dirty_flag = TRUE;
585 }
586
587 HRESULT WINAPI
588 GL_IDirect3DTextureImpl_2_1T_Load(LPDIRECT3DTEXTURE2 iface,
589                                   LPDIRECT3DTEXTURE2 lpD3DTexture2)
590 {
591     ICOM_THIS_FROM(IDirectDrawSurfaceImpl, IDirect3DTexture2, iface);
592     IDirect3DTextureGLImpl *glThis = (IDirect3DTextureGLImpl *) This->tex_private;
593     IDirectDrawSurfaceImpl *lpD3DTextureImpl = ICOM_OBJECT(IDirectDrawSurfaceImpl, IDirect3DTexture2, lpD3DTexture2);
594     DWORD mem_used;
595     DDSURFACEDESC *src_d, *dst_d;
596     HRESULT ret_value = D3D_OK;
597     
598     TRACE("(%p/%p)->(%p)\n", This, iface, lpD3DTexture2);
599
600     if (glThis != NULL) {
601         if (glThis->loaded == FALSE) {
602             /* Only check memory for not already loaded texture... */
603             mem_used = This->surface_desc.dwHeight *
604                        This->surface_desc.u1.lPitch;
605             if (This->ddraw_owner->allocate_memory(This->ddraw_owner, mem_used) < 0) {
606                 TRACE(" out of virtual memory... Warning application.\n");
607                 return D3DERR_TEXTURE_LOAD_FAILED;
608             }
609         }
610         glThis->loaded = TRUE;
611     }
612     
613     TRACE("Copied surface %p to surface %p\n", lpD3DTextureImpl, This);
614
615     if ( This->surface_desc.ddsCaps.dwCaps & DDSCAPS_ALLOCONLOAD )
616         /* If the surface is not allocated and its location is not yet specified,
617            force it to video memory */ 
618         if ( !(This->surface_desc.ddsCaps.dwCaps & (DDSCAPS_SYSTEMMEMORY|DDSCAPS_VIDEOMEMORY)) )
619             This->surface_desc.ddsCaps.dwCaps |= DDSCAPS_VIDEOMEMORY;
620
621     /* Suppress the ALLOCONLOAD flag */
622     This->surface_desc.ddsCaps.dwCaps &= ~DDSCAPS_ALLOCONLOAD;
623     
624     /* After seeing some logs, not sure at all about this... */
625     if (This->palette == NULL) {
626         This->palette = lpD3DTextureImpl->palette;
627         if (lpD3DTextureImpl->palette != NULL) IDirectDrawPalette_AddRef(ICOM_INTERFACE(lpD3DTextureImpl->palette,
628                                                                                         IDirectDrawPalette));
629     } else {
630         if (lpD3DTextureImpl->palette != NULL) {
631             PALETTEENTRY palent[256];
632             IDirectDrawPalette *pal_int = ICOM_INTERFACE(lpD3DTextureImpl->palette, IDirectDrawPalette);
633             IDirectDrawPalette_GetEntries(pal_int, 0, 0, 256, palent);
634             IDirectDrawPalette_SetEntries(ICOM_INTERFACE(This->palette, IDirectDrawPalette),
635                                           0, 0, 256, palent);
636         }
637     }
638     
639     /* Copy one surface on the other */
640     dst_d = (DDSURFACEDESC *)&(This->surface_desc);
641     src_d = (DDSURFACEDESC *)&(lpD3DTextureImpl->surface_desc);
642
643     if ((src_d->dwWidth != dst_d->dwWidth) || (src_d->dwHeight != dst_d->dwHeight)) {
644         /* Should also check for same pixel format, u1.lPitch, ... */
645         ERR("Error in surface sizes\n");
646         return D3DERR_TEXTURE_LOAD_FAILED;
647     } else {
648         /* LPDIRECT3DDEVICE2 d3dd = (LPDIRECT3DDEVICE2) This->D3Ddevice; */
649         /* I should put a macro for the calculus of bpp */
650
651         /* Copy also the ColorKeying stuff */
652         if (src_d->dwFlags & DDSD_CKSRCBLT) {
653             dst_d->dwFlags |= DDSD_CKSRCBLT;
654             dst_d->ddckCKSrcBlt.dwColorSpaceLowValue = src_d->ddckCKSrcBlt.dwColorSpaceLowValue;
655             dst_d->ddckCKSrcBlt.dwColorSpaceHighValue = src_d->ddckCKSrcBlt.dwColorSpaceHighValue;
656         }
657
658         /* Copy the main memory texture into the surface that corresponds to the OpenGL
659            texture object. */
660         memcpy(dst_d->lpSurface, src_d->lpSurface, src_d->u1.lPitch * src_d->dwHeight);
661
662         if (glThis != NULL) {
663             /* If the GetHandle was not done, it is an error... */
664             if (glThis->tex_name == 0) ERR("Unbound GL texture !!!\n");
665
666             /* Set this texture as dirty */
667             glThis->dirty_flag = TRUE;
668         }
669     }
670
671     return ret_value;
672 }
673
674 HRESULT WINAPI
675 Thunk_IDirect3DTextureImpl_2_QueryInterface(LPDIRECT3DTEXTURE2 iface,
676                                             REFIID riid,
677                                             LPVOID* obp)
678 {
679     TRACE("(%p)->(%s,%p) thunking to IDirectDrawSurface7 interface.\n", iface, debugstr_guid(riid), obp);
680     return IDirectDrawSurface7_QueryInterface(COM_INTERFACE_CAST(IDirectDrawSurfaceImpl, IDirect3DTexture2, IDirectDrawSurface7, iface),
681                                               riid,
682                                               obp);
683 }
684
685 ULONG WINAPI
686 Thunk_IDirect3DTextureImpl_2_AddRef(LPDIRECT3DTEXTURE2 iface)
687 {
688     TRACE("(%p)->() thunking to IDirectDrawSurface7 interface.\n", iface);
689     return IDirectDrawSurface7_AddRef(COM_INTERFACE_CAST(IDirectDrawSurfaceImpl, IDirect3DTexture2, IDirectDrawSurface7, iface));
690 }
691
692 ULONG WINAPI
693 Thunk_IDirect3DTextureImpl_2_Release(LPDIRECT3DTEXTURE2 iface)
694 {
695     TRACE("(%p)->() thunking to IDirectDrawSurface7 interface.\n", iface);
696     return IDirectDrawSurface7_Release(COM_INTERFACE_CAST(IDirectDrawSurfaceImpl, IDirect3DTexture2, IDirectDrawSurface7, iface));
697 }
698
699 HRESULT WINAPI
700 Thunk_IDirect3DTextureImpl_1_QueryInterface(LPDIRECT3DTEXTURE iface,
701                                             REFIID riid,
702                                             LPVOID* obp)
703 {
704     TRACE("(%p)->(%s,%p) thunking to IDirectDrawSurface7 interface.\n", iface, debugstr_guid(riid), obp);
705     return IDirectDrawSurface7_QueryInterface(COM_INTERFACE_CAST(IDirectDrawSurfaceImpl, IDirect3DTexture, IDirectDrawSurface7, iface),
706                                               riid,
707                                               obp);
708 }
709
710 ULONG WINAPI
711 Thunk_IDirect3DTextureImpl_1_AddRef(LPDIRECT3DTEXTURE iface)
712 {
713     TRACE("(%p)->() thunking to IDirectDrawSurface7 interface.\n", iface);
714     return IDirectDrawSurface7_AddRef(COM_INTERFACE_CAST(IDirectDrawSurfaceImpl, IDirect3DTexture, IDirectDrawSurface7, iface));
715 }
716
717 ULONG WINAPI
718 Thunk_IDirect3DTextureImpl_1_Release(LPDIRECT3DTEXTURE iface)
719 {
720     TRACE("(%p)->() thunking to IDirectDrawSurface7 interface.\n", iface);
721     return IDirectDrawSurface7_Release(COM_INTERFACE_CAST(IDirectDrawSurfaceImpl, IDirect3DTexture, IDirectDrawSurface7, iface));
722 }
723
724 HRESULT WINAPI
725 Thunk_IDirect3DTextureImpl_1_PaletteChanged(LPDIRECT3DTEXTURE iface,
726                                             DWORD dwStart,
727                                             DWORD dwCount)
728 {
729     TRACE("(%p)->(%08lx,%08lx) thunking to IDirect3DTexture2 interface.\n", iface, dwStart, dwCount);
730     return IDirect3DTexture2_PaletteChanged(COM_INTERFACE_CAST(IDirectDrawSurfaceImpl, IDirect3DTexture, IDirect3DTexture2, iface),
731                                             dwStart,
732                                             dwCount);
733 }
734
735 HRESULT WINAPI
736 Thunk_IDirect3DTextureImpl_1_GetHandle(LPDIRECT3DTEXTURE iface,
737                                        LPDIRECT3DDEVICE lpDirect3DDevice,
738                                        LPD3DTEXTUREHANDLE lpHandle)
739 {
740     TRACE("(%p)->(%p,%p) thunking to IDirect3DTexture2 interface.\n", iface, lpDirect3DDevice, lpHandle);
741     return IDirect3DTexture2_GetHandle(COM_INTERFACE_CAST(IDirectDrawSurfaceImpl, IDirect3DTexture, IDirect3DTexture2, iface),
742                                        COM_INTERFACE_CAST(IDirect3DDeviceImpl, IDirect3DDevice, IDirect3DDevice2, lpDirect3DDevice),
743                                        lpHandle);
744 }
745
746 HRESULT WINAPI
747 Thunk_IDirect3DTextureImpl_1_Load(LPDIRECT3DTEXTURE iface,
748                                   LPDIRECT3DTEXTURE lpD3DTexture)
749 {
750     TRACE("(%p)->(%p) thunking to IDirect3DTexture2 interface.\n", iface, lpD3DTexture);
751     return IDirect3DTexture2_Load(COM_INTERFACE_CAST(IDirectDrawSurfaceImpl, IDirect3DTexture, IDirect3DTexture2, iface),
752                                   COM_INTERFACE_CAST(IDirectDrawSurfaceImpl, IDirect3DTexture, IDirect3DTexture2, lpD3DTexture));
753 }
754
755 #if !defined(__STRICT_ANSI__) && defined(__GNUC__)
756 # define XCAST(fun)     (typeof(VTABLE_IDirect3DTexture2.fun))
757 #else
758 # define XCAST(fun)     (void*)
759 #endif
760
761 ICOM_VTABLE(IDirect3DTexture2) VTABLE_IDirect3DTexture2 =
762 {
763     ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE
764     XCAST(QueryInterface) Thunk_IDirect3DTextureImpl_2_QueryInterface,
765     XCAST(AddRef) Thunk_IDirect3DTextureImpl_2_AddRef,
766     XCAST(Release) Thunk_IDirect3DTextureImpl_2_Release,
767     XCAST(GetHandle) Main_IDirect3DTextureImpl_2_1T_GetHandle,
768     XCAST(PaletteChanged) Main_IDirect3DTextureImpl_2_1T_PaletteChanged,
769     XCAST(Load) GL_IDirect3DTextureImpl_2_1T_Load,
770 };
771
772 #if !defined(__STRICT_ANSI__) && defined(__GNUC__)
773 #undef XCAST
774 #endif
775
776
777 #if !defined(__STRICT_ANSI__) && defined(__GNUC__)
778 # define XCAST(fun)     (typeof(VTABLE_IDirect3DTexture.fun))
779 #else
780 # define XCAST(fun)     (void*)
781 #endif
782
783 ICOM_VTABLE(IDirect3DTexture) VTABLE_IDirect3DTexture =
784 {
785     ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE
786     XCAST(QueryInterface) Thunk_IDirect3DTextureImpl_1_QueryInterface,
787     XCAST(AddRef) Thunk_IDirect3DTextureImpl_1_AddRef,
788     XCAST(Release) Thunk_IDirect3DTextureImpl_1_Release,
789     XCAST(Initialize) Main_IDirect3DTextureImpl_1_Initialize,
790     XCAST(GetHandle) Thunk_IDirect3DTextureImpl_1_GetHandle,
791     XCAST(PaletteChanged) Thunk_IDirect3DTextureImpl_1_PaletteChanged,
792     XCAST(Load) Thunk_IDirect3DTextureImpl_1_Load,
793     XCAST(Unload) Main_IDirect3DTextureImpl_1_Unload,
794 };
795
796 #if !defined(__STRICT_ANSI__) && defined(__GNUC__)
797 #undef XCAST
798 #endif
799
800 HRESULT d3dtexture_create(IDirect3DImpl *d3d, IDirectDrawSurfaceImpl *surf, BOOLEAN at_creation, 
801                           IDirectDrawSurfaceImpl *main)
802 {
803     /* First, initialize the texture vtables... */
804     ICOM_INIT_INTERFACE(surf, IDirect3DTexture,  VTABLE_IDirect3DTexture);
805     ICOM_INIT_INTERFACE(surf, IDirect3DTexture2, VTABLE_IDirect3DTexture2);
806         
807     /* Only create all the private stuff if we actually have an OpenGL context.. */
808     if (d3d->current_device != NULL) {
809         IDirect3DTextureGLImpl *private;
810
811         private = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IDirect3DTextureGLImpl));
812         if (private == NULL) return DDERR_OUTOFMEMORY;
813
814         private->final_release = surf->final_release;
815         private->lock_update = surf->lock_update;
816         private->unlock_update = surf->unlock_update;
817         private->set_palette = surf->set_palette;
818         
819         /* If at creation, we can optimize stuff and wait the first 'unlock' to upload a valid stuff to OpenGL.
820            Otherwise, it will be uploaded here (and may be invalid). */
821         surf->final_release = gltex_final_release;
822         surf->lock_update = gltex_lock_update;
823         surf->unlock_update = gltex_unlock_update;
824         surf->tex_private = private;
825         surf->aux_setcolorkey_cb = gltex_setcolorkey_cb;
826         surf->set_palette = gltex_set_palette;
827
828         ENTER_GL();
829         if (surf->mipmap_level == 0) {
830             glGenTextures(1, &(private->tex_name));
831             if (private->tex_name == 0) ERR("Error at creation of OpenGL texture ID !\n");
832             TRACE(" GL texture created for surface %p (private data at %p and GL id %d).\n", surf, private, private->tex_name);
833         } else {
834             private->tex_name = ((IDirect3DTextureGLImpl *) (main->tex_private))->tex_name;
835             TRACE(" GL texture created for surface %p (private data at %p and GL id reusing id %d from surface %p (%p)).\n",
836                   surf, private, private->tex_name, main, main->tex_private);
837         }
838         LEAVE_GL();
839
840         /* And set the dirty flag accordingly */
841         private->dirty_flag = (at_creation == FALSE);
842         private->initial_upload_done = FALSE;
843     }
844
845     return D3D_OK;
846 }