- only enumerate 32 bpp ARGB texture format and remove RGBA one
[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 == 0xFF000000)) {
390                 /* Convert from ARGB (Windows' format) to RGBA.
391                    Note: need to check for GL extensions handling ARGB instead of always converting */
392                 DWORD i;
393                 DWORD *src = (DWORD *) src_d->lpSurface, *dst;
394                 
395                 surface = (DWORD *) HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, src_d->dwWidth * src_d->dwHeight * sizeof(DWORD));
396                 dst = (DWORD *) surface;
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 & 0x00FFFFFF) << 8;
401                         if ((color < src_d->ddckCKSrcBlt.dwColorSpaceLowValue) ||
402                             (color > src_d->ddckCKSrcBlt.dwColorSpaceHighValue))
403                             *dst |= (color & 0xFF000000) >> 24;
404                         dst++;
405                     }
406                 } else {
407                     for (i = 0; i < src_d->dwHeight * src_d->dwWidth; i++) {
408                         DWORD color = *src++;
409                         *dst = (color & 0x00FFFFFF) << 8;
410                         *dst |= (color & 0xFF000000) >> 24;
411                     }
412                 }
413                 format = GL_RGBA;
414                 pixel_format = GL_UNSIGNED_INT_8_8_8_8;
415             } else if ((src_d->ddpfPixelFormat.u2.dwRBitMask ==        0x00FF0000) &&
416                        (src_d->ddpfPixelFormat.u3.dwGBitMask ==        0x0000FF00) &&
417                        (src_d->ddpfPixelFormat.u4.dwBBitMask ==        0x000000FF) &&
418                        (src_d->ddpfPixelFormat.u5.dwRGBAlphaBitMask == 0x00000000)) {
419                 /* Just add an alpha component and handle color-keying... */
420                 DWORD i;
421                 DWORD *src = (DWORD *) src_d->lpSurface, *dst;
422                 
423                 surface = (DWORD *) HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, src_d->dwWidth * src_d->dwHeight * sizeof(DWORD));
424                 dst = (DWORD *) surface;
425                 
426                 if (src_d->dwFlags & DDSD_CKSRCBLT) {
427                     for (i = 0; i < src_d->dwHeight * src_d->dwWidth; i++) {
428                         DWORD color = *src++;
429                         *dst = color << 8;
430                         if ((color < src_d->ddckCKSrcBlt.dwColorSpaceLowValue) ||
431                             (color > src_d->ddckCKSrcBlt.dwColorSpaceHighValue))
432                             *dst |= 0xFF;
433                         dst++;
434                     }
435                 } else {
436                     for (i = 0; i < src_d->dwHeight * src_d->dwWidth; i++) {
437                         *dst++ = (*src++ << 8) | 0xFF;
438                     }
439                 }
440                 format = GL_RGBA;
441                 pixel_format = GL_UNSIGNED_INT_8_8_8_8;
442             } else {
443                 error = TRUE;
444             }
445         } else {
446             error = TRUE;
447         }
448     } else {
449         error = TRUE;
450     } 
451
452     if ((upload_done == FALSE) && (error == FALSE)) {
453         if (glThis->initial_upload_done == FALSE) {
454             glTexImage2D(GL_TEXTURE_2D,
455                          This->mipmap_level,
456                          format,
457                          src_d->dwWidth, src_d->dwHeight,
458                          0,
459                          format,
460                          pixel_format,
461                          surface == NULL ? src_d->lpSurface : surface);
462             glThis->initial_upload_done = TRUE;
463         } else {
464             glTexSubImage2D(GL_TEXTURE_2D,
465                             This->mipmap_level,
466                             0, 0,
467                             src_d->dwWidth, src_d->dwHeight,
468                             format,
469                             pixel_format,
470                             surface == NULL ? src_d->lpSurface : surface);
471         }
472         
473         if (surface) HeapFree(GetProcessHeap(), 0, surface);
474     } else if (error == TRUE) {
475         if (ERR_ON(ddraw)) {
476             ERR("Unsupported pixel format for textures : \n");
477             DDRAW_dump_pixelformat(&src_d->ddpfPixelFormat);
478         }
479     }
480
481     glThis->dirty_flag = FALSE;
482
483     return DD_OK;
484 }
485
486 HRESULT WINAPI
487 Main_IDirect3DTextureImpl_1_Initialize(LPDIRECT3DTEXTURE iface,
488                                        LPDIRECT3DDEVICE lpDirect3DDevice,
489                                        LPDIRECTDRAWSURFACE lpDDSurface)
490 {
491     ICOM_THIS_FROM(IDirectDrawSurfaceImpl, IDirect3DTexture, iface);
492     FIXME("(%p/%p)->(%p,%p) no-op...\n", This, iface, lpDirect3DDevice, lpDDSurface);
493     return DD_OK;
494 }
495
496 static HRESULT
497 gltex_setcolorkey_cb(IDirectDrawSurfaceImpl *This, DWORD dwFlags, LPDDCOLORKEY ckey )
498 {
499     IDirect3DTextureGLImpl *glThis = (IDirect3DTextureGLImpl *) This->tex_private;
500
501     glThis->dirty_flag = TRUE;
502
503     return DD_OK;
504 }
505
506 HRESULT WINAPI
507 Main_IDirect3DTextureImpl_2_1T_PaletteChanged(LPDIRECT3DTEXTURE2 iface,
508                                               DWORD dwStart,
509                                               DWORD dwCount)
510 {
511     ICOM_THIS_FROM(IDirectDrawSurfaceImpl, IDirect3DTexture2, iface);
512     FIXME("(%p/%p)->(%08lx,%08lx): stub!\n", This, iface, dwStart, dwCount);
513     return DD_OK;
514 }
515
516 HRESULT WINAPI
517 Main_IDirect3DTextureImpl_1_Unload(LPDIRECT3DTEXTURE iface)
518 {
519     ICOM_THIS_FROM(IDirectDrawSurfaceImpl, IDirect3DTexture, iface);
520     FIXME("(%p/%p)->(): stub!\n", This, iface);
521     return DD_OK;
522 }
523
524 HRESULT WINAPI
525 Main_IDirect3DTextureImpl_2_1T_GetHandle(LPDIRECT3DTEXTURE2 iface,
526                                          LPDIRECT3DDEVICE2 lpDirect3DDevice2,
527                                          LPD3DTEXTUREHANDLE lpHandle)
528 {
529     ICOM_THIS_FROM(IDirectDrawSurfaceImpl, IDirect3DTexture2, iface);
530     IDirect3DDeviceImpl *lpDeviceImpl = ICOM_OBJECT(IDirect3DDeviceImpl, IDirect3DDevice2, lpDirect3DDevice2);
531     
532     TRACE("(%p/%p)->(%p,%p)\n", This, iface, lpDirect3DDevice2, lpHandle);
533
534     /* The handle is simply the pointer to the implementation structure */
535     *lpHandle = (D3DTEXTUREHANDLE) This;
536
537     TRACE(" returning handle %08lx.\n", *lpHandle);
538     
539     /* Now set the device for this texture */
540     This->d3ddevice = lpDeviceImpl;
541
542     return D3D_OK;
543 }
544
545 HRESULT WINAPI
546 Main_IDirect3DTextureImpl_2_1T_Load(LPDIRECT3DTEXTURE2 iface,
547                                     LPDIRECT3DTEXTURE2 lpD3DTexture2)
548 {
549     ICOM_THIS_FROM(IDirectDrawSurfaceImpl, IDirect3DTexture2, iface);
550     FIXME("(%p/%p)->(%p): stub!\n", This, iface, lpD3DTexture2);
551     return DD_OK;
552 }
553
554 static void gltex_set_palette(IDirectDrawSurfaceImpl* This, IDirectDrawPaletteImpl* pal)
555 {
556     IDirect3DTextureGLImpl *glThis = (IDirect3DTextureGLImpl *) This->tex_private;
557     
558     /* First call the previous set_palette function */
559     glThis->set_palette(This, pal);
560     
561     /* And set the dirty flag */
562     glThis->dirty_flag = TRUE;
563 }
564
565 static void
566 gltex_final_release(IDirectDrawSurfaceImpl *This)
567 {
568     IDirect3DTextureGLImpl *glThis = (IDirect3DTextureGLImpl *) This->tex_private;
569     DWORD mem_used;
570     int i;
571
572     TRACE(" deleting texture with GL id %d.\n", glThis->tex_name);
573
574     /* And delete texture handle */
575     ENTER_GL();
576     if (glThis->tex_name != 0)
577         glDeleteTextures(1, &(glThis->tex_name));
578     LEAVE_GL(); 
579
580     /* And if this texture was the current one, remove it at the device level */
581     if (This->d3ddevice != NULL)
582         for (i = 0; i < MAX_TEXTURES; i++)
583             if (This->d3ddevice->current_texture[i] == This)
584                 This->d3ddevice->current_texture[i] = NULL;
585
586     /* All this should be part of main surface management not just a hack for texture.. */
587     if (glThis->loaded) {
588         mem_used = This->surface_desc.dwHeight *
589                    This->surface_desc.u1.lPitch;
590         This->ddraw_owner->free_memory(This->ddraw_owner, mem_used);
591     }
592
593     glThis->final_release(This);
594 }
595
596 static void
597 gltex_lock_update(IDirectDrawSurfaceImpl* This, LPCRECT pRect, DWORD dwFlags)
598 {
599     IDirect3DTextureGLImpl *glThis = (IDirect3DTextureGLImpl *) This->tex_private;
600     
601     glThis->lock_update(This, pRect, dwFlags);
602 }
603
604 static void
605 gltex_unlock_update(IDirectDrawSurfaceImpl* This, LPCRECT pRect)
606 {
607     IDirect3DTextureGLImpl *glThis = (IDirect3DTextureGLImpl *) This->tex_private;
608
609     glThis->unlock_update(This, pRect);
610     
611     /* Set the dirty flag according to the lock type */
612     if ((This->lastlocktype & DDLOCK_READONLY) == 0)
613         glThis->dirty_flag = TRUE;
614 }
615
616 HRESULT WINAPI
617 GL_IDirect3DTextureImpl_2_1T_Load(LPDIRECT3DTEXTURE2 iface,
618                                   LPDIRECT3DTEXTURE2 lpD3DTexture2)
619 {
620     ICOM_THIS_FROM(IDirectDrawSurfaceImpl, IDirect3DTexture2, iface);
621     IDirect3DTextureGLImpl *glThis = (IDirect3DTextureGLImpl *) This->tex_private;
622     IDirectDrawSurfaceImpl *lpD3DTextureImpl = ICOM_OBJECT(IDirectDrawSurfaceImpl, IDirect3DTexture2, lpD3DTexture2);
623     DWORD mem_used;
624     DDSURFACEDESC *src_d, *dst_d;
625     HRESULT ret_value = D3D_OK;
626     
627     TRACE("(%p/%p)->(%p)\n", This, iface, lpD3DTexture2);
628
629     if (glThis != NULL) {
630         if (glThis->loaded == FALSE) {
631             /* Only check memory for not already loaded texture... */
632             mem_used = This->surface_desc.dwHeight *
633                        This->surface_desc.u1.lPitch;
634             if (This->ddraw_owner->allocate_memory(This->ddraw_owner, mem_used) < 0) {
635                 TRACE(" out of virtual memory... Warning application.\n");
636                 return D3DERR_TEXTURE_LOAD_FAILED;
637             }
638         }
639         glThis->loaded = TRUE;
640     }
641     
642     TRACE("Copied surface %p to surface %p\n", lpD3DTextureImpl, This);
643
644     if ( This->surface_desc.ddsCaps.dwCaps & DDSCAPS_ALLOCONLOAD )
645         /* If the surface is not allocated and its location is not yet specified,
646            force it to video memory */ 
647         if ( !(This->surface_desc.ddsCaps.dwCaps & (DDSCAPS_SYSTEMMEMORY|DDSCAPS_VIDEOMEMORY)) )
648             This->surface_desc.ddsCaps.dwCaps |= DDSCAPS_VIDEOMEMORY;
649
650     /* Suppress the ALLOCONLOAD flag */
651     This->surface_desc.ddsCaps.dwCaps &= ~DDSCAPS_ALLOCONLOAD;
652     
653     /* After seeing some logs, not sure at all about this... */
654     if (This->palette == NULL) {
655         This->palette = lpD3DTextureImpl->palette;
656         if (lpD3DTextureImpl->palette != NULL) IDirectDrawPalette_AddRef(ICOM_INTERFACE(lpD3DTextureImpl->palette,
657                                                                                         IDirectDrawPalette));
658     } else {
659         if (lpD3DTextureImpl->palette != NULL) {
660             PALETTEENTRY palent[256];
661             IDirectDrawPalette *pal_int = ICOM_INTERFACE(lpD3DTextureImpl->palette, IDirectDrawPalette);
662             IDirectDrawPalette_GetEntries(pal_int, 0, 0, 256, palent);
663             IDirectDrawPalette_SetEntries(ICOM_INTERFACE(This->palette, IDirectDrawPalette),
664                                           0, 0, 256, palent);
665         }
666     }
667     
668     /* Copy one surface on the other */
669     dst_d = (DDSURFACEDESC *)&(This->surface_desc);
670     src_d = (DDSURFACEDESC *)&(lpD3DTextureImpl->surface_desc);
671
672     if ((src_d->dwWidth != dst_d->dwWidth) || (src_d->dwHeight != dst_d->dwHeight)) {
673         /* Should also check for same pixel format, u1.lPitch, ... */
674         ERR("Error in surface sizes\n");
675         return D3DERR_TEXTURE_LOAD_FAILED;
676     } else {
677         /* LPDIRECT3DDEVICE2 d3dd = (LPDIRECT3DDEVICE2) This->D3Ddevice; */
678         /* I should put a macro for the calculus of bpp */
679
680         /* Copy also the ColorKeying stuff */
681         if (src_d->dwFlags & DDSD_CKSRCBLT) {
682             dst_d->dwFlags |= DDSD_CKSRCBLT;
683             dst_d->ddckCKSrcBlt.dwColorSpaceLowValue = src_d->ddckCKSrcBlt.dwColorSpaceLowValue;
684             dst_d->ddckCKSrcBlt.dwColorSpaceHighValue = src_d->ddckCKSrcBlt.dwColorSpaceHighValue;
685         }
686
687         /* Copy the main memory texture into the surface that corresponds to the OpenGL
688            texture object. */
689         memcpy(dst_d->lpSurface, src_d->lpSurface, src_d->u1.lPitch * src_d->dwHeight);
690
691         if (glThis != NULL) {
692             /* If the GetHandle was not done, it is an error... */
693             if (glThis->tex_name == 0) ERR("Unbound GL texture !!!\n");
694
695             /* Set this texture as dirty */
696             glThis->dirty_flag = TRUE;
697         }
698     }
699
700     return ret_value;
701 }
702
703 HRESULT WINAPI
704 Thunk_IDirect3DTextureImpl_2_QueryInterface(LPDIRECT3DTEXTURE2 iface,
705                                             REFIID riid,
706                                             LPVOID* obp)
707 {
708     TRACE("(%p)->(%s,%p) thunking to IDirectDrawSurface7 interface.\n", iface, debugstr_guid(riid), obp);
709     return IDirectDrawSurface7_QueryInterface(COM_INTERFACE_CAST(IDirectDrawSurfaceImpl, IDirect3DTexture2, IDirectDrawSurface7, iface),
710                                               riid,
711                                               obp);
712 }
713
714 ULONG WINAPI
715 Thunk_IDirect3DTextureImpl_2_AddRef(LPDIRECT3DTEXTURE2 iface)
716 {
717     TRACE("(%p)->() thunking to IDirectDrawSurface7 interface.\n", iface);
718     return IDirectDrawSurface7_AddRef(COM_INTERFACE_CAST(IDirectDrawSurfaceImpl, IDirect3DTexture2, IDirectDrawSurface7, iface));
719 }
720
721 ULONG WINAPI
722 Thunk_IDirect3DTextureImpl_2_Release(LPDIRECT3DTEXTURE2 iface)
723 {
724     TRACE("(%p)->() thunking to IDirectDrawSurface7 interface.\n", iface);
725     return IDirectDrawSurface7_Release(COM_INTERFACE_CAST(IDirectDrawSurfaceImpl, IDirect3DTexture2, IDirectDrawSurface7, iface));
726 }
727
728 HRESULT WINAPI
729 Thunk_IDirect3DTextureImpl_1_QueryInterface(LPDIRECT3DTEXTURE iface,
730                                             REFIID riid,
731                                             LPVOID* obp)
732 {
733     TRACE("(%p)->(%s,%p) thunking to IDirectDrawSurface7 interface.\n", iface, debugstr_guid(riid), obp);
734     return IDirectDrawSurface7_QueryInterface(COM_INTERFACE_CAST(IDirectDrawSurfaceImpl, IDirect3DTexture, IDirectDrawSurface7, iface),
735                                               riid,
736                                               obp);
737 }
738
739 ULONG WINAPI
740 Thunk_IDirect3DTextureImpl_1_AddRef(LPDIRECT3DTEXTURE iface)
741 {
742     TRACE("(%p)->() thunking to IDirectDrawSurface7 interface.\n", iface);
743     return IDirectDrawSurface7_AddRef(COM_INTERFACE_CAST(IDirectDrawSurfaceImpl, IDirect3DTexture, IDirectDrawSurface7, iface));
744 }
745
746 ULONG WINAPI
747 Thunk_IDirect3DTextureImpl_1_Release(LPDIRECT3DTEXTURE iface)
748 {
749     TRACE("(%p)->() thunking to IDirectDrawSurface7 interface.\n", iface);
750     return IDirectDrawSurface7_Release(COM_INTERFACE_CAST(IDirectDrawSurfaceImpl, IDirect3DTexture, IDirectDrawSurface7, iface));
751 }
752
753 HRESULT WINAPI
754 Thunk_IDirect3DTextureImpl_1_PaletteChanged(LPDIRECT3DTEXTURE iface,
755                                             DWORD dwStart,
756                                             DWORD dwCount)
757 {
758     TRACE("(%p)->(%08lx,%08lx) thunking to IDirect3DTexture2 interface.\n", iface, dwStart, dwCount);
759     return IDirect3DTexture2_PaletteChanged(COM_INTERFACE_CAST(IDirectDrawSurfaceImpl, IDirect3DTexture, IDirect3DTexture2, iface),
760                                             dwStart,
761                                             dwCount);
762 }
763
764 HRESULT WINAPI
765 Thunk_IDirect3DTextureImpl_1_GetHandle(LPDIRECT3DTEXTURE iface,
766                                        LPDIRECT3DDEVICE lpDirect3DDevice,
767                                        LPD3DTEXTUREHANDLE lpHandle)
768 {
769     TRACE("(%p)->(%p,%p) thunking to IDirect3DTexture2 interface.\n", iface, lpDirect3DDevice, lpHandle);
770     return IDirect3DTexture2_GetHandle(COM_INTERFACE_CAST(IDirectDrawSurfaceImpl, IDirect3DTexture, IDirect3DTexture2, iface),
771                                        COM_INTERFACE_CAST(IDirect3DDeviceImpl, IDirect3DDevice, IDirect3DDevice2, lpDirect3DDevice),
772                                        lpHandle);
773 }
774
775 HRESULT WINAPI
776 Thunk_IDirect3DTextureImpl_1_Load(LPDIRECT3DTEXTURE iface,
777                                   LPDIRECT3DTEXTURE lpD3DTexture)
778 {
779     TRACE("(%p)->(%p) thunking to IDirect3DTexture2 interface.\n", iface, lpD3DTexture);
780     return IDirect3DTexture2_Load(COM_INTERFACE_CAST(IDirectDrawSurfaceImpl, IDirect3DTexture, IDirect3DTexture2, iface),
781                                   COM_INTERFACE_CAST(IDirectDrawSurfaceImpl, IDirect3DTexture, IDirect3DTexture2, lpD3DTexture));
782 }
783
784 #if !defined(__STRICT_ANSI__) && defined(__GNUC__)
785 # define XCAST(fun)     (typeof(VTABLE_IDirect3DTexture2.fun))
786 #else
787 # define XCAST(fun)     (void*)
788 #endif
789
790 ICOM_VTABLE(IDirect3DTexture2) VTABLE_IDirect3DTexture2 =
791 {
792     ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE
793     XCAST(QueryInterface) Thunk_IDirect3DTextureImpl_2_QueryInterface,
794     XCAST(AddRef) Thunk_IDirect3DTextureImpl_2_AddRef,
795     XCAST(Release) Thunk_IDirect3DTextureImpl_2_Release,
796     XCAST(GetHandle) Main_IDirect3DTextureImpl_2_1T_GetHandle,
797     XCAST(PaletteChanged) Main_IDirect3DTextureImpl_2_1T_PaletteChanged,
798     XCAST(Load) GL_IDirect3DTextureImpl_2_1T_Load,
799 };
800
801 #if !defined(__STRICT_ANSI__) && defined(__GNUC__)
802 #undef XCAST
803 #endif
804
805
806 #if !defined(__STRICT_ANSI__) && defined(__GNUC__)
807 # define XCAST(fun)     (typeof(VTABLE_IDirect3DTexture.fun))
808 #else
809 # define XCAST(fun)     (void*)
810 #endif
811
812 ICOM_VTABLE(IDirect3DTexture) VTABLE_IDirect3DTexture =
813 {
814     ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE
815     XCAST(QueryInterface) Thunk_IDirect3DTextureImpl_1_QueryInterface,
816     XCAST(AddRef) Thunk_IDirect3DTextureImpl_1_AddRef,
817     XCAST(Release) Thunk_IDirect3DTextureImpl_1_Release,
818     XCAST(Initialize) Main_IDirect3DTextureImpl_1_Initialize,
819     XCAST(GetHandle) Thunk_IDirect3DTextureImpl_1_GetHandle,
820     XCAST(PaletteChanged) Thunk_IDirect3DTextureImpl_1_PaletteChanged,
821     XCAST(Load) Thunk_IDirect3DTextureImpl_1_Load,
822     XCAST(Unload) Main_IDirect3DTextureImpl_1_Unload,
823 };
824
825 #if !defined(__STRICT_ANSI__) && defined(__GNUC__)
826 #undef XCAST
827 #endif
828
829 HRESULT d3dtexture_create(IDirect3DImpl *d3d, IDirectDrawSurfaceImpl *surf, BOOLEAN at_creation, 
830                           IDirectDrawSurfaceImpl *main)
831 {
832     /* First, initialize the texture vtables... */
833     ICOM_INIT_INTERFACE(surf, IDirect3DTexture,  VTABLE_IDirect3DTexture);
834     ICOM_INIT_INTERFACE(surf, IDirect3DTexture2, VTABLE_IDirect3DTexture2);
835         
836     /* Only create all the private stuff if we actually have an OpenGL context.. */
837     if (d3d->current_device != NULL) {
838         IDirect3DTextureGLImpl *private;
839
840         private = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IDirect3DTextureGLImpl));
841         if (private == NULL) return DDERR_OUTOFMEMORY;
842
843         private->final_release = surf->final_release;
844         private->lock_update = surf->lock_update;
845         private->unlock_update = surf->unlock_update;
846         private->set_palette = surf->set_palette;
847         
848         /* If at creation, we can optimize stuff and wait the first 'unlock' to upload a valid stuff to OpenGL.
849            Otherwise, it will be uploaded here (and may be invalid). */
850         surf->final_release = gltex_final_release;
851         surf->lock_update = gltex_lock_update;
852         surf->unlock_update = gltex_unlock_update;
853         surf->tex_private = private;
854         surf->aux_setcolorkey_cb = gltex_setcolorkey_cb;
855         surf->set_palette = gltex_set_palette;
856
857         ENTER_GL();
858         if (surf->mipmap_level == 0) {
859             glGenTextures(1, &(private->tex_name));
860             if (private->tex_name == 0) ERR("Error at creation of OpenGL texture ID !\n");
861             TRACE(" GL texture created for surface %p (private data at %p and GL id %d).\n", surf, private, private->tex_name);
862         } else {
863             private->tex_name = ((IDirect3DTextureGLImpl *) (main->tex_private))->tex_name;
864             TRACE(" GL texture created for surface %p (private data at %p and GL id reusing id %d from surface %p (%p)).\n",
865                   surf, private, private->tex_name, main, main->tex_private);
866         }
867         LEAVE_GL();
868
869         /* And set the dirty flag accordingly */
870         private->dirty_flag = (at_creation == FALSE);
871         private->initial_upload_done = FALSE;
872     }
873
874     return D3D_OK;
875 }