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