fdopen: don't rewind the file after creating the FILE* handle. Added
[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 #include "windef.h"
26 #include "winerror.h"
27 #include "objbase.h"
28 #include "ddraw.h"
29 #include "d3d.h"
30 #include "wine/debug.h"
31
32 #include "mesa_private.h"
33
34 WINE_DEFAULT_DEBUG_CHANNEL(ddraw);
35
36 /* Define this if you want to save to a file all the textures used by a game
37    (can be funny to see how they managed to cram all the pictures in
38    texture memory) */
39 #undef TEXTURE_SNOOP
40
41 #ifdef TEXTURE_SNOOP
42 #include <stdio.h>
43
44 #define SNOOP_PALETTED()                                                                        \
45       {                                                                                         \
46         FILE *f;                                                                                \
47         char buf[32];                                                                           \
48         int x, y;                                                                               \
49                                                                                                 \
50         sprintf(buf, "%ld.pnm", glThis->tex_name);                                              \
51         f = fopen(buf, "wb");                                                                   \
52         fprintf(f, "P6\n%ld %ld\n255\n", src_d->dwWidth, src_d->dwHeight);                      \
53         for (y = 0; y < src_d->dwHeight; y++) {                                                 \
54           for (x = 0; x < src_d->dwWidth; x++) {                                                \
55             unsigned char c = ((unsigned char *) src_d->lpSurface)[y * src_d->dwWidth + x];     \
56             fputc(table[c][0], f);                                                              \
57             fputc(table[c][1], f);                                                              \
58             fputc(table[c][2], f);                                                              \
59           }                                                                                     \
60         }                                                                                       \
61         fclose(f);                                                                              \
62       }
63
64 #define SNOOP_5650()                                                                                    \
65           {                                                                                             \
66             FILE *f;                                                                                    \
67             char buf[32];                                                                               \
68             int x, y;                                                                                   \
69                                                                                                         \
70             sprintf(buf, "%ld.pnm", glThis->tex_name);                                                  \
71             f = fopen(buf, "wb");                                                                       \
72             fprintf(f, "P6\n%ld %ld\n255\n", src_d->dwWidth, src_d->dwHeight);                          \
73             for (y = 0; y < src_d->dwHeight; y++) {                                                     \
74               for (x = 0; x < src_d->dwWidth; x++) {                                                    \
75                 unsigned short c = ((unsigned short *) src_d->lpSurface)[y * src_d->dwWidth + x];       \
76                 fputc((c & 0xF800) >> 8, f);                                                            \
77                 fputc((c & 0x07E0) >> 3, f);                                                            \
78                 fputc((c & 0x001F) << 3, f);                                                            \
79               }                                                                                         \
80             }                                                                                           \
81             fclose(f);                                                                                  \
82           }
83
84 #define SNOOP_5551()                                                                                    \
85           {                                                                                             \
86             FILE *f;                                                                                    \
87             char buf[32];                                                                               \
88             int x, y;                                                                                   \
89                                                                                                         \
90             sprintf(buf, "%ld.pnm", glThis->tex_name);                                                  \
91             f = fopen(buf, "wb");                                                                       \
92             fprintf(f, "P6\n%ld %ld\n255\n", src_d->dwWidth, src_d->dwHeight);                          \
93             for (y = 0; y < src_d->dwHeight; y++) {                                                     \
94               for (x = 0; x < src_d->dwWidth; x++) {                                                    \
95                 unsigned short c = ((unsigned short *) src_d->lpSurface)[y * src_d->dwWidth + x];       \
96                 fputc((c & 0xF800) >> 8, f);                                                            \
97                 fputc((c & 0x07C0) >> 3, f);                                                            \
98                 fputc((c & 0x003E) << 2, f);                                                            \
99               }                                                                                         \
100             }                                                                                           \
101             fclose(f);                                                                                  \
102           }
103
104 #define SNOOP_1555()                                                                                    \
105           {                                                                                             \
106             FILE *f;                                                                                    \
107             char buf[32];                                                                               \
108             int x, y;                                                                                   \
109                                                                                                         \
110             sprintf(buf, "%ld.pnm", glThis->tex_name);                                                  \
111             f = fopen(buf, "wb");                                                                       \
112             fprintf(f, "P6\n%ld %ld\n255\n", src_d->dwWidth, src_d->dwHeight);                          \
113             for (y = 0; y < src_d->dwHeight; y++) {                                                     \
114               for (x = 0; x < src_d->dwWidth; x++) {                                                    \
115                 unsigned short c = ((unsigned short *) src_d->lpSurface)[y * src_d->dwWidth + x];       \
116                 fputc((c & 0x7C00) >> 7, f);                                                            \
117                 fputc((c & 0x03E0) >> 2, f);                                                            \
118                 fputc((c & 0x001F) << 3, f);                                                            \
119               }                                                                                         \
120             }                                                                                           \
121             fclose(f);                                                                                  \
122           }
123 #else
124 #define SNOOP_PALETTED()
125 #define SNOOP_5650()
126 #define SNOOP_5551()
127 #define SNOOP_1555()
128 #endif
129
130 /*******************************************************************************
131  *                         IDirectSurface callback methods
132  */
133 HRESULT WINAPI gltex_setcolorkey_cb(IDirectDrawSurfaceImpl *texture, DWORD dwFlags, LPDDCOLORKEY ckey )
134 {
135     DDSURFACEDESC *tex_d;
136     GLuint current_texture;
137     IDirect3DTextureGLImpl *glThis = (IDirect3DTextureGLImpl *) texture->tex_private;
138     
139     TRACE("(%p) : colorkey callback\n", texture);
140
141     /* Get the texture description */
142     tex_d = (DDSURFACEDESC *)&(texture->surface_desc);
143
144     /* Now, save the current texture */
145     ENTER_GL();
146     glGetIntegerv(GL_TEXTURE_BINDING_2D, &current_texture);
147     if (glThis->tex_name == 0) ERR("Unbound GL texture !!!\n");
148     glBindTexture(GL_TEXTURE_2D, glThis->tex_name);
149
150     if (tex_d->ddpfPixelFormat.dwFlags & DDPF_PALETTEINDEXED8) {
151         FIXME("Todo Paletted\n");
152     } else if (tex_d->ddpfPixelFormat.dwFlags & DDPF_RGB) {
153         if (tex_d->ddpfPixelFormat.u1.dwRGBBitCount == 8) {
154             FIXME("Todo 3_3_2_0\n");
155         } else if (tex_d->ddpfPixelFormat.u1.dwRGBBitCount == 16) {
156             if (tex_d->ddpfPixelFormat.u5.dwRGBAlphaBitMask == 0x00000000) {
157                 /* Now transform the 5_6_5 into a 5_5_5_1 surface to support color keying */
158                 unsigned short *dest = (unsigned short *) HeapAlloc(GetProcessHeap(),
159                                                                     HEAP_ZERO_MEMORY,
160                                                                     tex_d->u1.lPitch * tex_d->dwHeight);
161                 unsigned short *src = (unsigned short *) tex_d->lpSurface;
162                 int x, y;
163                 
164                 for (y = 0; y < tex_d->dwHeight; y++) {
165                     for (x = 0; x < tex_d->dwWidth; x++) {
166                         unsigned short cpixel = src[x + y * tex_d->dwWidth];
167                         
168                         if ((dwFlags & DDCKEY_SRCBLT) &&
169                             (cpixel >= ckey->dwColorSpaceLowValue) &&
170                             (cpixel <= ckey->dwColorSpaceHighValue)) /* No alpha bit => this pixel is transparent */
171                             dest[x + y * tex_d->dwWidth] = (cpixel & ~0x003F) | ((cpixel & 0x001F) << 1) | 0x0000;
172                         else                                         /* Alpha bit is set => this pixel will be seen */
173                             dest[x + y * tex_d->dwWidth] = (cpixel & ~0x003F) | ((cpixel & 0x001F) << 1) | 0x0001;
174                     }
175                 }
176
177                 glTexSubImage2D(GL_TEXTURE_2D,
178                                 glThis->mipmap_level,
179                                 0, 0,
180                                 tex_d->dwWidth, tex_d->dwHeight,
181                                 GL_RGBA,
182                                 GL_UNSIGNED_SHORT_5_5_5_1,
183                                 dest);
184                 
185                 /* Frees the temporary surface */
186                 HeapFree(GetProcessHeap(),0,dest);
187             } else if (tex_d->ddpfPixelFormat.u5.dwRGBAlphaBitMask == 0x00000001) {
188                 FIXME("Todo 5_5_5_1\n");
189             } else if (tex_d->ddpfPixelFormat.u5.dwRGBAlphaBitMask == 0x0000000F) {
190                 FIXME("Todo 4_4_4_4\n");
191             } else {
192                 ERR("Unhandled texture format (bad Aplha channel for a 16 bit texture)\n");
193             }
194         } else if (tex_d->ddpfPixelFormat.u1.dwRGBBitCount == 24) {
195             FIXME("Todo 8_8_8_0\n");
196         } else if (tex_d->ddpfPixelFormat.u1.dwRGBBitCount == 32) {
197             FIXME("Todo 8_8_8_8\n");
198         } else {
199             ERR("Unhandled texture format (bad RGB count)\n");
200         }
201     } else {
202         ERR("Unhandled texture format (neither RGB nor INDEX)\n");
203     }
204     glBindTexture(GL_TEXTURE_2D, current_texture);
205     LEAVE_GL();
206
207     return DD_OK;
208 }
209
210 static void
211 gltex_upload_texture(IDirectDrawSurfaceImpl *This, BOOLEAN init_upload) {
212     IDirect3DTextureGLImpl *glThis = (IDirect3DTextureGLImpl *) This->tex_private;
213     GLuint current_texture;
214 #if 0
215     static BOOL color_table_queried = FALSE;
216 #endif
217     void (*ptr_ColorTableEXT) (GLenum target, GLenum internalformat,
218                                GLsizei width, GLenum format, GLenum type, const GLvoid *table) = NULL;
219
220     DDSURFACEDESC *src_d = (DDSURFACEDESC *)&(This->surface_desc);
221
222     TRACE(" uploading texture to GL id %d (initial = %d).\n", glThis->tex_name, init_upload);
223
224     glGetIntegerv(GL_TEXTURE_BINDING_2D, &current_texture);
225     glBindTexture(GL_TEXTURE_2D, glThis->tex_name);
226
227     if (src_d->ddpfPixelFormat.dwFlags & DDPF_PALETTEINDEXED8) {
228           /* ****************
229              Paletted Texture
230              **************** */
231         IDirectDrawPaletteImpl* pal = This->palette;
232         BYTE table[256][4];
233         int i;
234
235 #if 0
236         if (color_table_queried == FALSE) {
237             ptr_ColorTableEXT =
238                 ((Mesa_DeviceCapabilities *) ((x11_dd_private *) This->surface->s.ddraw->d->private)->device_capabilities)->ptr_ColorTableEXT;
239         }
240 #endif
241         
242         if (pal == NULL) {
243             ERR("Palettized texture Loading with a NULL palette !\n");
244             LEAVE_GL();
245             return;
246         }
247         /* Get the surface's palette */
248         for (i = 0; i < 256; i++) {
249             table[i][0] = pal->palents[i].peRed;
250             table[i][1] = pal->palents[i].peGreen;
251             table[i][2] = pal->palents[i].peBlue;
252             if ((src_d->dwFlags & DDSD_CKSRCBLT) &&
253                 (i >= src_d->ddckCKSrcBlt.dwColorSpaceLowValue) &&
254                 (i <= src_d->ddckCKSrcBlt.dwColorSpaceHighValue))
255                 table[i][3] = 0x00;
256             else
257                 table[i][3] = 0xFF;
258         }
259
260         /* Texture snooping */
261         SNOOP_PALETTED();
262
263         if (ptr_ColorTableEXT != NULL) {
264             /* use Paletted Texture Extension */
265             ptr_ColorTableEXT(GL_TEXTURE_2D,    /* target */
266                               GL_RGBA,          /* internal format */
267                               256,              /* table size */
268                               GL_RGBA,          /* table format */
269                               GL_UNSIGNED_BYTE, /* table type */
270                               table);           /* the color table */
271             
272             glTexImage2D(GL_TEXTURE_2D,       /* target */
273                          glThis->mipmap_level,                   /* level */
274                          GL_COLOR_INDEX8_EXT, /* internal format */
275                          src_d->dwWidth, src_d->dwHeight, /* width, height */
276                          0,                   /* border */
277                          GL_COLOR_INDEX,      /* texture format */
278                          GL_UNSIGNED_BYTE,    /* texture type */
279                          src_d->lpSurface); /* the texture */
280         } else {
281             DWORD *surface = (DWORD *) HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, src_d->dwWidth * src_d->dwHeight * sizeof(DWORD));
282             DWORD i;
283             BYTE *src = (BYTE *) src_d->lpSurface, *dst = (BYTE *) surface;
284             
285             for (i = 0; i < src_d->dwHeight * src_d->dwWidth; i++) {
286                 BYTE color = *src++;
287                 *dst++ = table[color][0];
288                 *dst++ = table[color][1];
289                 *dst++ = table[color][2];
290                 *dst++ = table[color][3];
291             }
292             
293             if (init_upload)
294                 glTexImage2D(GL_TEXTURE_2D,
295                              glThis->mipmap_level,
296                              GL_RGBA,
297                              src_d->dwWidth, src_d->dwHeight,
298                              0,
299                              GL_RGBA,
300                              GL_UNSIGNED_BYTE,
301                              surface);
302             else
303                 glTexSubImage2D(GL_TEXTURE_2D,
304                                 glThis->mipmap_level,
305                                 0, 0,
306                                 src_d->dwWidth, src_d->dwHeight,
307                                 GL_RGBA,
308                                 GL_UNSIGNED_BYTE,
309                                 surface);
310             
311             HeapFree(GetProcessHeap(), 0, surface);
312         }
313     } else if (src_d->ddpfPixelFormat.dwFlags & DDPF_RGB) {
314             /* ************
315                RGB Textures
316                ************ */
317         if (src_d->ddpfPixelFormat.u1.dwRGBBitCount == 8) {
318                 /* **********************
319                    GL_UNSIGNED_BYTE_3_3_2
320                    ********************** */
321             if (init_upload)
322                 glTexImage2D(GL_TEXTURE_2D,
323                              glThis->mipmap_level,
324                              GL_RGB,
325                              src_d->dwWidth, src_d->dwHeight,
326                              0,
327                              GL_RGB,
328                              GL_UNSIGNED_BYTE_3_3_2,
329                              src_d->lpSurface);
330             else
331                 glTexSubImage2D(GL_TEXTURE_2D,
332                                 glThis->mipmap_level,
333                                 0, 0,
334                                 src_d->dwWidth, src_d->dwHeight,
335                                 GL_RGB,
336                                 GL_UNSIGNED_BYTE_3_3_2,
337                                 src_d->lpSurface);
338         } else if (src_d->ddpfPixelFormat.u1.dwRGBBitCount == 16) {
339             if (src_d->ddpfPixelFormat.u5.dwRGBAlphaBitMask == 0x00000000) {
340                 /* Texture snooping */
341                 SNOOP_5650();
342                     
343                 if (init_upload)
344                     glTexImage2D(GL_TEXTURE_2D,
345                                  glThis->mipmap_level,
346                                  GL_RGB,
347                                  src_d->dwWidth, src_d->dwHeight,
348                                  0,
349                                  GL_RGB,
350                                  GL_UNSIGNED_SHORT_5_6_5,
351                                  src_d->lpSurface);
352                 else
353                     glTexSubImage2D(GL_TEXTURE_2D,
354                                     glThis->mipmap_level,
355                                     0, 0,
356                                     src_d->dwWidth, src_d->dwHeight,
357                                     GL_RGB,
358                                     GL_UNSIGNED_SHORT_5_6_5,
359                                     src_d->lpSurface);
360
361             } else if (src_d->ddpfPixelFormat.u5.dwRGBAlphaBitMask == 0x00000001) {
362                 /* Texture snooping */
363                 SNOOP_5551();
364                     
365                 if (init_upload)
366                     glTexImage2D(GL_TEXTURE_2D,
367                                  glThis->mipmap_level,
368                                  GL_RGBA,
369                                  src_d->dwWidth, src_d->dwHeight,
370                                  0,
371                                  GL_RGBA,
372                                  GL_UNSIGNED_SHORT_5_5_5_1,
373                                  src_d->lpSurface);
374                 else
375                     glTexSubImage2D(GL_TEXTURE_2D,
376                                     glThis->mipmap_level,
377                                     0, 0,
378                                     src_d->dwWidth, src_d->dwHeight,
379                                     GL_RGBA,
380                                     GL_UNSIGNED_SHORT_5_5_5_1,
381                                     src_d->lpSurface);
382             } else if (src_d->ddpfPixelFormat.u5.dwRGBAlphaBitMask == 0x0000000F) {
383                 if (init_upload)
384                     glTexImage2D(GL_TEXTURE_2D,
385                                  glThis->mipmap_level,
386                                  GL_RGBA,
387                                  src_d->dwWidth, src_d->dwHeight,
388                                  0,
389                                  GL_RGBA,
390                                  GL_UNSIGNED_SHORT_4_4_4_4,
391                                  src_d->lpSurface);
392                 else
393                     glTexSubImage2D(GL_TEXTURE_2D,
394                                     glThis->mipmap_level,
395                                     0, 0,
396                                     src_d->dwWidth, src_d->dwHeight,
397                                     GL_RGBA,
398                                     GL_UNSIGNED_SHORT_4_4_4_4,
399                                     src_d->lpSurface);
400             } else if (src_d->ddpfPixelFormat.u5.dwRGBAlphaBitMask == 0x0000F000) {
401                 /* Move the four Alpha bits... */
402                 WORD *surface = (WORD *) HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, src_d->dwWidth * src_d->dwHeight * sizeof(WORD));
403                 DWORD i;
404                 WORD *src = (WORD *) src_d->lpSurface, *dst = surface;
405                 
406                 for (i = 0; i < src_d->dwHeight * src_d->dwWidth; i++) {
407                     *dst++ = (((*src & 0xFFF0) >>  4) |
408                               ((*src & 0x000F) << 12));
409                     src++;
410                 }
411                 
412                 if (init_upload)
413                     glTexImage2D(GL_TEXTURE_2D,
414                                  glThis->mipmap_level,
415                                  GL_RGBA,
416                                  src_d->dwWidth, src_d->dwHeight,
417                                  0,
418                                  GL_RGBA,
419                                  GL_UNSIGNED_SHORT_4_4_4_4,
420                                  surface);
421                 else
422                     glTexSubImage2D(GL_TEXTURE_2D,
423                                     glThis->mipmap_level,
424                                     0, 0,
425                                     src_d->dwWidth, src_d->dwHeight,
426                                     GL_RGBA,
427                                     GL_UNSIGNED_SHORT_4_4_4_4,
428                                     surface);
429                 
430                 HeapFree(GetProcessHeap(), 0, surface);
431             } else if (src_d->ddpfPixelFormat.u5.dwRGBAlphaBitMask == 0x00008000) {
432                 /* Converting the 1555 format in 5551 packed */
433                 WORD *surface = (WORD *) HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, src_d->dwWidth * src_d->dwHeight * sizeof(WORD));
434                 DWORD i;
435                 WORD *src = (WORD *) src_d->lpSurface, *dst = surface;
436                 
437                 for (i = 0; i < src_d->dwHeight * src_d->dwWidth; i++) {
438                     *dst++ = (((*src & 0x8000) >> 15) |
439                               ((*src & 0x7FFF) <<  1));
440                     src++;
441                 }
442                 SNOOP_1555();
443                 
444                 if (init_upload)
445                     glTexImage2D(GL_TEXTURE_2D,
446                                  glThis->mipmap_level,
447                                  GL_RGBA,
448                                  src_d->dwWidth, src_d->dwHeight,
449                                  0,
450                                  GL_RGBA,
451                                  GL_UNSIGNED_SHORT_5_5_5_1,
452                                  surface);
453                 else
454                     glTexSubImage2D(GL_TEXTURE_2D,
455                                     glThis->mipmap_level,
456                                     0, 0,
457                                     src_d->dwWidth, src_d->dwHeight,
458                                     GL_RGBA,
459                                     GL_UNSIGNED_SHORT_5_5_5_1,
460                                     surface);
461
462                 HeapFree(GetProcessHeap(), 0, surface);
463             } else {
464                 ERR("Unhandled texture format (bad Aplha channel for a 16 bit texture)\n");
465             }
466         } else if (src_d->ddpfPixelFormat.u1.dwRGBBitCount == 24) {
467             if (init_upload)
468                 glTexImage2D(GL_TEXTURE_2D,
469                              glThis->mipmap_level,
470                              GL_RGB,
471                              src_d->dwWidth, src_d->dwHeight,
472                              0,
473                              GL_RGB,
474                              GL_UNSIGNED_BYTE,
475                              src_d->lpSurface);
476             else
477                 glTexSubImage2D(GL_TEXTURE_2D,
478                                 glThis->mipmap_level,
479                                 0, 0,
480                                 src_d->dwWidth, src_d->dwHeight,
481                                 GL_RGB,
482                                 GL_UNSIGNED_BYTE,
483                                 src_d->lpSurface);
484         } else if (src_d->ddpfPixelFormat.u1.dwRGBBitCount == 32) {
485             if (init_upload)
486                 glTexImage2D(GL_TEXTURE_2D,
487                              glThis->mipmap_level,
488                              GL_RGBA,
489                              src_d->dwWidth, src_d->dwHeight,
490                              0,
491                              GL_RGBA,
492                              GL_UNSIGNED_BYTE,
493                              src_d->lpSurface);
494             else
495                 glTexSubImage2D(GL_TEXTURE_2D,
496                                 glThis->mipmap_level,
497                                 0, 0,
498                                 src_d->dwWidth, src_d->dwHeight,
499                                 GL_RGBA,
500                                 GL_UNSIGNED_BYTE,
501                                 src_d->lpSurface);
502         } else {
503             ERR("Unhandled texture format (bad RGB count)\n");
504         }
505     } else {
506         ERR("Unhandled texture format (neither RGB nor INDEX)\n");
507     }    
508     glBindTexture(GL_TEXTURE_2D, current_texture);
509 }
510
511 HRESULT WINAPI
512 Main_IDirect3DTextureImpl_1_Initialize(LPDIRECT3DTEXTURE iface,
513                                        LPDIRECT3DDEVICE lpDirect3DDevice,
514                                        LPDIRECTDRAWSURFACE lpDDSurface)
515 {
516     ICOM_THIS_FROM(IDirectDrawSurfaceImpl, IDirect3DTexture, iface);
517     FIXME("(%p/%p)->(%p,%p) no-op...\n", This, iface, lpDirect3DDevice, lpDDSurface);
518     return DD_OK;
519 }
520
521 HRESULT WINAPI
522 Main_IDirect3DTextureImpl_2_1T_PaletteChanged(LPDIRECT3DTEXTURE2 iface,
523                                               DWORD dwStart,
524                                               DWORD dwCount)
525 {
526     ICOM_THIS_FROM(IDirectDrawSurfaceImpl, IDirect3DTexture2, iface);
527     FIXME("(%p/%p)->(%08lx,%08lx): stub!\n", This, iface, dwStart, dwCount);
528     return DD_OK;
529 }
530
531 HRESULT WINAPI
532 Main_IDirect3DTextureImpl_1_Unload(LPDIRECT3DTEXTURE iface)
533 {
534     ICOM_THIS_FROM(IDirectDrawSurfaceImpl, IDirect3DTexture, iface);
535     FIXME("(%p/%p)->(): stub!\n", This, iface);
536     return DD_OK;
537 }
538
539 HRESULT WINAPI
540 Main_IDirect3DTextureImpl_2_1T_GetHandle(LPDIRECT3DTEXTURE2 iface,
541                                          LPDIRECT3DDEVICE2 lpDirect3DDevice2,
542                                          LPD3DTEXTUREHANDLE lpHandle)
543 {
544     ICOM_THIS_FROM(IDirectDrawSurfaceImpl, IDirect3DTexture2, iface);
545     FIXME("(%p/%p)->(%p,%p): stub!\n", This, iface, lpDirect3DDevice2, lpHandle);
546     return DD_OK;
547 }
548
549 HRESULT WINAPI
550 Main_IDirect3DTextureImpl_2_1T_Load(LPDIRECT3DTEXTURE2 iface,
551                                     LPDIRECT3DTEXTURE2 lpD3DTexture2)
552 {
553     ICOM_THIS_FROM(IDirectDrawSurfaceImpl, IDirect3DTexture2, iface);
554     FIXME("(%p/%p)->(%p): stub!\n", This, iface, lpD3DTexture2);
555     return DD_OK;
556 }
557
558 static void
559 gltex_final_release(IDirectDrawSurfaceImpl *This)
560 {
561     IDirect3DTextureGLImpl *glThis = (IDirect3DTextureGLImpl *) This->tex_private;
562     DWORD mem_used;
563
564     TRACE(" deleting texture with GL id %d.\n", glThis->tex_name);
565       
566     /* And delete texture handle */
567     ENTER_GL();
568     if (glThis->tex_name != 0)
569         glDeleteTextures(1, &(glThis->tex_name));
570     LEAVE_GL(); 
571
572     /* And if this texture was the current one, remove it at the device level */
573     if (This->d3ddevice != NULL)
574         if (This->d3ddevice->current_texture[0] == This)
575             This->d3ddevice->current_texture[0] = NULL;
576
577     /* All this should be part of main surface management not just a hack for texture.. */
578     if (glThis->loaded) {
579         mem_used = This->surface_desc.dwHeight *
580                    This->surface_desc.dwHeight *
581                    This->surface_desc.u4.ddpfPixelFormat.u1.dwRGBBitCount;
582         This->ddraw_owner->free_memory(This->ddraw_owner, mem_used);
583     }
584
585     glThis->final_release(This);
586 }
587
588 static void
589 gltex_lock_update(IDirectDrawSurfaceImpl* This, LPCRECT pRect, DWORD dwFlags)
590 {
591     IDirect3DTextureGLImpl *glThis = (IDirect3DTextureGLImpl *) This->tex_private;
592     
593     glThis->lock_update(This, pRect, dwFlags);
594 }
595
596 static void
597 gltex_unlock_update(IDirectDrawSurfaceImpl* This, LPCRECT pRect)
598 {
599     IDirect3DTextureGLImpl *glThis = (IDirect3DTextureGLImpl *) This->tex_private;
600
601     ENTER_GL();
602     gltex_upload_texture(This, glThis->first_unlock);
603     LEAVE_GL();
604     glThis->first_unlock = FALSE;
605
606     glThis->unlock_update(This, pRect);
607 }
608
609 HRESULT WINAPI
610 GL_IDirect3DTextureImpl_2_1T_GetHandle(LPDIRECT3DTEXTURE2 iface,
611                                        LPDIRECT3DDEVICE2 lpDirect3DDevice2,
612                                        LPD3DTEXTUREHANDLE lpHandle)
613 {
614     ICOM_THIS_FROM(IDirectDrawSurfaceImpl, IDirect3DTexture2, iface);
615     IDirect3DTextureGLImpl *glThis = (IDirect3DTextureGLImpl *) This->tex_private;
616     IDirect3DDeviceImpl *lpDeviceImpl = ICOM_OBJECT(IDirect3DDeviceImpl, IDirect3DDevice2, lpDirect3DDevice2);
617     
618     TRACE("(%p/%p)->(%p,%p)\n", This, iface, lpDirect3DDevice2, lpHandle);
619
620     /* The handle is simply the pointer to the implementation structure */
621     *lpHandle = (D3DTEXTUREHANDLE) This;
622
623     TRACE(" returning handle %08lx.\n", *lpHandle);
624     
625     /* Now, bind a new texture */
626     This->d3ddevice = lpDeviceImpl;
627
628     /* Associate the texture with the device and perform the appropriate AddRef/Release */
629     /* FIXME: Is there only one or several textures associated with the device ? */
630     if (lpDeviceImpl->current_texture[0] != NULL)
631         IDirectDrawSurface7_Release(ICOM_INTERFACE(lpDeviceImpl->current_texture[0], IDirectDrawSurface7));
632     IDirectDrawSurface7_AddRef(ICOM_INTERFACE(This, IDirectDrawSurface7));
633     lpDeviceImpl->current_texture[0] = This;
634
635     TRACE("OpenGL texture handle is : %d\n", glThis->tex_name);
636
637     return D3D_OK;
638 }
639
640 HRESULT WINAPI
641 GL_IDirect3DTextureImpl_2_1T_Load(LPDIRECT3DTEXTURE2 iface,
642                                   LPDIRECT3DTEXTURE2 lpD3DTexture2)
643 {
644     ICOM_THIS_FROM(IDirectDrawSurfaceImpl, IDirect3DTexture2, iface);
645     IDirect3DTextureGLImpl *glThis = (IDirect3DTextureGLImpl *) This->tex_private;
646     IDirectDrawSurfaceImpl *lpD3DTextureImpl = ICOM_OBJECT(IDirectDrawSurfaceImpl, IDirect3DTexture2, lpD3DTexture2);
647     DWORD mem_used;
648     DDSURFACEDESC *src_d, *dst_d;
649     
650     TRACE("(%p/%p)->(%p)\n", This, iface, lpD3DTexture2);
651
652     if (glThis->loaded == FALSE) {
653         /* Only check memory for not already loaded texture... */
654         mem_used = This->surface_desc.dwHeight *
655                    This->surface_desc.u1.lPitch;
656         if (This->ddraw_owner->allocate_memory(This->ddraw_owner, mem_used) < 0) {
657             TRACE(" out of virtual memory... Warning application.\n");
658             return D3DERR_TEXTURE_LOAD_FAILED;
659         }
660     }
661     glThis->loaded = TRUE;
662     
663     TRACE("Copied surface %p to surface %p\n", lpD3DTextureImpl, This);
664
665     if ( This->surface_desc.ddsCaps.dwCaps & DDSCAPS_ALLOCONLOAD )
666         /* If the surface is not allocated and its location is not yet specified,
667            force it to video memory */ 
668         if ( !(This->surface_desc.ddsCaps.dwCaps & (DDSCAPS_SYSTEMMEMORY|DDSCAPS_VIDEOMEMORY)) )
669             This->surface_desc.ddsCaps.dwCaps |= DDSCAPS_VIDEOMEMORY;
670
671     /* Suppress the ALLOCONLOAD flag */
672     This->surface_desc.ddsCaps.dwCaps &= ~DDSCAPS_ALLOCONLOAD;
673     This->palette = lpD3DTextureImpl->palette;
674     
675     /* Copy one surface on the other */
676     dst_d = (DDSURFACEDESC *)&(This->surface_desc);
677     src_d = (DDSURFACEDESC *)&(lpD3DTextureImpl->surface_desc);
678
679     if ((src_d->dwWidth != dst_d->dwWidth) || (src_d->dwHeight != dst_d->dwHeight)) {
680         /* Should also check for same pixel format, u1.lPitch, ... */
681         ERR("Error in surface sizes\n");
682         return D3DERR_TEXTURE_LOAD_FAILED;
683     } else {
684         /* LPDIRECT3DDEVICE2 d3dd = (LPDIRECT3DDEVICE2) This->D3Ddevice; */
685         /* I should put a macro for the calculus of bpp */
686
687         /* Copy also the ColorKeying stuff */
688         if (src_d->dwFlags & DDSD_CKSRCBLT) {
689             dst_d->ddckCKSrcBlt.dwColorSpaceLowValue = src_d->ddckCKSrcBlt.dwColorSpaceLowValue;
690             dst_d->ddckCKSrcBlt.dwColorSpaceHighValue = src_d->ddckCKSrcBlt.dwColorSpaceHighValue;
691         }
692
693         /* Copy the main memry texture into the surface that corresponds to the OpenGL
694            texture object. */
695         memcpy(dst_d->lpSurface, src_d->lpSurface, src_d->u1.lPitch * src_d->dwHeight);
696
697         /* If the GetHandle was not done, it is an error... */
698         if (glThis->tex_name == 0) ERR("Unbound GL texture !!!\n");
699
700         ENTER_GL();
701
702         /* Now, load the texture */
703         /* d3dd->set_context(d3dd); We need to set the context somehow.... */
704
705         gltex_upload_texture(This, glThis->first_unlock);
706         glThis->first_unlock = FALSE;
707         
708         LEAVE_GL();
709     }
710
711     return D3D_OK;
712 }
713
714 HRESULT WINAPI
715 Thunk_IDirect3DTextureImpl_2_QueryInterface(LPDIRECT3DTEXTURE2 iface,
716                                             REFIID riid,
717                                             LPVOID* obp)
718 {
719     TRACE("(%p)->(%s,%p) thunking to IDirectDrawSurface7 interface.\n", iface, debugstr_guid(riid), obp);
720     return IDirectDrawSurface7_QueryInterface(COM_INTERFACE_CAST(IDirectDrawSurfaceImpl, IDirect3DTexture2, IDirectDrawSurface7, iface),
721                                               riid,
722                                               obp);
723 }
724
725 ULONG WINAPI
726 Thunk_IDirect3DTextureImpl_2_AddRef(LPDIRECT3DTEXTURE2 iface)
727 {
728     TRACE("(%p)->() thunking to IDirectDrawSurface7 interface.\n", iface);
729     return IDirectDrawSurface7_AddRef(COM_INTERFACE_CAST(IDirectDrawSurfaceImpl, IDirect3DTexture2, IDirectDrawSurface7, iface));
730 }
731
732 ULONG WINAPI
733 Thunk_IDirect3DTextureImpl_2_Release(LPDIRECT3DTEXTURE2 iface)
734 {
735     TRACE("(%p)->() thunking to IDirectDrawSurface7 interface.\n", iface);
736     return IDirectDrawSurface7_AddRef(COM_INTERFACE_CAST(IDirectDrawSurfaceImpl, IDirect3DTexture2, IDirectDrawSurface7, iface));
737 }
738
739 HRESULT WINAPI
740 Thunk_IDirect3DTextureImpl_1_QueryInterface(LPDIRECT3DTEXTURE iface,
741                                             REFIID riid,
742                                             LPVOID* obp)
743 {
744     TRACE("(%p)->(%s,%p) thunking to IDirectDrawSurface7 interface.\n", iface, debugstr_guid(riid), obp);
745     return IDirectDrawSurface7_QueryInterface(COM_INTERFACE_CAST(IDirectDrawSurfaceImpl, IDirect3DTexture, IDirectDrawSurface7, iface),
746                                               riid,
747                                               obp);
748 }
749
750 ULONG WINAPI
751 Thunk_IDirect3DTextureImpl_1_AddRef(LPDIRECT3DTEXTURE iface)
752 {
753     TRACE("(%p)->() thunking to IDirectDrawSurface7 interface.\n", iface);
754     return IDirectDrawSurface7_AddRef(COM_INTERFACE_CAST(IDirectDrawSurfaceImpl, IDirect3DTexture, IDirectDrawSurface7, iface));
755 }
756
757 ULONG WINAPI
758 Thunk_IDirect3DTextureImpl_1_Release(LPDIRECT3DTEXTURE iface)
759 {
760     TRACE("(%p)->() thunking to IDirectDrawSurface7 interface.\n", iface);
761     return IDirectDrawSurface7_AddRef(COM_INTERFACE_CAST(IDirectDrawSurfaceImpl, IDirect3DTexture, IDirectDrawSurface7, iface));
762 }
763
764 HRESULT WINAPI
765 Thunk_IDirect3DTextureImpl_1_PaletteChanged(LPDIRECT3DTEXTURE iface,
766                                             DWORD dwStart,
767                                             DWORD dwCount)
768 {
769     TRACE("(%p)->(%08lx,%08lx) thunking to IDirect3DTexture2 interface.\n", iface, dwStart, dwCount);
770     return IDirect3DTexture2_PaletteChanged(COM_INTERFACE_CAST(IDirectDrawSurfaceImpl, IDirect3DTexture, IDirect3DTexture2, iface),
771                                             dwStart,
772                                             dwCount);
773 }
774
775 HRESULT WINAPI
776 Thunk_IDirect3DTextureImpl_1_GetHandle(LPDIRECT3DTEXTURE iface,
777                                        LPDIRECT3DDEVICE lpDirect3DDevice,
778                                        LPD3DTEXTUREHANDLE lpHandle)
779 {
780     TRACE("(%p)->(%p,%p) thunking to IDirect3DTexture2 interface.\n", iface, lpDirect3DDevice, lpHandle);
781     return IDirect3DTexture2_GetHandle(COM_INTERFACE_CAST(IDirectDrawSurfaceImpl, IDirect3DTexture, IDirect3DTexture2, iface),
782                                        COM_INTERFACE_CAST(IDirect3DDeviceImpl, IDirect3DDevice, IDirect3DDevice2, lpDirect3DDevice),
783                                        lpHandle);
784 }
785
786 HRESULT WINAPI
787 Thunk_IDirect3DTextureImpl_1_Load(LPDIRECT3DTEXTURE iface,
788                                   LPDIRECT3DTEXTURE lpD3DTexture)
789 {
790     TRACE("(%p)->(%p) thunking to IDirect3DTexture2 interface.\n", iface, lpD3DTexture);
791     return IDirect3DTexture2_Load(COM_INTERFACE_CAST(IDirectDrawSurfaceImpl, IDirect3DTexture, IDirect3DTexture2, iface),
792                                   COM_INTERFACE_CAST(IDirectDrawSurfaceImpl, IDirect3DTexture, IDirect3DTexture2, lpD3DTexture));
793 }
794
795 #if !defined(__STRICT_ANSI__) && defined(__GNUC__)
796 # define XCAST(fun)     (typeof(VTABLE_IDirect3DTexture2.fun))
797 #else
798 # define XCAST(fun)     (void*)
799 #endif
800
801 ICOM_VTABLE(IDirect3DTexture2) VTABLE_IDirect3DTexture2 =
802 {
803     ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE
804     XCAST(QueryInterface) Thunk_IDirect3DTextureImpl_2_QueryInterface,
805     XCAST(AddRef) Thunk_IDirect3DTextureImpl_2_AddRef,
806     XCAST(Release) Thunk_IDirect3DTextureImpl_2_Release,
807     XCAST(GetHandle) GL_IDirect3DTextureImpl_2_1T_GetHandle,
808     XCAST(PaletteChanged) Main_IDirect3DTextureImpl_2_1T_PaletteChanged,
809     XCAST(Load) GL_IDirect3DTextureImpl_2_1T_Load,
810 };
811
812 #if !defined(__STRICT_ANSI__) && defined(__GNUC__)
813 #undef XCAST
814 #endif
815
816
817 #if !defined(__STRICT_ANSI__) && defined(__GNUC__)
818 # define XCAST(fun)     (typeof(VTABLE_IDirect3DTexture.fun))
819 #else
820 # define XCAST(fun)     (void*)
821 #endif
822
823 ICOM_VTABLE(IDirect3DTexture) VTABLE_IDirect3DTexture =
824 {
825     ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE
826     XCAST(QueryInterface) Thunk_IDirect3DTextureImpl_1_QueryInterface,
827     XCAST(AddRef) Thunk_IDirect3DTextureImpl_1_AddRef,
828     XCAST(Release) Thunk_IDirect3DTextureImpl_1_Release,
829     XCAST(Initialize) Main_IDirect3DTextureImpl_1_Initialize,
830     XCAST(GetHandle) Thunk_IDirect3DTextureImpl_1_GetHandle,
831     XCAST(PaletteChanged) Thunk_IDirect3DTextureImpl_1_PaletteChanged,
832     XCAST(Load) Thunk_IDirect3DTextureImpl_1_Load,
833     XCAST(Unload) Main_IDirect3DTextureImpl_1_Unload,
834 };
835
836 #if !defined(__STRICT_ANSI__) && defined(__GNUC__)
837 #undef XCAST
838 #endif
839
840 HRESULT d3dtexture_create(IDirect3DImpl *d3d, IDirectDrawSurfaceImpl *surf, BOOLEAN at_creation, 
841                           IDirectDrawSurfaceImpl *main, DWORD mipmap_level)
842 {
843     IDirect3DTextureGLImpl *private;
844
845     private = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IDirect3DTextureGLImpl));
846     if (private == NULL) return DDERR_OUTOFMEMORY;
847
848     private->final_release = surf->final_release;
849     private->lock_update = surf->lock_update;
850     private->unlock_update = surf->unlock_update;
851     private->mipmap_level = mipmap_level;
852     
853     /* If at creation, we can optimize stuff and wait the first 'unlock' to upload a valid stuff to OpenGL.
854        Otherwise, it will be uploaded here (and may be invalid). */
855     if (at_creation == TRUE)
856         private->first_unlock = TRUE;
857     else
858         private->first_unlock = FALSE;
859     surf->final_release = gltex_final_release;
860     surf->lock_update = gltex_lock_update;
861     surf->unlock_update = gltex_unlock_update;
862     surf->tex_private = private;
863     surf->SetColorKey_cb = gltex_setcolorkey_cb;
864     
865     ICOM_INIT_INTERFACE(surf, IDirect3DTexture,  VTABLE_IDirect3DTexture);
866     ICOM_INIT_INTERFACE(surf, IDirect3DTexture2, VTABLE_IDirect3DTexture2);
867
868     ENTER_GL();
869     if (mipmap_level == 0) {
870         glGenTextures(1, &(private->tex_name));
871         if (private->tex_name == 0) ERR("Error at creation of OpenGL texture ID !\n");
872         TRACE(" GL texture created (private data at %p and GL id %d).\n", private, private->tex_name);
873     } else {
874         private->tex_name = ((IDirect3DTextureGLImpl *) main->tex_private)->tex_name;
875         TRACE(" GL texture created (private data at %p and GL id reusing id %d).\n", private, private->tex_name);
876     }
877
878     if ((at_creation == FALSE) &&
879         ((surf->surface_desc.ddsCaps.dwCaps & DDSCAPS_ALLOCONLOAD) == 0))
880     {
881         gltex_upload_texture(surf, TRUE);
882     }
883     LEAVE_GL();
884
885     return D3D_OK;
886 }