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