2 * Copyright (c) 1998 Lionel ULMER
4 * This file contains the implementation of interface Direct3DTexture2.
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.
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.
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
26 #define NONAMELESSUNION
27 #define NONAMELESSSTRUCT
35 #include "wine/debug.h"
37 #include "mesa_private.h"
39 WINE_DEFAULT_DEBUG_CHANNEL(ddraw
);
40 WINE_DECLARE_DEBUG_CHANNEL(ddraw_tex
);
45 snoop_texture(IDirectDrawSurfaceImpl
*This
) {
46 IDirect3DTextureGLImpl
*glThis
= (IDirect3DTextureGLImpl
*) This
->tex_private
;
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
));
53 sprintf(buf
, "tex_%05d_%02d.pnm", glThis
->tex_name
, This
->mipmap_level
);
55 DDRAW_dump_surface_to_disk(This
, f
, 1);
58 static IDirectDrawSurfaceImpl
*
59 get_sub_mimaplevel(IDirectDrawSurfaceImpl
*tex_ptr
)
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
;
67 hr
= IDirectDrawSurface7_GetAttachedSurface(ICOM_INTERFACE(tex_ptr
, IDirectDrawSurface7
),
68 (DDSCAPS2
*) &mipmap_caps
, &next_level
);
69 if (FAILED(hr
)) return NULL
;
71 surf_ptr
= ICOM_OBJECT(IDirectDrawSurfaceImpl
, IDirectDrawSurface7
, next_level
);
72 IDirectDrawSurface7_Release(next_level
);
77 /*******************************************************************************
78 * IDirectSurface callback methods
82 gltex_download_texture(IDirectDrawSurfaceImpl
*surf_ptr
) {
83 IDirect3DTextureGLImpl
*gl_surf_ptr
= (IDirect3DTextureGLImpl
*) surf_ptr
->tex_private
;
85 FIXME("This is not supported yet... Expect some graphical glitches !!!\n");
87 /* GL and memory are in sync again ...
88 No need to change the 'global' flag as it only handles the 'MEMORY_DIRTY' case.
90 gl_surf_ptr
->dirty_flag
= SURFACE_MEMORY
;
96 convert_min_filter_to_GL(D3DTEXTUREMINFILTER dwMinState
, D3DTEXTUREMIPFILTER dwMipState
)
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;
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;
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;
123 convert_mag_filter_to_GL(D3DTEXTUREMAGFILTER dwState
)
129 gl_state
= GL_NEAREST
;
132 gl_state
= GL_LINEAR
;
135 gl_state
= GL_LINEAR
;
142 convert_tex_address_to_GL(D3DTEXTUREADDRESS 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
;
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.
157 TRACE(" setting GL_REPEAT instead of GL_MIRRORED_REPEAT.\n");
160 default: gl_state
= GL_REPEAT
; break;
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
;
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
);
176 /* Now check if the texture parameters for this texture are still in-line with what D3D expect
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.
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])) {
187 if ((surf_ptr
->surface_desc
.ddsCaps
.dwCaps
& DDSCAPS_MIPMAP
) == 0) {
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;
197 if (unit
!= gl_d3ddev
->current_active_tex_unit
) {
198 GL_extensions
.glActiveTexture(unit
);
199 gl_d3ddev
->current_active_tex_unit
= unit
;
201 glTexParameteri(GL_TEXTURE_2D
, GL_TEXTURE_MAX_LEVEL
, max_mip_level
);
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
;
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]));
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
;
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]));
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
;
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]));
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
;
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]));
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])) {
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
;
265 glTexParameterfv(GL_TEXTURE_2D
, GL_TEXTURE_BORDER_COLOR
, color
);
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
));
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
));
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");
283 while (surf_ptr
!= NULL
) {
284 IDirect3DTextureGLImpl
*gl_surf_ptr
= (IDirect3DTextureGLImpl
*) surf_ptr
->tex_private
;
286 if (gl_surf_ptr
->dirty_flag
!= SURFACE_MEMORY_DIRTY
) {
287 TRACE(" - level %d already uploaded.\n", surf_ptr
->mipmap_level
);
289 TRACE(" - uploading texture level %d (initial done = %d).\n",
290 surf_ptr
->mipmap_level
, gl_surf_ptr
->initial_upload_done
);
292 /* Texture snooping for the curious :-) */
293 if (TRACE_ON(ddraw_tex
)) {
294 snoop_texture(surf_ptr
);
297 if (unit
!= gl_d3ddev
->current_active_tex_unit
) {
298 GL_extensions
.glActiveTexture(unit
);
299 gl_d3ddev
->current_active_tex_unit
= unit
;
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
;
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
);
314 if (surf_ptr
->surface_desc
.ddsCaps
.dwCaps
& DDSCAPS_MIPMAP
) {
315 surf_ptr
= get_sub_mimaplevel(surf_ptr
);
321 *(gl_surf_ptr
->global_dirty_flag
) = SURFACE_MEMORY
;
327 Main_IDirect3DTextureImpl_1_Initialize(LPDIRECT3DTEXTURE iface
,
328 LPDIRECT3DDEVICE lpDirect3DDevice
,
329 LPDIRECTDRAWSURFACE lpDDSurface
)
331 ICOM_THIS_FROM(IDirectDrawSurfaceImpl
, IDirect3DTexture
, iface
);
332 FIXME("(%p/%p)->(%p,%p) no-op...\n", This
, iface
, lpDirect3DDevice
, lpDDSurface
);
337 gltex_setcolorkey_cb(IDirectDrawSurfaceImpl
*This
, DWORD dwFlags
, LPDDCOLORKEY ckey
)
339 IDirect3DTextureGLImpl
*glThis
= (IDirect3DTextureGLImpl
*) This
->tex_private
;
341 if (glThis
->dirty_flag
== SURFACE_GL
) {
344 TRACE(" flushing GL texture back to memory.\n");
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
);
354 glThis
->dirty_flag
= SURFACE_MEMORY_DIRTY
;
355 *(glThis
->global_dirty_flag
) = SURFACE_MEMORY_DIRTY
;
356 /* TODO: check color-keying on mipmapped surfaces... */
362 gltex_blt(IDirectDrawSurfaceImpl
*This
, LPRECT rdst
,
363 LPDIRECTDRAWSURFACE7 src
, LPRECT rsrc
,
364 DWORD dwFlags
, LPDDBLTFX lpbltfx
)
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");
372 return DDERR_INVALIDPARAMS
;
376 gltex_bltfast(IDirectDrawSurfaceImpl
*surf_ptr
, DWORD dstx
,
377 DWORD dsty
, LPDIRECTDRAWSURFACE7 src
,
378 LPRECT rsrc
, DWORD trans
)
381 IDirectDrawSurfaceImpl
*src_ptr
= ICOM_OBJECT(IDirectDrawSurfaceImpl
, IDirectDrawSurface7
, src
);
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. */
389 IDirect3DTextureGLImpl
*gl_surf_ptr
= surf_ptr
->tex_private
;
393 WARN("rsrc is NULL\n");
398 rsrc
->right
= src_ptr
->surface_desc
.dwWidth
;
399 rsrc
->bottom
= src_ptr
->surface_desc
.dwHeight
;
402 width
= rsrc
->right
- rsrc
->left
;
403 height
= rsrc
->bottom
- rsrc
->top
;
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
;
411 if ((width
== 0) || (height
== 0)) {
415 TRACE(" direct frame buffer => texture BltFast override.\n");
419 glGetIntegerv(GL_TEXTURE_BINDING_2D
, &cur_tex
);
420 glBindTexture(GL_TEXTURE_2D
, gl_surf_ptr
->tex_name
);
422 if ((gl_surf_ptr
->dirty_flag
== SURFACE_MEMORY_DIRTY
) &&
423 !((dstx
== 0) && (dsty
== 0) &&
424 (width
== surf_ptr
->surface_desc
.dwWidth
) && (height
== surf_ptr
->surface_desc
.dwHeight
))) {
425 /* If not 'full size' and the surface is dirty, first flush it to GL before doing the copy. */
426 if (upload_surface_to_tex_memory_init(surf_ptr
, surf_ptr
->mipmap_level
, &(gl_surf_ptr
->current_internal_format
),
427 gl_surf_ptr
->initial_upload_done
== FALSE
, TRUE
, 0, 0) == DD_OK
) {
428 upload_surface_to_tex_memory(NULL
, 0, 0, &(gl_surf_ptr
->surface_ptr
));
429 upload_surface_to_tex_memory_release();
430 gl_surf_ptr
->dirty_flag
= SURFACE_MEMORY
;
431 gl_surf_ptr
->initial_upload_done
= TRUE
;
433 glBindTexture(GL_TEXTURE_2D
, cur_tex
);
435 ERR("Error at texture upload !\n");
436 return DDERR_INVALIDPARAMS
;
440 /* This is a hack and would need some clean-up :-) */
441 if (gl_surf_ptr
->initial_upload_done
== FALSE
) {
442 if (upload_surface_to_tex_memory_init(surf_ptr
, surf_ptr
->mipmap_level
, &(gl_surf_ptr
->current_internal_format
),
443 TRUE
, TRUE
, 0, 0) == DD_OK
) {
444 upload_surface_to_tex_memory(NULL
, 0, 0, &(gl_surf_ptr
->surface_ptr
));
445 upload_surface_to_tex_memory_release();
446 gl_surf_ptr
->dirty_flag
= SURFACE_MEMORY
;
447 gl_surf_ptr
->initial_upload_done
= TRUE
;
449 glBindTexture(GL_TEXTURE_2D
, cur_tex
);
451 ERR("Error at texture upload (initial case) !\n");
452 return DDERR_INVALIDPARAMS
;
456 if ((src_ptr
->surface_desc
.ddsCaps
.dwCaps
& (DDSCAPS_FRONTBUFFER
|DDSCAPS_PRIMARYSURFACE
)) != 0)
457 glReadBuffer(GL_FRONT
);
458 else if ((src_ptr
->surface_desc
.ddsCaps
.dwCaps
& (DDSCAPS_BACKBUFFER
)) == (DDSCAPS_BACKBUFFER
))
459 glReadBuffer(GL_BACK
);
461 ERR("Wrong surface type for locking !\n");
462 glBindTexture(GL_TEXTURE_2D
, cur_tex
);
464 return DDERR_INVALIDPARAMS
;
467 for (y
= (src_ptr
->surface_desc
.dwHeight
- rsrc
->top
- 1);
468 y
>= (src_ptr
->surface_desc
.dwHeight
- (rsrc
->top
+ height
));
470 glCopyTexSubImage2D(GL_TEXTURE_2D
, surf_ptr
->mipmap_level
,
477 glBindTexture(GL_TEXTURE_2D
, cur_tex
);
480 /* The SURFACE_GL case is not handled by the 'global' dirty flag */
481 gl_surf_ptr
->dirty_flag
= SURFACE_GL
;
486 return DDERR_INVALIDPARAMS
;
490 Main_IDirect3DTextureImpl_2_1T_PaletteChanged(LPDIRECT3DTEXTURE2 iface
,
494 ICOM_THIS_FROM(IDirectDrawSurfaceImpl
, IDirect3DTexture2
, iface
);
495 FIXME("(%p/%p)->(%08lx,%08lx): stub!\n", This
, iface
, dwStart
, dwCount
);
500 Main_IDirect3DTextureImpl_1_Unload(LPDIRECT3DTEXTURE iface
)
502 ICOM_THIS_FROM(IDirectDrawSurfaceImpl
, IDirect3DTexture
, iface
);
503 FIXME("(%p/%p)->(): stub!\n", This
, iface
);
508 Main_IDirect3DTextureImpl_2_1T_GetHandle(LPDIRECT3DTEXTURE2 iface
,
509 LPDIRECT3DDEVICE2 lpDirect3DDevice2
,
510 LPD3DTEXTUREHANDLE lpHandle
)
512 ICOM_THIS_FROM(IDirectDrawSurfaceImpl
, IDirect3DTexture2
, iface
);
513 IDirect3DDeviceImpl
*lpDeviceImpl
= ICOM_OBJECT(IDirect3DDeviceImpl
, IDirect3DDevice2
, lpDirect3DDevice2
);
515 TRACE("(%p/%p)->(%p,%p)\n", This
, iface
, lpDirect3DDevice2
, lpHandle
);
517 /* The handle is simply the pointer to the implementation structure */
518 *lpHandle
= (D3DTEXTUREHANDLE
) This
;
520 TRACE(" returning handle %08lx.\n", *lpHandle
);
522 /* Now set the device for this texture */
523 This
->d3ddevice
= lpDeviceImpl
;
529 Main_IDirect3DTextureImpl_2_1T_Load(LPDIRECT3DTEXTURE2 iface
,
530 LPDIRECT3DTEXTURE2 lpD3DTexture2
)
532 ICOM_THIS_FROM(IDirectDrawSurfaceImpl
, IDirect3DTexture2
, iface
);
533 FIXME("(%p/%p)->(%p): stub!\n", This
, iface
, lpD3DTexture2
);
537 static void gltex_set_palette(IDirectDrawSurfaceImpl
* This
, IDirectDrawPaletteImpl
* pal
)
539 IDirect3DTextureGLImpl
*glThis
= (IDirect3DTextureGLImpl
*) This
->tex_private
;
541 if (glThis
->dirty_flag
== SURFACE_GL
) {
544 TRACE(" flushing GL texture back to memory.\n");
547 glGetIntegerv(GL_TEXTURE_BINDING_2D
, &cur_tex
);
548 glBindTexture(GL_TEXTURE_2D
, glThis
->tex_name
);
549 gltex_download_texture(This
);
550 glBindTexture(GL_TEXTURE_2D
, cur_tex
);
554 /* First call the previous set_palette function */
555 glThis
->set_palette(This
, pal
);
557 /* And set the dirty flag */
558 glThis
->dirty_flag
= SURFACE_MEMORY_DIRTY
;
559 *(glThis
->global_dirty_flag
) = SURFACE_MEMORY_DIRTY
;
561 /* TODO: check palette on mipmapped surfaces...
562 TODO: do we need to re-upload in case of usage of the paletted texture extension ? */
566 gltex_final_release(IDirectDrawSurfaceImpl
*This
)
568 IDirect3DTextureGLImpl
*glThis
= (IDirect3DTextureGLImpl
*) This
->tex_private
;
572 TRACE(" deleting texture with GL id %d.\n", glThis
->tex_name
);
574 /* And delete texture handle */
576 if (glThis
->tex_name
!= 0)
577 glDeleteTextures(1, &(glThis
->tex_name
));
580 HeapFree(GetProcessHeap(), 0, glThis
->surface_ptr
);
582 /* And if this texture was the current one, remove it at the device level */
583 if (This
->d3ddevice
!= NULL
)
584 for (i
= 0; i
< MAX_TEXTURES
; i
++)
585 if (This
->d3ddevice
->current_texture
[i
] == This
)
586 This
->d3ddevice
->current_texture
[i
] = NULL
;
588 /* All this should be part of main surface management not just a hack for texture.. */
589 if (glThis
->loaded
) {
590 mem_used
= This
->surface_desc
.dwHeight
*
591 This
->surface_desc
.u1
.lPitch
;
592 This
->ddraw_owner
->free_memory(This
->ddraw_owner
, mem_used
);
595 glThis
->final_release(This
);
599 gltex_lock_update(IDirectDrawSurfaceImpl
* This
, LPCRECT pRect
, DWORD dwFlags
)
601 IDirect3DTextureGLImpl
*glThis
= (IDirect3DTextureGLImpl
*) This
->tex_private
;
603 glThis
->lock_update(This
, pRect
, dwFlags
);
607 gltex_unlock_update(IDirectDrawSurfaceImpl
* This
, LPCRECT pRect
)
609 IDirect3DTextureGLImpl
*glThis
= (IDirect3DTextureGLImpl
*) This
->tex_private
;
611 glThis
->unlock_update(This
, pRect
);
613 /* Set the dirty flag according to the lock type */
614 if ((This
->lastlocktype
& DDLOCK_READONLY
) == 0) {
615 glThis
->dirty_flag
= SURFACE_MEMORY_DIRTY
;
616 *(glThis
->global_dirty_flag
) = SURFACE_MEMORY_DIRTY
;
621 GL_IDirect3DTextureImpl_2_1T_Load(LPDIRECT3DTEXTURE2 iface
,
622 LPDIRECT3DTEXTURE2 lpD3DTexture2
)
624 ICOM_THIS_FROM(IDirectDrawSurfaceImpl
, IDirect3DTexture2
, iface
);
625 IDirectDrawSurfaceImpl
*src_ptr
= ICOM_OBJECT(IDirectDrawSurfaceImpl
, IDirect3DTexture2
, lpD3DTexture2
);
626 IDirectDrawSurfaceImpl
*dst_ptr
= This
;
627 HRESULT ret_value
= D3D_OK
;
629 TRACE("(%p/%p)->(%p)\n", This
, iface
, lpD3DTexture2
);
631 if (((src_ptr
->surface_desc
.ddsCaps
.dwCaps
& DDSCAPS_MIPMAP
) != (dst_ptr
->surface_desc
.ddsCaps
.dwCaps
& DDSCAPS_MIPMAP
)) ||
632 (src_ptr
->surface_desc
.u2
.dwMipMapCount
!= dst_ptr
->surface_desc
.u2
.dwMipMapCount
)) {
633 ERR("Trying to load surfaces with different mip-map counts !\n");
636 /* Now loop through all mipmap levels and load all of them... */
638 IDirect3DTextureGLImpl
*gl_dst_ptr
= (IDirect3DTextureGLImpl
*) dst_ptr
->tex_private
;
639 DDSURFACEDESC
*src_d
, *dst_d
;
641 if (gl_dst_ptr
!= NULL
) {
642 if (gl_dst_ptr
->loaded
== FALSE
) {
643 /* Only check memory for not already loaded texture... */
645 if (dst_ptr
->surface_desc
.u4
.ddpfPixelFormat
.dwFlags
& DDPF_FOURCC
)
646 mem_used
= dst_ptr
->surface_desc
.u1
.dwLinearSize
;
648 mem_used
= dst_ptr
->surface_desc
.dwHeight
* dst_ptr
->surface_desc
.u1
.lPitch
;
649 if (This
->ddraw_owner
->allocate_memory(This
->ddraw_owner
, mem_used
) < 0) {
650 TRACE(" out of virtual memory... Warning application.\n");
651 return D3DERR_TEXTURE_LOAD_FAILED
;
654 gl_dst_ptr
->loaded
= TRUE
;
657 TRACE(" copying surface %p to surface %p (mipmap level %d)\n", src_ptr
, dst_ptr
, src_ptr
->mipmap_level
);
659 if ( dst_ptr
->surface_desc
.ddsCaps
.dwCaps
& DDSCAPS_ALLOCONLOAD
)
660 /* If the surface is not allocated and its location is not yet specified,
661 force it to video memory */
662 if ( !(dst_ptr
->surface_desc
.ddsCaps
.dwCaps
& (DDSCAPS_SYSTEMMEMORY
|DDSCAPS_VIDEOMEMORY
)) )
663 dst_ptr
->surface_desc
.ddsCaps
.dwCaps
|= DDSCAPS_VIDEOMEMORY
;
665 /* Suppress the ALLOCONLOAD flag */
666 dst_ptr
->surface_desc
.ddsCaps
.dwCaps
&= ~DDSCAPS_ALLOCONLOAD
;
668 /* After seeing some logs, not sure at all about this... */
669 if (dst_ptr
->palette
== NULL
) {
670 dst_ptr
->palette
= src_ptr
->palette
;
671 if (src_ptr
->palette
!= NULL
) IDirectDrawPalette_AddRef(ICOM_INTERFACE(src_ptr
->palette
, IDirectDrawPalette
));
673 if (src_ptr
->palette
!= NULL
) {
674 PALETTEENTRY palent
[256];
675 IDirectDrawPalette_GetEntries(ICOM_INTERFACE(src_ptr
->palette
, IDirectDrawPalette
),
677 IDirectDrawPalette_SetEntries(ICOM_INTERFACE(dst_ptr
->palette
, IDirectDrawPalette
),
682 /* Copy one surface on the other */
683 dst_d
= (DDSURFACEDESC
*)&(dst_ptr
->surface_desc
);
684 src_d
= (DDSURFACEDESC
*)&(src_ptr
->surface_desc
);
686 if ((src_d
->dwWidth
!= dst_d
->dwWidth
) || (src_d
->dwHeight
!= dst_d
->dwHeight
)) {
687 /* Should also check for same pixel format, u1.lPitch, ... */
688 ERR("Error in surface sizes\n");
689 return D3DERR_TEXTURE_LOAD_FAILED
;
691 /* LPDIRECT3DDEVICE2 d3dd = (LPDIRECT3DDEVICE2) This->D3Ddevice; */
692 /* I should put a macro for the calculus of bpp */
694 /* Copy also the ColorKeying stuff */
695 if (src_d
->dwFlags
& DDSD_CKSRCBLT
) {
696 dst_d
->dwFlags
|= DDSD_CKSRCBLT
;
697 dst_d
->ddckCKSrcBlt
.dwColorSpaceLowValue
= src_d
->ddckCKSrcBlt
.dwColorSpaceLowValue
;
698 dst_d
->ddckCKSrcBlt
.dwColorSpaceHighValue
= src_d
->ddckCKSrcBlt
.dwColorSpaceHighValue
;
701 /* Copy the main memory texture into the surface that corresponds to the OpenGL
703 if (dst_ptr
->surface_desc
.u4
.ddpfPixelFormat
.dwFlags
& DDPF_FOURCC
)
704 memcpy(dst_d
->lpSurface
, src_d
->lpSurface
, src_ptr
->surface_desc
.u1
.dwLinearSize
);
706 memcpy(dst_d
->lpSurface
, src_d
->lpSurface
, src_d
->u1
.lPitch
* src_d
->dwHeight
);
708 if (gl_dst_ptr
!= NULL
) {
709 /* If the GetHandle was not done, it is an error... */
710 if (gl_dst_ptr
->tex_name
== 0) ERR("Unbound GL texture !!!\n");
712 /* Set this texture as dirty */
713 gl_dst_ptr
->dirty_flag
= SURFACE_MEMORY_DIRTY
;
714 *(gl_dst_ptr
->global_dirty_flag
) = SURFACE_MEMORY_DIRTY
;
718 if (src_ptr
->surface_desc
.ddsCaps
.dwCaps
& DDSCAPS_MIPMAP
) {
719 src_ptr
= get_sub_mimaplevel(src_ptr
);
723 if (dst_ptr
->surface_desc
.ddsCaps
.dwCaps
& DDSCAPS_MIPMAP
) {
724 dst_ptr
= get_sub_mimaplevel(dst_ptr
);
729 if ((src_ptr
== NULL
) || (dst_ptr
== NULL
)) {
730 if (src_ptr
!= dst_ptr
) {
731 ERR(" Loading surface with different mipmap structure !!!\n");
741 Thunk_IDirect3DTextureImpl_2_QueryInterface(LPDIRECT3DTEXTURE2 iface
,
745 TRACE("(%p)->(%s,%p) thunking to IDirectDrawSurface7 interface.\n", iface
, debugstr_guid(riid
), obp
);
746 return IDirectDrawSurface7_QueryInterface(COM_INTERFACE_CAST(IDirectDrawSurfaceImpl
, IDirect3DTexture2
, IDirectDrawSurface7
, iface
),
752 Thunk_IDirect3DTextureImpl_2_AddRef(LPDIRECT3DTEXTURE2 iface
)
754 TRACE("(%p)->() thunking to IDirectDrawSurface7 interface.\n", iface
);
755 return IDirectDrawSurface7_AddRef(COM_INTERFACE_CAST(IDirectDrawSurfaceImpl
, IDirect3DTexture2
, IDirectDrawSurface7
, iface
));
759 Thunk_IDirect3DTextureImpl_2_Release(LPDIRECT3DTEXTURE2 iface
)
761 TRACE("(%p)->() thunking to IDirectDrawSurface7 interface.\n", iface
);
762 return IDirectDrawSurface7_Release(COM_INTERFACE_CAST(IDirectDrawSurfaceImpl
, IDirect3DTexture2
, IDirectDrawSurface7
, iface
));
766 Thunk_IDirect3DTextureImpl_1_QueryInterface(LPDIRECT3DTEXTURE iface
,
770 TRACE("(%p)->(%s,%p) thunking to IDirectDrawSurface7 interface.\n", iface
, debugstr_guid(riid
), obp
);
771 return IDirectDrawSurface7_QueryInterface(COM_INTERFACE_CAST(IDirectDrawSurfaceImpl
, IDirect3DTexture
, IDirectDrawSurface7
, iface
),
777 Thunk_IDirect3DTextureImpl_1_AddRef(LPDIRECT3DTEXTURE iface
)
779 TRACE("(%p)->() thunking to IDirectDrawSurface7 interface.\n", iface
);
780 return IDirectDrawSurface7_AddRef(COM_INTERFACE_CAST(IDirectDrawSurfaceImpl
, IDirect3DTexture
, IDirectDrawSurface7
, iface
));
784 Thunk_IDirect3DTextureImpl_1_Release(LPDIRECT3DTEXTURE iface
)
786 TRACE("(%p)->() thunking to IDirectDrawSurface7 interface.\n", iface
);
787 return IDirectDrawSurface7_Release(COM_INTERFACE_CAST(IDirectDrawSurfaceImpl
, IDirect3DTexture
, IDirectDrawSurface7
, iface
));
791 Thunk_IDirect3DTextureImpl_1_PaletteChanged(LPDIRECT3DTEXTURE iface
,
795 TRACE("(%p)->(%08lx,%08lx) thunking to IDirect3DTexture2 interface.\n", iface
, dwStart
, dwCount
);
796 return IDirect3DTexture2_PaletteChanged(COM_INTERFACE_CAST(IDirectDrawSurfaceImpl
, IDirect3DTexture
, IDirect3DTexture2
, iface
),
802 Thunk_IDirect3DTextureImpl_1_GetHandle(LPDIRECT3DTEXTURE iface
,
803 LPDIRECT3DDEVICE lpDirect3DDevice
,
804 LPD3DTEXTUREHANDLE lpHandle
)
806 TRACE("(%p)->(%p,%p) thunking to IDirect3DTexture2 interface.\n", iface
, lpDirect3DDevice
, lpHandle
);
807 return IDirect3DTexture2_GetHandle(COM_INTERFACE_CAST(IDirectDrawSurfaceImpl
, IDirect3DTexture
, IDirect3DTexture2
, iface
),
808 COM_INTERFACE_CAST(IDirect3DDeviceImpl
, IDirect3DDevice
, IDirect3DDevice2
, lpDirect3DDevice
),
813 Thunk_IDirect3DTextureImpl_1_Load(LPDIRECT3DTEXTURE iface
,
814 LPDIRECT3DTEXTURE lpD3DTexture
)
816 TRACE("(%p)->(%p) thunking to IDirect3DTexture2 interface.\n", iface
, lpD3DTexture
);
817 return IDirect3DTexture2_Load(COM_INTERFACE_CAST(IDirectDrawSurfaceImpl
, IDirect3DTexture
, IDirect3DTexture2
, iface
),
818 COM_INTERFACE_CAST(IDirectDrawSurfaceImpl
, IDirect3DTexture
, IDirect3DTexture2
, lpD3DTexture
));
821 #if !defined(__STRICT_ANSI__) && defined(__GNUC__)
822 # define XCAST(fun) (typeof(VTABLE_IDirect3DTexture2.fun))
824 # define XCAST(fun) (void*)
827 IDirect3DTexture2Vtbl VTABLE_IDirect3DTexture2
=
829 XCAST(QueryInterface
) Thunk_IDirect3DTextureImpl_2_QueryInterface
,
830 XCAST(AddRef
) Thunk_IDirect3DTextureImpl_2_AddRef
,
831 XCAST(Release
) Thunk_IDirect3DTextureImpl_2_Release
,
832 XCAST(GetHandle
) Main_IDirect3DTextureImpl_2_1T_GetHandle
,
833 XCAST(PaletteChanged
) Main_IDirect3DTextureImpl_2_1T_PaletteChanged
,
834 XCAST(Load
) GL_IDirect3DTextureImpl_2_1T_Load
,
837 #if !defined(__STRICT_ANSI__) && defined(__GNUC__)
842 #if !defined(__STRICT_ANSI__) && defined(__GNUC__)
843 # define XCAST(fun) (typeof(VTABLE_IDirect3DTexture.fun))
845 # define XCAST(fun) (void*)
848 IDirect3DTextureVtbl VTABLE_IDirect3DTexture
=
850 XCAST(QueryInterface
) Thunk_IDirect3DTextureImpl_1_QueryInterface
,
851 XCAST(AddRef
) Thunk_IDirect3DTextureImpl_1_AddRef
,
852 XCAST(Release
) Thunk_IDirect3DTextureImpl_1_Release
,
853 XCAST(Initialize
) Main_IDirect3DTextureImpl_1_Initialize
,
854 XCAST(GetHandle
) Thunk_IDirect3DTextureImpl_1_GetHandle
,
855 XCAST(PaletteChanged
) Thunk_IDirect3DTextureImpl_1_PaletteChanged
,
856 XCAST(Load
) Thunk_IDirect3DTextureImpl_1_Load
,
857 XCAST(Unload
) Main_IDirect3DTextureImpl_1_Unload
,
860 #if !defined(__STRICT_ANSI__) && defined(__GNUC__)
864 HRESULT
d3dtexture_create(IDirectDrawImpl
*d3d
, IDirectDrawSurfaceImpl
*surf
, BOOLEAN at_creation
,
865 IDirectDrawSurfaceImpl
*main
)
867 /* First, initialize the texture vtables... */
868 ICOM_INIT_INTERFACE(surf
, IDirect3DTexture
, VTABLE_IDirect3DTexture
);
869 ICOM_INIT_INTERFACE(surf
, IDirect3DTexture2
, VTABLE_IDirect3DTexture2
);
871 /* Only create all the private stuff if we actually have an OpenGL context.. */
872 if (d3d
->current_device
!= NULL
) {
873 IDirect3DTextureGLImpl
*private;
875 private = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(IDirect3DTextureGLImpl
));
876 if (private == NULL
) return DDERR_OUTOFMEMORY
;
878 private->final_release
= surf
->final_release
;
879 private->lock_update
= surf
->lock_update
;
880 private->unlock_update
= surf
->unlock_update
;
881 private->set_palette
= surf
->set_palette
;
883 /* If at creation, we can optimize stuff and wait the first 'unlock' to upload a valid stuff to OpenGL.
884 Otherwise, it will be uploaded here (and may be invalid). */
885 surf
->final_release
= gltex_final_release
;
886 surf
->lock_update
= gltex_lock_update
;
887 surf
->unlock_update
= gltex_unlock_update
;
888 surf
->tex_private
= private;
889 surf
->aux_setcolorkey_cb
= gltex_setcolorkey_cb
;
890 surf
->set_palette
= gltex_set_palette
;
892 /* We are the only one to use the aux_blt and aux_bltfast overrides, so no need
894 surf
->aux_blt
= gltex_blt
;
895 surf
->aux_bltfast
= gltex_bltfast
;
897 TRACE(" GL texture created for surface %p (private data at %p)\n", surf
, private);
900 if (surf
->mipmap_level
== 0) {
901 glGenTextures(1, &(private->tex_name
));
902 if (private->tex_name
== 0) ERR("Error at creation of OpenGL texture ID !\n");
903 TRACE(" GL texture id is : %d.\n", private->tex_name
);
904 private->__global_dirty_flag
= (at_creation
== FALSE
? SURFACE_MEMORY_DIRTY
: SURFACE_MEMORY
);
905 private->global_dirty_flag
= &(private->__global_dirty_flag
);
907 private->tex_name
= ((IDirect3DTextureGLImpl
*) (main
->tex_private
))->tex_name
;
908 TRACE(" GL texture id reusing id %d from surface %p (private at %p)).\n", private->tex_name
, main
, main
->tex_private
);
909 private->global_dirty_flag
= &(((IDirect3DTextureGLImpl
*) (main
->tex_private
))->__global_dirty_flag
);
913 /* And set the dirty flag accordingly */
914 private->dirty_flag
= (at_creation
== FALSE
? SURFACE_MEMORY_DIRTY
: SURFACE_MEMORY
);
915 private->initial_upload_done
= FALSE
;