Fix segmentation fault caused by incorrect referencing of client audio
[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 <stdarg.h>
24 #include <string.h>
25
26 #define NONAMELESSUNION
27 #define NONAMELESSSTRUCT
28 #include "windef.h"
29 #include "winbase.h"
30 #include "winerror.h"
31 #include "objbase.h"
32 #include "wingdi.h"
33 #include "ddraw.h"
34 #include "d3d.h"
35 #include "wine/debug.h"
36
37 #include "mesa_private.h"
38
39 WINE_DEFAULT_DEBUG_CHANNEL(ddraw);
40 WINE_DECLARE_DEBUG_CHANNEL(ddraw_tex);
41
42 #include <stdio.h>
43
44 static void 
45 snoop_texture(IDirectDrawSurfaceImpl *This) {
46     IDirect3DTextureGLImpl *glThis = (IDirect3DTextureGLImpl *) This->tex_private;
47     char buf[128];
48     FILE *f;
49
50     TRACE_(ddraw_tex)("Dumping surface id (%5d) level (%2d) : \n", glThis->tex_name, This->mipmap_level);
51     DDRAW_dump_surface_desc(&(This->surface_desc));
52     
53     sprintf(buf, "tex_%05d_%02d.pnm", glThis->tex_name, This->mipmap_level);
54     f = fopen(buf, "wb");
55     DDRAW_dump_surface_to_disk(This, f, 1);
56 }
57
58 static IDirectDrawSurfaceImpl *
59 get_sub_mimaplevel(IDirectDrawSurfaceImpl *tex_ptr)
60 {
61     /* Now go down the mipmap chain to the next surface */
62     static const DDSCAPS2 mipmap_caps = { DDSCAPS_MIPMAP | DDSCAPS_TEXTURE, 0, 0, 0 };
63     LPDIRECTDRAWSURFACE7 next_level;
64     IDirectDrawSurfaceImpl *surf_ptr;
65     HRESULT hr;
66     
67     hr = IDirectDrawSurface7_GetAttachedSurface(ICOM_INTERFACE(tex_ptr, IDirectDrawSurface7),
68                                                 (DDSCAPS2 *) &mipmap_caps, &next_level);
69     if (FAILED(hr)) return NULL;
70     
71     surf_ptr = ICOM_OBJECT(IDirectDrawSurfaceImpl, IDirectDrawSurface7, next_level);
72     IDirectDrawSurface7_Release(next_level);
73     
74     return surf_ptr;
75 }
76
77 /*******************************************************************************
78  *                         IDirectSurface callback methods
79  */
80
81 HRESULT
82 gltex_download_texture(IDirectDrawSurfaceImpl *surf_ptr) {
83     IDirect3DTextureGLImpl *gl_surf_ptr = (IDirect3DTextureGLImpl *) surf_ptr->tex_private;
84
85     FIXME("This is not supported yet... Expect some graphical glitches !!!\n");
86
87     /* GL and memory are in sync again ... 
88        No need to change the 'global' flag as it only handles the 'MEMORY_DIRTY' case.
89     */
90     gl_surf_ptr->dirty_flag = SURFACE_MEMORY;
91     
92     return DD_OK;
93 }
94
95 static GLenum
96 convert_min_filter_to_GL(D3DTEXTUREMINFILTER dwMinState, D3DTEXTUREMIPFILTER dwMipState)
97 {
98     GLenum gl_state;
99
100     if (dwMipState == D3DTFP_NONE) {
101         switch (dwMinState) {
102             case D3DTFN_POINT:  gl_state = GL_NEAREST; break;
103             case D3DTFN_LINEAR: gl_state = GL_LINEAR;  break;
104             default:            gl_state = GL_LINEAR;  break;
105         }
106     } else if (dwMipState == D3DTFP_POINT) {
107         switch (dwMinState) {
108             case D3DTFN_POINT:  gl_state = GL_NEAREST_MIPMAP_NEAREST; break;
109             case D3DTFN_LINEAR: gl_state = GL_LINEAR_MIPMAP_NEAREST;  break;
110             default:            gl_state = GL_LINEAR_MIPMAP_NEAREST;  break;
111         }
112     } else {
113         switch (dwMinState) {
114             case D3DTFN_POINT:  gl_state = GL_NEAREST_MIPMAP_LINEAR; break;
115             case D3DTFN_LINEAR: gl_state = GL_LINEAR_MIPMAP_LINEAR;  break;
116             default:            gl_state = GL_LINEAR_MIPMAP_LINEAR;  break;
117         }
118     }
119     return gl_state;
120 }
121
122 static GLenum
123 convert_mag_filter_to_GL(D3DTEXTUREMAGFILTER dwState)
124 {
125     GLenum gl_state;
126
127     switch (dwState) {
128         case D3DTFG_POINT:
129             gl_state = GL_NEAREST;
130             break;
131         case D3DTFG_LINEAR:
132             gl_state = GL_LINEAR;
133             break;
134         default:
135             gl_state = GL_LINEAR;
136             break;
137     }
138     return gl_state;
139 }
140
141 static GLenum
142 convert_tex_address_to_GL(D3DTEXTUREADDRESS dwState)
143 {
144     GLenum gl_state;
145     switch (dwState) {
146         case D3DTADDRESS_WRAP:   gl_state = GL_REPEAT; break;
147         case D3DTADDRESS_CLAMP:  gl_state = GL_CLAMP; break;
148         case D3DTADDRESS_BORDER: gl_state = GL_CLAMP_TO_EDGE; break;
149         case D3DTADDRESS_MIRROR:
150             if (GL_extensions.mirrored_repeat) {
151                 gl_state = GL_MIRRORED_REPEAT_WINE;
152             } else {
153                 gl_state = GL_REPEAT;
154                 /* This is a TRACE instead of a FIXME as the FIXME was already printed when the game
155                    actually set D3DTADDRESS_MIRROR.
156                 */
157                 TRACE(" setting GL_REPEAT instead of GL_MIRRORED_REPEAT.\n");
158             }
159         break;
160         default:                 gl_state = GL_REPEAT; break;
161     }
162     return gl_state;
163 }
164
165 HRESULT
166 gltex_upload_texture(IDirectDrawSurfaceImpl *surf_ptr, IDirect3DDeviceImpl *d3ddev, DWORD stage) {
167     IDirect3DTextureGLImpl *gl_surf_ptr = (IDirect3DTextureGLImpl *) surf_ptr->tex_private;
168     IDirect3DDeviceGLImpl *gl_d3ddev = (IDirect3DDeviceGLImpl *) d3ddev;
169     BOOLEAN changed = FALSE;
170     GLenum unit = GL_TEXTURE0_WINE + stage;
171     
172     if (surf_ptr->mipmap_level != 0) {
173         WARN(" application activating a sub-level of the mipmapping chain (level %d) !\n", surf_ptr->mipmap_level);
174     }
175
176     /* Now check if the texture parameters for this texture are still in-line with what D3D expect
177        us to do..
178
179        NOTE: there is no check for the situation where the same texture is bound to multiple stage
180              but with different parameters per stage.
181     */
182     if ((gl_surf_ptr->tex_parameters == NULL) ||
183         (gl_surf_ptr->tex_parameters[D3DTSS_MAXMIPLEVEL - D3DTSS_ADDRESSU] != 
184          d3ddev->state_block.texture_stage_state[stage][D3DTSS_MAXMIPLEVEL - 1])) {
185         DWORD max_mip_level;
186         
187         if ((surf_ptr->surface_desc.ddsCaps.dwCaps & DDSCAPS_MIPMAP) == 0) {
188             max_mip_level = 0;
189         } else {
190             max_mip_level = surf_ptr->surface_desc.u2.dwMipMapCount - 1;
191             if (d3ddev->state_block.texture_stage_state[stage][D3DTSS_MAXMIPLEVEL - 1] != 0) {
192                 if (max_mip_level >= d3ddev->state_block.texture_stage_state[stage][D3DTSS_MAXMIPLEVEL - 1]) {
193                     max_mip_level = d3ddev->state_block.texture_stage_state[stage][D3DTSS_MAXMIPLEVEL - 1] - 1;
194                 }
195             }
196         }
197         if (unit != gl_d3ddev->current_active_tex_unit) {
198             GL_extensions.glActiveTexture(unit);
199             gl_d3ddev->current_active_tex_unit = unit;
200         }
201         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, max_mip_level);
202         changed = TRUE;
203     }
204     
205     if ((gl_surf_ptr->tex_parameters == NULL) ||
206         (gl_surf_ptr->tex_parameters[D3DTSS_MAGFILTER - D3DTSS_ADDRESSU] != 
207          d3ddev->state_block.texture_stage_state[stage][D3DTSS_MAGFILTER - 1])) {
208         if (unit != gl_d3ddev->current_active_tex_unit) {
209             GL_extensions.glActiveTexture(unit);
210             gl_d3ddev->current_active_tex_unit = unit;
211         }
212         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, 
213                         convert_mag_filter_to_GL(d3ddev->state_block.texture_stage_state[stage][D3DTSS_MAGFILTER - 1]));
214         changed = TRUE;
215     }
216     if ((gl_surf_ptr->tex_parameters == NULL) ||
217         (gl_surf_ptr->tex_parameters[D3DTSS_MINFILTER - D3DTSS_ADDRESSU] != 
218          d3ddev->state_block.texture_stage_state[stage][D3DTSS_MINFILTER - 1]) ||
219         (gl_surf_ptr->tex_parameters[D3DTSS_MIPFILTER - D3DTSS_ADDRESSU] != 
220          d3ddev->state_block.texture_stage_state[stage][D3DTSS_MIPFILTER - 1])) {
221         if (unit != gl_d3ddev->current_active_tex_unit) {
222             GL_extensions.glActiveTexture(unit);
223             gl_d3ddev->current_active_tex_unit = unit;
224         }
225         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER,
226                         convert_min_filter_to_GL(d3ddev->state_block.texture_stage_state[stage][D3DTSS_MINFILTER - 1],
227                                                  d3ddev->state_block.texture_stage_state[stage][D3DTSS_MIPFILTER - 1]));
228         changed = TRUE;
229     }
230     if ((gl_surf_ptr->tex_parameters == NULL) ||
231         (gl_surf_ptr->tex_parameters[D3DTSS_ADDRESSU - D3DTSS_ADDRESSU] != 
232          d3ddev->state_block.texture_stage_state[stage][D3DTSS_ADDRESSU - 1])) {
233         if (unit != gl_d3ddev->current_active_tex_unit) {
234             GL_extensions.glActiveTexture(unit);
235             gl_d3ddev->current_active_tex_unit = unit;
236         }
237         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S,
238                         convert_tex_address_to_GL(d3ddev->state_block.texture_stage_state[stage][D3DTSS_ADDRESSU - 1]));
239         changed = TRUE;
240     }
241     if ((gl_surf_ptr->tex_parameters == NULL) ||
242         (gl_surf_ptr->tex_parameters[D3DTSS_ADDRESSV - D3DTSS_ADDRESSU] != 
243          d3ddev->state_block.texture_stage_state[stage][D3DTSS_ADDRESSV - 1])) {
244         if (unit != gl_d3ddev->current_active_tex_unit) {
245             GL_extensions.glActiveTexture(unit);
246             gl_d3ddev->current_active_tex_unit = unit;
247         }
248         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T,
249                         convert_tex_address_to_GL(d3ddev->state_block.texture_stage_state[stage][D3DTSS_ADDRESSV - 1]));        
250         changed = TRUE;
251     }
252     if ((gl_surf_ptr->tex_parameters == NULL) ||
253         (gl_surf_ptr->tex_parameters[D3DTSS_BORDERCOLOR - D3DTSS_ADDRESSU] != 
254          d3ddev->state_block.texture_stage_state[stage][D3DTSS_BORDERCOLOR - 1])) {
255         GLfloat color[4];
256         
257         color[0] = ((d3ddev->state_block.texture_stage_state[stage][D3DTSS_BORDERCOLOR - 1] >> 16) & 0xFF) / 255.0;
258         color[1] = ((d3ddev->state_block.texture_stage_state[stage][D3DTSS_BORDERCOLOR - 1] >>  8) & 0xFF) / 255.0;
259         color[2] = ((d3ddev->state_block.texture_stage_state[stage][D3DTSS_BORDERCOLOR - 1] >>  0) & 0xFF) / 255.0;
260         color[3] = ((d3ddev->state_block.texture_stage_state[stage][D3DTSS_BORDERCOLOR - 1] >> 24) & 0xFF) / 255.0;
261         if (unit != gl_d3ddev->current_active_tex_unit) {
262             GL_extensions.glActiveTexture(unit);
263             gl_d3ddev->current_active_tex_unit = unit;
264         }
265         glTexParameterfv(GL_TEXTURE_2D, GL_TEXTURE_BORDER_COLOR, color);
266         changed = TRUE;
267     }
268
269     if (changed) {
270         if (gl_surf_ptr->tex_parameters == NULL) {
271             gl_surf_ptr->tex_parameters = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
272                                                     sizeof(DWORD) * (D3DTSS_MAXMIPLEVEL + 1 - D3DTSS_ADDRESSU));
273         }
274         memcpy(gl_surf_ptr->tex_parameters, &(d3ddev->state_block.texture_stage_state[stage][D3DTSS_ADDRESSU - 1]),
275                sizeof(DWORD) * (D3DTSS_MAXMIPLEVEL + 1 - D3DTSS_ADDRESSU));
276     }
277
278     if (*(gl_surf_ptr->global_dirty_flag) != SURFACE_MEMORY_DIRTY) {
279         TRACE(" nothing to do - memory copy and GL state in synch for all texture levels.\n");
280         return DD_OK;
281     }
282     
283     while (surf_ptr != NULL) {
284         IDirect3DTextureGLImpl *gl_surf_ptr = (IDirect3DTextureGLImpl *) surf_ptr->tex_private;
285         
286         if (gl_surf_ptr->dirty_flag != SURFACE_MEMORY_DIRTY) {
287             TRACE("   - level %d already uploaded.\n", surf_ptr->mipmap_level);
288         } else {
289             TRACE("   - uploading texture level %d (initial done = %d).\n",
290                   surf_ptr->mipmap_level, gl_surf_ptr->initial_upload_done);
291
292             /* Texture snooping for the curious :-) */
293             if (TRACE_ON(ddraw_tex)) {
294                 snoop_texture(surf_ptr);
295             }
296
297             if (unit != gl_d3ddev->current_active_tex_unit) {
298                 GL_extensions.glActiveTexture(unit);
299                 gl_d3ddev->current_active_tex_unit = unit;
300             }
301             
302             if (upload_surface_to_tex_memory_init(surf_ptr, surf_ptr->mipmap_level, &(gl_surf_ptr->current_internal_format),
303                                                   gl_surf_ptr->initial_upload_done == FALSE, TRUE, 0, 0) == DD_OK) {
304                 upload_surface_to_tex_memory(NULL, 0, 0, &(gl_surf_ptr->surface_ptr));
305                 upload_surface_to_tex_memory_release();
306                 gl_surf_ptr->dirty_flag = SURFACE_MEMORY;
307                 gl_surf_ptr->initial_upload_done = TRUE;
308             } else {
309                 ERR("Problem for upload of texture %d (level = %d / initial done = %d).\n",
310                     gl_surf_ptr->tex_name, surf_ptr->mipmap_level, gl_surf_ptr->initial_upload_done);
311             }
312         }
313         
314         if (surf_ptr->surface_desc.ddsCaps.dwCaps & DDSCAPS_MIPMAP) {
315             surf_ptr = get_sub_mimaplevel(surf_ptr);
316         } else {
317             surf_ptr = NULL;
318         }
319     }
320     
321     *(gl_surf_ptr->global_dirty_flag) = SURFACE_MEMORY;
322     
323     return DD_OK;
324 }
325
326 HRESULT WINAPI
327 Main_IDirect3DTextureImpl_1_Initialize(LPDIRECT3DTEXTURE iface,
328                                        LPDIRECT3DDEVICE lpDirect3DDevice,
329                                        LPDIRECTDRAWSURFACE lpDDSurface)
330 {
331     ICOM_THIS_FROM(IDirectDrawSurfaceImpl, IDirect3DTexture, iface);
332     FIXME("(%p/%p)->(%p,%p) no-op...\n", This, iface, lpDirect3DDevice, lpDDSurface);
333     return DD_OK;
334 }
335
336 static HRESULT
337 gltex_setcolorkey_cb(IDirectDrawSurfaceImpl *This, DWORD dwFlags, LPDDCOLORKEY ckey )
338 {
339     IDirect3DTextureGLImpl *glThis = (IDirect3DTextureGLImpl *) This->tex_private;
340
341     if (glThis->dirty_flag == SURFACE_GL) {
342         GLuint cur_tex;
343
344         TRACE(" flushing GL texture back to memory.\n");
345         
346         ENTER_GL();
347         glGetIntegerv(GL_TEXTURE_BINDING_2D, &cur_tex);
348         glBindTexture(GL_TEXTURE_2D, glThis->tex_name);
349         gltex_download_texture(This);
350         glBindTexture(GL_TEXTURE_2D, cur_tex);
351         LEAVE_GL();
352     }
353
354     glThis->dirty_flag = SURFACE_MEMORY_DIRTY;
355     *(glThis->global_dirty_flag) = SURFACE_MEMORY_DIRTY;
356     /* TODO: check color-keying on mipmapped surfaces... */
357     
358     return DD_OK;
359 }
360
361 HRESULT
362 gltex_blt(IDirectDrawSurfaceImpl *This, LPRECT rdst,
363           LPDIRECTDRAWSURFACE7 src, LPRECT rsrc,
364           DWORD dwFlags, LPDDBLTFX lpbltfx)
365 {
366     if (src != NULL) {
367         IDirectDrawSurfaceImpl *src_ptr = ICOM_OBJECT(IDirectDrawSurfaceImpl, IDirectDrawSurface7, src);
368         if (src_ptr->surface_desc.ddsCaps.dwCaps & DDSCAPS_3DDEVICE) {
369             FIXME("Blt from framebuffer to texture - unsupported now, please report !\n");
370         }
371     }
372     return DDERR_INVALIDPARAMS;
373 }
374
375 HRESULT
376 gltex_bltfast(IDirectDrawSurfaceImpl *surf_ptr, DWORD dstx,
377               DWORD dsty, LPDIRECTDRAWSURFACE7 src,
378               LPRECT rsrc, DWORD trans)
379 {
380     if (src != NULL) {
381         IDirectDrawSurfaceImpl *src_ptr = ICOM_OBJECT(IDirectDrawSurfaceImpl, IDirectDrawSurface7, src);
382         
383         if ((src_ptr->surface_desc.ddsCaps.dwCaps & DDSCAPS_3DDEVICE) &&
384             ((trans & (DDBLTFAST_SRCCOLORKEY | DDBLTFAST_DESTCOLORKEY)) == 0)) {
385             /* This is a blt without color keying... We can use the direct copy. */
386             RECT rsrc2;
387             DWORD width, height;
388             GLuint cur_tex;
389             IDirect3DTextureGLImpl *gl_surf_ptr = surf_ptr->tex_private;
390             int y;
391             
392             if (rsrc == NULL) {
393                 WARN("rsrc is NULL\n");
394                 rsrc = &rsrc2;
395                 
396                 rsrc->left = 0;
397                 rsrc->top = 0;
398                 rsrc->right = src_ptr->surface_desc.dwWidth;
399                 rsrc->bottom = src_ptr->surface_desc.dwHeight;
400             }
401             
402             width = rsrc->right - rsrc->left;
403             height = rsrc->bottom - rsrc->top;
404             
405             if (((dstx + width)  > surf_ptr->surface_desc.dwWidth) ||
406                 ((dsty + height) > surf_ptr->surface_desc.dwHeight)) {
407                 FIXME("Does not handle clipping yet in FB => Texture blits !\n");
408                 return DDERR_INVALIDPARAMS;
409             }
410
411             if ((width == 0) || (height == 0)) {
412                 return DD_OK;
413             }
414             
415             TRACE(" direct frame buffer => texture BltFast override.\n");
416             
417             ENTER_GL();
418             
419             glGetIntegerv(GL_TEXTURE_BINDING_2D, &cur_tex);
420             /* This call is to create the actual texture name in GL (as we do 'late' ID creation) */
421             gltex_get_tex_name(surf_ptr);
422             glBindTexture(GL_TEXTURE_2D, gl_surf_ptr->tex_name);
423             
424             if ((gl_surf_ptr->dirty_flag == SURFACE_MEMORY_DIRTY) &&
425                 !((dstx == 0) && (dsty == 0) &&
426                   (width == surf_ptr->surface_desc.dwWidth) && (height == surf_ptr->surface_desc.dwHeight))) {
427                 /* If not 'full size' and the surface is dirty, first flush it to GL before doing the copy. */
428                 if (upload_surface_to_tex_memory_init(surf_ptr, surf_ptr->mipmap_level, &(gl_surf_ptr->current_internal_format),
429                                                       gl_surf_ptr->initial_upload_done == FALSE, TRUE, 0, 0) == DD_OK) {
430                     upload_surface_to_tex_memory(NULL, 0, 0, &(gl_surf_ptr->surface_ptr));
431                     upload_surface_to_tex_memory_release();
432                     gl_surf_ptr->dirty_flag = SURFACE_MEMORY;
433                     gl_surf_ptr->initial_upload_done = TRUE;
434                 } else {
435                     glBindTexture(GL_TEXTURE_2D, cur_tex);
436                     LEAVE_GL();
437                     ERR("Error at texture upload !\n");
438                     return DDERR_INVALIDPARAMS;
439                 }
440             }
441
442             /* This is a hack and would need some clean-up :-) */
443             if (gl_surf_ptr->initial_upload_done == FALSE) {
444                 if (upload_surface_to_tex_memory_init(surf_ptr, surf_ptr->mipmap_level, &(gl_surf_ptr->current_internal_format),
445                                                       TRUE, TRUE, 0, 0) == DD_OK) {
446                     upload_surface_to_tex_memory(NULL, 0, 0, &(gl_surf_ptr->surface_ptr));
447                     upload_surface_to_tex_memory_release();
448                     gl_surf_ptr->dirty_flag = SURFACE_MEMORY;
449                     gl_surf_ptr->initial_upload_done = TRUE;
450                 } else {
451                     glBindTexture(GL_TEXTURE_2D, cur_tex);
452                     LEAVE_GL();
453                     ERR("Error at texture upload (initial case) !\n");
454                     return DDERR_INVALIDPARAMS;
455                 }
456             }
457             
458             if ((src_ptr->surface_desc.ddsCaps.dwCaps & (DDSCAPS_FRONTBUFFER|DDSCAPS_PRIMARYSURFACE)) != 0)
459                 glReadBuffer(GL_FRONT);
460             else if ((src_ptr->surface_desc.ddsCaps.dwCaps & (DDSCAPS_BACKBUFFER)) == (DDSCAPS_BACKBUFFER))
461                 glReadBuffer(GL_BACK);
462             else {
463                 ERR("Wrong surface type for locking !\n");
464                 glBindTexture(GL_TEXTURE_2D, cur_tex);
465                 LEAVE_GL();
466                 return DDERR_INVALIDPARAMS;
467             }
468             
469             for (y = (src_ptr->surface_desc.dwHeight - rsrc->top - 1);
470                  y >= (src_ptr->surface_desc.dwHeight - (rsrc->top + height));
471                  y--) {
472                 glCopyTexSubImage2D(GL_TEXTURE_2D, surf_ptr->mipmap_level,
473                                     dstx, dsty,
474                                     rsrc->left, y,
475                                     width, 1);
476                 dsty++;
477             }
478             
479             glBindTexture(GL_TEXTURE_2D, cur_tex);
480             LEAVE_GL();
481             
482             /* The SURFACE_GL case is not handled by the 'global' dirty flag */
483             gl_surf_ptr->dirty_flag = SURFACE_GL;
484             
485             return DD_OK;
486         }
487     }
488     return DDERR_INVALIDPARAMS;
489 }
490
491 HRESULT WINAPI
492 Main_IDirect3DTextureImpl_2_1T_PaletteChanged(LPDIRECT3DTEXTURE2 iface,
493                                               DWORD dwStart,
494                                               DWORD dwCount)
495 {
496     ICOM_THIS_FROM(IDirectDrawSurfaceImpl, IDirect3DTexture2, iface);
497     FIXME("(%p/%p)->(%08lx,%08lx): stub!\n", This, iface, dwStart, dwCount);
498     return DD_OK;
499 }
500
501 HRESULT WINAPI
502 Main_IDirect3DTextureImpl_1_Unload(LPDIRECT3DTEXTURE iface)
503 {
504     ICOM_THIS_FROM(IDirectDrawSurfaceImpl, IDirect3DTexture, iface);
505     FIXME("(%p/%p)->(): stub!\n", This, iface);
506     return DD_OK;
507 }
508
509 HRESULT WINAPI
510 Main_IDirect3DTextureImpl_2_1T_GetHandle(LPDIRECT3DTEXTURE2 iface,
511                                          LPDIRECT3DDEVICE2 lpDirect3DDevice2,
512                                          LPD3DTEXTUREHANDLE lpHandle)
513 {
514     ICOM_THIS_FROM(IDirectDrawSurfaceImpl, IDirect3DTexture2, iface);
515     IDirect3DDeviceImpl *lpDeviceImpl = ICOM_OBJECT(IDirect3DDeviceImpl, IDirect3DDevice2, lpDirect3DDevice2);
516     
517     TRACE("(%p/%p)->(%p,%p)\n", This, iface, lpDirect3DDevice2, lpHandle);
518
519     /* The handle is simply the pointer to the implementation structure */
520     *lpHandle = (D3DTEXTUREHANDLE) This;
521
522     TRACE(" returning handle %08lx.\n", *lpHandle);
523     
524     /* Now set the device for this texture */
525     This->d3ddevice = lpDeviceImpl;
526
527     return D3D_OK;
528 }
529
530 HRESULT WINAPI
531 Main_IDirect3DTextureImpl_2_1T_Load(LPDIRECT3DTEXTURE2 iface,
532                                     LPDIRECT3DTEXTURE2 lpD3DTexture2)
533 {
534     ICOM_THIS_FROM(IDirectDrawSurfaceImpl, IDirect3DTexture2, iface);
535     FIXME("(%p/%p)->(%p): stub!\n", This, iface, lpD3DTexture2);
536     return DD_OK;
537 }
538
539 static void gltex_set_palette(IDirectDrawSurfaceImpl* This, IDirectDrawPaletteImpl* pal)
540 {
541     IDirect3DTextureGLImpl *glThis = (IDirect3DTextureGLImpl *) This->tex_private;
542
543     if (glThis->dirty_flag == SURFACE_GL) {
544         GLuint cur_tex;
545         
546         TRACE(" flushing GL texture back to memory.\n");
547         
548         ENTER_GL();
549         glGetIntegerv(GL_TEXTURE_BINDING_2D, &cur_tex);
550         glBindTexture(GL_TEXTURE_2D, glThis->tex_name);
551         gltex_download_texture(This);
552         glBindTexture(GL_TEXTURE_2D, cur_tex);
553         LEAVE_GL();
554     }
555     
556     /* First call the previous set_palette function */
557     glThis->set_palette(This, pal);
558     
559     /* And set the dirty flag */
560     glThis->dirty_flag = SURFACE_MEMORY_DIRTY;
561     *(glThis->global_dirty_flag) = SURFACE_MEMORY_DIRTY;
562     
563     /* TODO: check palette on mipmapped surfaces...
564        TODO: do we need to re-upload in case of usage of the paletted texture extension ? */
565 }
566
567 static void
568 gltex_final_release(IDirectDrawSurfaceImpl *This)
569 {
570     IDirect3DTextureGLImpl *glThis = (IDirect3DTextureGLImpl *) This->tex_private;
571     DWORD mem_used;
572     int i;
573
574     TRACE(" deleting texture with GL id %d.\n", glThis->tex_name);
575
576     /* And delete texture handle */
577     ENTER_GL();
578     if (glThis->tex_name != 0)
579         glDeleteTextures(1, &(glThis->tex_name));
580     LEAVE_GL(); 
581
582     HeapFree(GetProcessHeap(), 0, glThis->surface_ptr);
583
584     /* And if this texture was the current one, remove it at the device level */
585     if (This->d3ddevice != NULL)
586         for (i = 0; i < MAX_TEXTURES; i++)
587             if (This->d3ddevice->current_texture[i] == This)
588                 This->d3ddevice->current_texture[i] = NULL;
589
590     /* All this should be part of main surface management not just a hack for texture.. */
591     if (glThis->loaded) {
592         mem_used = This->surface_desc.dwHeight *
593                    This->surface_desc.u1.lPitch;
594         This->ddraw_owner->free_memory(This->ddraw_owner, mem_used);
595     }
596
597     glThis->final_release(This);
598 }
599
600 static void
601 gltex_lock_update(IDirectDrawSurfaceImpl* This, LPCRECT pRect, DWORD dwFlags)
602 {
603     IDirect3DTextureGLImpl *glThis = (IDirect3DTextureGLImpl *) This->tex_private;
604     
605     glThis->lock_update(This, pRect, dwFlags);
606 }
607
608 static void
609 gltex_unlock_update(IDirectDrawSurfaceImpl* This, LPCRECT pRect)
610 {
611     IDirect3DTextureGLImpl *glThis = (IDirect3DTextureGLImpl *) This->tex_private;
612
613     glThis->unlock_update(This, pRect);
614     
615     /* Set the dirty flag according to the lock type */
616     if ((This->lastlocktype & DDLOCK_READONLY) == 0) {
617         glThis->dirty_flag = SURFACE_MEMORY_DIRTY;
618         *(glThis->global_dirty_flag) = SURFACE_MEMORY_DIRTY;
619     }
620 }
621
622 HRESULT WINAPI
623 GL_IDirect3DTextureImpl_2_1T_Load(LPDIRECT3DTEXTURE2 iface,
624                                   LPDIRECT3DTEXTURE2 lpD3DTexture2)
625 {
626     ICOM_THIS_FROM(IDirectDrawSurfaceImpl, IDirect3DTexture2, iface);
627     IDirectDrawSurfaceImpl *src_ptr = ICOM_OBJECT(IDirectDrawSurfaceImpl, IDirect3DTexture2, lpD3DTexture2);
628     IDirectDrawSurfaceImpl *dst_ptr = This;
629     HRESULT ret_value = D3D_OK;
630    
631     TRACE("(%p/%p)->(%p)\n", This, iface, lpD3DTexture2);
632
633     if (((src_ptr->surface_desc.ddsCaps.dwCaps & DDSCAPS_MIPMAP) != (dst_ptr->surface_desc.ddsCaps.dwCaps & DDSCAPS_MIPMAP)) ||
634         (src_ptr->surface_desc.u2.dwMipMapCount != dst_ptr->surface_desc.u2.dwMipMapCount)) {
635         ERR("Trying to load surfaces with different mip-map counts !\n");
636     }
637
638     /* Now loop through all mipmap levels and load all of them... */
639     while (1) {
640         IDirect3DTextureGLImpl *gl_dst_ptr = (IDirect3DTextureGLImpl *) dst_ptr->tex_private;
641         DDSURFACEDESC *src_d, *dst_d;
642         
643         if (gl_dst_ptr != NULL) {
644             if (gl_dst_ptr->loaded == FALSE) {
645                 /* Only check memory for not already loaded texture... */
646                 DWORD mem_used;
647                 if (dst_ptr->surface_desc.u4.ddpfPixelFormat.dwFlags & DDPF_FOURCC)
648                     mem_used = dst_ptr->surface_desc.u1.dwLinearSize;
649                 else
650                     mem_used = dst_ptr->surface_desc.dwHeight * dst_ptr->surface_desc.u1.lPitch;
651                 if (This->ddraw_owner->allocate_memory(This->ddraw_owner, mem_used) < 0) {
652                     TRACE(" out of virtual memory... Warning application.\n");
653                     return D3DERR_TEXTURE_LOAD_FAILED;
654                 }
655             }
656             gl_dst_ptr->loaded = TRUE;
657         }
658     
659         TRACE(" copying surface %p to surface %p (mipmap level %d)\n", src_ptr, dst_ptr, src_ptr->mipmap_level);
660
661         if ( dst_ptr->surface_desc.ddsCaps.dwCaps & DDSCAPS_ALLOCONLOAD )
662             /* If the surface is not allocated and its location is not yet specified,
663                force it to video memory */ 
664             if ( !(dst_ptr->surface_desc.ddsCaps.dwCaps & (DDSCAPS_SYSTEMMEMORY|DDSCAPS_VIDEOMEMORY)) )
665                 dst_ptr->surface_desc.ddsCaps.dwCaps |= DDSCAPS_VIDEOMEMORY;
666
667         /* Suppress the ALLOCONLOAD flag */
668         dst_ptr->surface_desc.ddsCaps.dwCaps &= ~DDSCAPS_ALLOCONLOAD;
669     
670         /* After seeing some logs, not sure at all about this... */
671         if (dst_ptr->palette == NULL) {
672             dst_ptr->palette = src_ptr->palette;
673             if (src_ptr->palette != NULL) IDirectDrawPalette_AddRef(ICOM_INTERFACE(src_ptr->palette, IDirectDrawPalette));
674         } else {
675             if (src_ptr->palette != NULL) {
676                 PALETTEENTRY palent[256];
677                 IDirectDrawPalette_GetEntries(ICOM_INTERFACE(src_ptr->palette, IDirectDrawPalette),
678                                               0, 0, 256, palent);
679                 IDirectDrawPalette_SetEntries(ICOM_INTERFACE(dst_ptr->palette, IDirectDrawPalette),
680                                               0, 0, 256, palent);
681             }
682         }
683         
684         /* Copy one surface on the other */
685         dst_d = (DDSURFACEDESC *)&(dst_ptr->surface_desc);
686         src_d = (DDSURFACEDESC *)&(src_ptr->surface_desc);
687
688         if ((src_d->dwWidth != dst_d->dwWidth) || (src_d->dwHeight != dst_d->dwHeight)) {
689             /* Should also check for same pixel format, u1.lPitch, ... */
690             ERR("Error in surface sizes\n");
691             return D3DERR_TEXTURE_LOAD_FAILED;
692         } else {
693             /* LPDIRECT3DDEVICE2 d3dd = (LPDIRECT3DDEVICE2) This->D3Ddevice; */
694             /* I should put a macro for the calculus of bpp */
695           
696             /* Copy also the ColorKeying stuff */
697             if (src_d->dwFlags & DDSD_CKSRCBLT) {
698                 dst_d->dwFlags |= DDSD_CKSRCBLT;
699                 dst_d->ddckCKSrcBlt.dwColorSpaceLowValue = src_d->ddckCKSrcBlt.dwColorSpaceLowValue;
700                 dst_d->ddckCKSrcBlt.dwColorSpaceHighValue = src_d->ddckCKSrcBlt.dwColorSpaceHighValue;
701             }
702
703             /* Copy the main memory texture into the surface that corresponds to the OpenGL
704                texture object. */
705             if (dst_ptr->surface_desc.u4.ddpfPixelFormat.dwFlags & DDPF_FOURCC)
706                 memcpy(dst_d->lpSurface, src_d->lpSurface, src_ptr->surface_desc.u1.dwLinearSize);
707             else
708                 memcpy(dst_d->lpSurface, src_d->lpSurface, src_d->u1.lPitch * src_d->dwHeight);
709
710             if (gl_dst_ptr != NULL) {
711                 /* Set this texture as dirty */
712                 gl_dst_ptr->dirty_flag = SURFACE_MEMORY_DIRTY;
713                 *(gl_dst_ptr->global_dirty_flag) = SURFACE_MEMORY_DIRTY;
714             }
715         }
716
717         if (src_ptr->surface_desc.ddsCaps.dwCaps & DDSCAPS_MIPMAP) {
718             src_ptr = get_sub_mimaplevel(src_ptr);
719         } else {
720             src_ptr = NULL;
721         }
722         if (dst_ptr->surface_desc.ddsCaps.dwCaps & DDSCAPS_MIPMAP) {
723             dst_ptr = get_sub_mimaplevel(dst_ptr);
724         } else {
725             dst_ptr = NULL;
726         }
727
728         if ((src_ptr == NULL) || (dst_ptr == NULL)) {
729             if (src_ptr != dst_ptr) {
730                 ERR(" Loading surface with different mipmap structure !!!\n");
731             }
732             break;
733         }
734     }
735
736     return ret_value;
737 }
738
739 HRESULT WINAPI
740 Thunk_IDirect3DTextureImpl_2_QueryInterface(LPDIRECT3DTEXTURE2 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, IDirect3DTexture2, IDirectDrawSurface7, iface),
746                                               riid,
747                                               obp);
748 }
749
750 ULONG WINAPI
751 Thunk_IDirect3DTextureImpl_2_AddRef(LPDIRECT3DTEXTURE2 iface)
752 {
753     TRACE("(%p)->() thunking to IDirectDrawSurface7 interface.\n", iface);
754     return IDirectDrawSurface7_AddRef(COM_INTERFACE_CAST(IDirectDrawSurfaceImpl, IDirect3DTexture2, IDirectDrawSurface7, iface));
755 }
756
757 ULONG WINAPI
758 Thunk_IDirect3DTextureImpl_2_Release(LPDIRECT3DTEXTURE2 iface)
759 {
760     TRACE("(%p)->() thunking to IDirectDrawSurface7 interface.\n", iface);
761     return IDirectDrawSurface7_Release(COM_INTERFACE_CAST(IDirectDrawSurfaceImpl, IDirect3DTexture2, IDirectDrawSurface7, iface));
762 }
763
764 HRESULT WINAPI
765 Thunk_IDirect3DTextureImpl_1_QueryInterface(LPDIRECT3DTEXTURE iface,
766                                             REFIID riid,
767                                             LPVOID* obp)
768 {
769     TRACE("(%p)->(%s,%p) thunking to IDirectDrawSurface7 interface.\n", iface, debugstr_guid(riid), obp);
770     return IDirectDrawSurface7_QueryInterface(COM_INTERFACE_CAST(IDirectDrawSurfaceImpl, IDirect3DTexture, IDirectDrawSurface7, iface),
771                                               riid,
772                                               obp);
773 }
774
775 ULONG WINAPI
776 Thunk_IDirect3DTextureImpl_1_AddRef(LPDIRECT3DTEXTURE iface)
777 {
778     TRACE("(%p)->() thunking to IDirectDrawSurface7 interface.\n", iface);
779     return IDirectDrawSurface7_AddRef(COM_INTERFACE_CAST(IDirectDrawSurfaceImpl, IDirect3DTexture, IDirectDrawSurface7, iface));
780 }
781
782 ULONG WINAPI
783 Thunk_IDirect3DTextureImpl_1_Release(LPDIRECT3DTEXTURE iface)
784 {
785     TRACE("(%p)->() thunking to IDirectDrawSurface7 interface.\n", iface);
786     return IDirectDrawSurface7_Release(COM_INTERFACE_CAST(IDirectDrawSurfaceImpl, IDirect3DTexture, IDirectDrawSurface7, iface));
787 }
788
789 HRESULT WINAPI
790 Thunk_IDirect3DTextureImpl_1_PaletteChanged(LPDIRECT3DTEXTURE iface,
791                                             DWORD dwStart,
792                                             DWORD dwCount)
793 {
794     TRACE("(%p)->(%08lx,%08lx) thunking to IDirect3DTexture2 interface.\n", iface, dwStart, dwCount);
795     return IDirect3DTexture2_PaletteChanged(COM_INTERFACE_CAST(IDirectDrawSurfaceImpl, IDirect3DTexture, IDirect3DTexture2, iface),
796                                             dwStart,
797                                             dwCount);
798 }
799
800 HRESULT WINAPI
801 Thunk_IDirect3DTextureImpl_1_GetHandle(LPDIRECT3DTEXTURE iface,
802                                        LPDIRECT3DDEVICE lpDirect3DDevice,
803                                        LPD3DTEXTUREHANDLE lpHandle)
804 {
805     TRACE("(%p)->(%p,%p) thunking to IDirect3DTexture2 interface.\n", iface, lpDirect3DDevice, lpHandle);
806     return IDirect3DTexture2_GetHandle(COM_INTERFACE_CAST(IDirectDrawSurfaceImpl, IDirect3DTexture, IDirect3DTexture2, iface),
807                                        COM_INTERFACE_CAST(IDirect3DDeviceImpl, IDirect3DDevice, IDirect3DDevice2, lpDirect3DDevice),
808                                        lpHandle);
809 }
810
811 HRESULT WINAPI
812 Thunk_IDirect3DTextureImpl_1_Load(LPDIRECT3DTEXTURE iface,
813                                   LPDIRECT3DTEXTURE lpD3DTexture)
814 {
815     TRACE("(%p)->(%p) thunking to IDirect3DTexture2 interface.\n", iface, lpD3DTexture);
816     return IDirect3DTexture2_Load(COM_INTERFACE_CAST(IDirectDrawSurfaceImpl, IDirect3DTexture, IDirect3DTexture2, iface),
817                                   COM_INTERFACE_CAST(IDirectDrawSurfaceImpl, IDirect3DTexture, IDirect3DTexture2, lpD3DTexture));
818 }
819
820 #if !defined(__STRICT_ANSI__) && defined(__GNUC__)
821 # define XCAST(fun)     (typeof(VTABLE_IDirect3DTexture2.fun))
822 #else
823 # define XCAST(fun)     (void*)
824 #endif
825
826 IDirect3DTexture2Vtbl VTABLE_IDirect3DTexture2 =
827 {
828     XCAST(QueryInterface) Thunk_IDirect3DTextureImpl_2_QueryInterface,
829     XCAST(AddRef) Thunk_IDirect3DTextureImpl_2_AddRef,
830     XCAST(Release) Thunk_IDirect3DTextureImpl_2_Release,
831     XCAST(GetHandle) Main_IDirect3DTextureImpl_2_1T_GetHandle,
832     XCAST(PaletteChanged) Main_IDirect3DTextureImpl_2_1T_PaletteChanged,
833     XCAST(Load) GL_IDirect3DTextureImpl_2_1T_Load,
834 };
835
836 #if !defined(__STRICT_ANSI__) && defined(__GNUC__)
837 #undef XCAST
838 #endif
839
840
841 #if !defined(__STRICT_ANSI__) && defined(__GNUC__)
842 # define XCAST(fun)     (typeof(VTABLE_IDirect3DTexture.fun))
843 #else
844 # define XCAST(fun)     (void*)
845 #endif
846
847 IDirect3DTextureVtbl VTABLE_IDirect3DTexture =
848 {
849     XCAST(QueryInterface) Thunk_IDirect3DTextureImpl_1_QueryInterface,
850     XCAST(AddRef) Thunk_IDirect3DTextureImpl_1_AddRef,
851     XCAST(Release) Thunk_IDirect3DTextureImpl_1_Release,
852     XCAST(Initialize) Main_IDirect3DTextureImpl_1_Initialize,
853     XCAST(GetHandle) Thunk_IDirect3DTextureImpl_1_GetHandle,
854     XCAST(PaletteChanged) Thunk_IDirect3DTextureImpl_1_PaletteChanged,
855     XCAST(Load) Thunk_IDirect3DTextureImpl_1_Load,
856     XCAST(Unload) Main_IDirect3DTextureImpl_1_Unload,
857 };
858
859 #if !defined(__STRICT_ANSI__) && defined(__GNUC__)
860 #undef XCAST
861 #endif
862
863 HRESULT d3dtexture_create(IDirectDrawImpl *d3d, IDirectDrawSurfaceImpl *surf, BOOLEAN at_creation, 
864                           IDirectDrawSurfaceImpl *main)
865 {
866     /* First, initialize the texture vtables... */
867     ICOM_INIT_INTERFACE(surf, IDirect3DTexture,  VTABLE_IDirect3DTexture);
868     ICOM_INIT_INTERFACE(surf, IDirect3DTexture2, VTABLE_IDirect3DTexture2);
869         
870     /* Only create all the private stuff if we actually have an OpenGL context.. */
871     if (d3d->current_device != NULL) {
872         IDirect3DTextureGLImpl *private;
873
874         private = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IDirect3DTextureGLImpl));
875         if (private == NULL) return DDERR_OUTOFMEMORY;
876
877         surf->tex_private = private;
878         
879         private->final_release = surf->final_release;
880         private->lock_update = surf->lock_update;
881         private->unlock_update = surf->unlock_update;
882         private->set_palette = surf->set_palette;
883         
884         /* If at creation, we can optimize stuff and wait the first 'unlock' to upload a valid stuff to OpenGL.
885            Otherwise, it will be uploaded here (and may be invalid). */
886         surf->final_release = gltex_final_release;
887         surf->lock_update = gltex_lock_update;
888         surf->unlock_update = gltex_unlock_update;
889         surf->aux_setcolorkey_cb = gltex_setcolorkey_cb;
890         surf->set_palette = gltex_set_palette;
891
892         /* We are the only one to use the aux_blt and aux_bltfast overrides, so no need
893            to save those... */
894         surf->aux_blt = gltex_blt;
895         surf->aux_bltfast = gltex_bltfast;
896         
897         TRACE(" GL texture created for surface %p (private data at %p)\n", surf, private);
898
899         /* Do not create the OpenGL texture id here as some game generate textures from a different thread which
900             cause problems.. */
901         private->tex_name = 0;
902         if (surf->mipmap_level == 0) {
903             private->main = NULL;
904             private->global_dirty_flag = &(private->__global_dirty_flag);
905         } else {
906             private->main = main;
907             private->global_dirty_flag = &(((IDirect3DTextureGLImpl *) (private->main->tex_private))->__global_dirty_flag);
908         }
909         private->initial_upload_done = FALSE;
910     }
911
912     return D3D_OK;
913 }
914
915 GLuint gltex_get_tex_name(IDirectDrawSurfaceImpl *surf)
916 {
917     IDirect3DTextureGLImpl *private = (IDirect3DTextureGLImpl *) (surf->tex_private);
918     
919     if (private->tex_name == 0) {
920         /* The texture was not created yet... */        
921         ENTER_GL();
922         if (surf->mipmap_level == 0) {
923             glGenTextures(1, &(private->tex_name));
924             if (private->tex_name == 0) ERR("Error at creation of OpenGL texture ID !\n");
925             TRACE(" GL texture id is : %d.\n", private->tex_name);
926             private->__global_dirty_flag = SURFACE_MEMORY_DIRTY;
927         } else {
928             private->tex_name = gltex_get_tex_name(private->main);
929             TRACE(" GL texture id reusing id %d from surface %p (private at %p)).\n", private->tex_name, private->main, private->main->tex_private);
930         }
931         LEAVE_GL();
932
933         /* And set the dirty flag accordingly */
934         private->dirty_flag = SURFACE_MEMORY_DIRTY;
935     }
936     return ((IDirect3DTextureGLImpl *) (surf->tex_private))->tex_name;
937 }