Make WINE_GET_SONAME work on NetBSD.
[wine/wine64.git] / dlls / ddraw / d3dtexture.c
blobfba177ee7419a2f762609c122a07abc161b3b997
1 /* Direct3D Texture
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
21 #include "config.h"
23 #include <string.h>
25 #define NONAMELESSUNION
26 #define NONAMELESSSTRUCT
27 #include "windef.h"
28 #include "winerror.h"
29 #include "objbase.h"
30 #include "ddraw.h"
31 #include "d3d.h"
32 #include "wine/debug.h"
34 #include "mesa_private.h"
36 WINE_DEFAULT_DEBUG_CHANNEL(ddraw);
38 /* Define this if you want to save to a file all the textures used by a game
39 (can be funny to see how they managed to cram all the pictures in
40 texture memory) */
41 #undef TEXTURE_SNOOP
43 #ifdef TEXTURE_SNOOP
44 #include <stdio.h>
46 static void
47 snoop_texture(IDirectDrawSurfaceImpl *This) {
48 IDirect3DTextureGLImpl *glThis = (IDirect3DTextureGLImpl *) This->tex_private;
49 char buf[128];
50 FILE *f;
52 sprintf(buf, "tex_%05d_%02d.pnm", glThis->tex_name, This->mipmap_level);
53 f = fopen(buf, "wb");
54 DDRAW_dump_surface_to_disk(This, f);
57 #else
59 #define snoop_texture(a)
61 #endif
63 static IDirectDrawSurfaceImpl *
64 get_sub_mimaplevel(IDirectDrawSurfaceImpl *tex_ptr)
66 /* Now go down the mipmap chain to the next surface */
67 static const DDSCAPS2 mipmap_caps = { DDSCAPS_MIPMAP | DDSCAPS_TEXTURE, 0, 0, 0 };
68 LPDIRECTDRAWSURFACE7 next_level;
69 IDirectDrawSurfaceImpl *surf_ptr;
70 HRESULT hr;
72 hr = IDirectDrawSurface7_GetAttachedSurface(ICOM_INTERFACE(tex_ptr, IDirectDrawSurface7),
73 (DDSCAPS2 *) &mipmap_caps, &next_level);
74 if (FAILED(hr)) return NULL;
76 surf_ptr = ICOM_OBJECT(IDirectDrawSurfaceImpl, IDirectDrawSurface7, next_level);
77 IDirectDrawSurface7_Release(next_level);
79 return surf_ptr;
82 /*******************************************************************************
83 * IDirectSurface callback methods
86 HRESULT
87 gltex_download_texture(IDirectDrawSurfaceImpl *surf_ptr) {
88 IDirect3DTextureGLImpl *gl_surf_ptr = (IDirect3DTextureGLImpl *) surf_ptr->tex_private;
90 FIXME("This is not supported yet... Expect some graphical glitches !!!\n");
92 /* GL and memory are in sync again ...
93 No need to change the 'global' flag as it only handles the 'MEMORY_DIRTY' case.
95 gl_surf_ptr->dirty_flag = SURFACE_MEMORY;
97 return DD_OK;
100 static GLenum
101 convert_min_filter_to_GL(D3DTEXTUREMINFILTER dwMinState, D3DTEXTUREMIPFILTER dwMipState)
103 GLenum gl_state;
105 if (dwMipState == D3DTFP_NONE) {
106 switch (dwMinState) {
107 case D3DTFN_POINT: gl_state = GL_NEAREST; break;
108 case D3DTFN_LINEAR: gl_state = GL_LINEAR; break;
109 default: gl_state = GL_LINEAR; break;
111 } else if (dwMipState == D3DTFP_POINT) {
112 switch (dwMinState) {
113 case D3DTFN_POINT: gl_state = GL_NEAREST_MIPMAP_NEAREST; break;
114 case D3DTFN_LINEAR: gl_state = GL_LINEAR_MIPMAP_NEAREST; break;
115 default: gl_state = GL_LINEAR_MIPMAP_NEAREST; break;
117 } else {
118 switch (dwMinState) {
119 case D3DTFN_POINT: gl_state = GL_NEAREST_MIPMAP_LINEAR; break;
120 case D3DTFN_LINEAR: gl_state = GL_LINEAR_MIPMAP_LINEAR; break;
121 default: gl_state = GL_LINEAR_MIPMAP_LINEAR; break;
124 return gl_state;
127 static GLenum
128 convert_mag_filter_to_GL(D3DTEXTUREMAGFILTER dwState)
130 GLenum gl_state;
132 switch (dwState) {
133 case D3DTFG_POINT:
134 gl_state = GL_NEAREST;
135 break;
136 case D3DTFG_LINEAR:
137 gl_state = GL_LINEAR;
138 break;
139 default:
140 gl_state = GL_LINEAR;
141 break;
143 return gl_state;
146 static GLenum
147 convert_tex_address_to_GL(D3DTEXTUREADDRESS dwState)
149 GLenum gl_state;
150 switch (dwState) {
151 case D3DTADDRESS_WRAP: gl_state = GL_REPEAT; break;
152 case D3DTADDRESS_CLAMP: gl_state = GL_CLAMP; break;
153 case D3DTADDRESS_BORDER: gl_state = GL_CLAMP_TO_EDGE; break;
154 #if defined(GL_VERSION_1_4)
155 case D3DTADDRESS_MIRROR: gl_state = GL_MIRRORED_REPEAT; break;
156 #elif defined(GL_ARB_texture_mirrored_repeat)
157 case D3DTADDRESS_MIRROR: gl_state = GL_MIRRORED_REPEAT_ARB; break;
158 #endif
159 default: gl_state = GL_REPEAT; break;
161 return gl_state;
164 HRESULT
165 gltex_upload_texture(IDirectDrawSurfaceImpl *surf_ptr, IDirect3DDeviceImpl *d3ddev, DWORD stage) {
166 IDirect3DTextureGLImpl *gl_surf_ptr = (IDirect3DTextureGLImpl *) surf_ptr->tex_private;
167 BOOLEAN changed = FALSE;
169 if (surf_ptr->mipmap_level != 0) {
170 WARN(" application activating a sub-level of the mipmapping chain (level %d) !\n", surf_ptr->mipmap_level);
173 /* Now check if the texture parameters for this texture are still in-line with what D3D expect
174 us to do..
176 NOTE: there is no check for the situation where the same texture is bound to multiple stage
177 but with different parameters per stage.
179 if ((gl_surf_ptr->tex_parameters == NULL) ||
180 (gl_surf_ptr->tex_parameters[D3DTSS_MAXMIPLEVEL - D3DTSS_ADDRESSU] !=
181 d3ddev->state_block.texture_stage_state[stage][D3DTSS_MAXMIPLEVEL - 1])) {
182 DWORD max_mip_level;
184 if ((surf_ptr->surface_desc.ddsCaps.dwCaps & DDSCAPS_MIPMAP) == 0) {
185 max_mip_level = 0;
186 } else {
187 max_mip_level = surf_ptr->surface_desc.u2.dwMipMapCount - 1;
188 if (d3ddev->state_block.texture_stage_state[stage][D3DTSS_MAXMIPLEVEL - 1] != 0) {
189 if (max_mip_level >= d3ddev->state_block.texture_stage_state[stage][D3DTSS_MAXMIPLEVEL - 1]) {
190 max_mip_level = d3ddev->state_block.texture_stage_state[stage][D3DTSS_MAXMIPLEVEL - 1] - 1;
194 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, max_mip_level);
195 changed = TRUE;
198 if ((gl_surf_ptr->tex_parameters == NULL) ||
199 (gl_surf_ptr->tex_parameters[D3DTSS_MAGFILTER - D3DTSS_ADDRESSU] !=
200 d3ddev->state_block.texture_stage_state[stage][D3DTSS_MAGFILTER - 1])) {
201 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER,
202 convert_mag_filter_to_GL(d3ddev->state_block.texture_stage_state[stage][D3DTSS_MAGFILTER - 1]));
203 changed = TRUE;
205 if ((gl_surf_ptr->tex_parameters == NULL) ||
206 (gl_surf_ptr->tex_parameters[D3DTSS_MINFILTER - D3DTSS_ADDRESSU] !=
207 d3ddev->state_block.texture_stage_state[stage][D3DTSS_MINFILTER - 1]) ||
208 (gl_surf_ptr->tex_parameters[D3DTSS_MIPFILTER - D3DTSS_ADDRESSU] !=
209 d3ddev->state_block.texture_stage_state[stage][D3DTSS_MIPFILTER - 1])) {
210 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER,
211 convert_min_filter_to_GL(d3ddev->state_block.texture_stage_state[stage][D3DTSS_MINFILTER - 1],
212 d3ddev->state_block.texture_stage_state[stage][D3DTSS_MIPFILTER - 1]));
213 changed = TRUE;
215 if ((gl_surf_ptr->tex_parameters == NULL) ||
216 (gl_surf_ptr->tex_parameters[D3DTSS_ADDRESSU - D3DTSS_ADDRESSU] !=
217 d3ddev->state_block.texture_stage_state[stage][D3DTSS_ADDRESSU - 1])) {
218 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S,
219 convert_tex_address_to_GL(d3ddev->state_block.texture_stage_state[stage][D3DTSS_ADDRESSU - 1]));
220 changed = TRUE;
222 if ((gl_surf_ptr->tex_parameters == NULL) ||
223 (gl_surf_ptr->tex_parameters[D3DTSS_ADDRESSV - D3DTSS_ADDRESSU] !=
224 d3ddev->state_block.texture_stage_state[stage][D3DTSS_ADDRESSV - 1])) {
225 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T,
226 convert_tex_address_to_GL(d3ddev->state_block.texture_stage_state[stage][D3DTSS_ADDRESSV - 1]));
227 changed = TRUE;
229 if ((gl_surf_ptr->tex_parameters == NULL) ||
230 (gl_surf_ptr->tex_parameters[D3DTSS_BORDERCOLOR - D3DTSS_ADDRESSU] !=
231 d3ddev->state_block.texture_stage_state[stage][D3DTSS_BORDERCOLOR - 1])) {
232 GLfloat color[4];
234 color[0] = ((d3ddev->state_block.texture_stage_state[stage][D3DTSS_BORDERCOLOR - 1] >> 16) & 0xFF) / 255.0;
235 color[1] = ((d3ddev->state_block.texture_stage_state[stage][D3DTSS_BORDERCOLOR - 1] >> 8) & 0xFF) / 255.0;
236 color[2] = ((d3ddev->state_block.texture_stage_state[stage][D3DTSS_BORDERCOLOR - 1] >> 0) & 0xFF) / 255.0;
237 color[3] = ((d3ddev->state_block.texture_stage_state[stage][D3DTSS_BORDERCOLOR - 1] >> 24) & 0xFF) / 255.0;
238 glTexParameterfv(GL_TEXTURE_2D, GL_TEXTURE_BORDER_COLOR, color);
239 changed = TRUE;
242 if (changed == TRUE) {
243 if (gl_surf_ptr->tex_parameters == NULL) {
244 gl_surf_ptr->tex_parameters = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
245 sizeof(DWORD) * (D3DTSS_MAXMIPLEVEL + 1 - D3DTSS_ADDRESSU));
247 memcpy(gl_surf_ptr->tex_parameters, &(d3ddev->state_block.texture_stage_state[stage][D3DTSS_ADDRESSU - 1]),
248 sizeof(DWORD) * (D3DTSS_MAXMIPLEVEL + 1 - D3DTSS_ADDRESSU));
251 if (*(gl_surf_ptr->global_dirty_flag) != SURFACE_MEMORY_DIRTY) {
252 TRACE(" nothing to do - memory copy and GL state in synch for all texture levels.\n");
253 return DD_OK;
256 while (surf_ptr != NULL) {
257 IDirect3DTextureGLImpl *gl_surf_ptr = (IDirect3DTextureGLImpl *) surf_ptr->tex_private;
259 if (gl_surf_ptr->dirty_flag != SURFACE_MEMORY_DIRTY) {
260 TRACE(" - level %d already uploaded.\n", surf_ptr->mipmap_level);
261 } else {
262 TRACE(" - uploading texture level %d (initial done = %d).\n",
263 surf_ptr->mipmap_level, gl_surf_ptr->initial_upload_done);
265 /* Texture snooping for the curious :-) */
266 snoop_texture(surf_ptr);
268 if (upload_surface_to_tex_memory_init(surf_ptr, surf_ptr->mipmap_level, &(gl_surf_ptr->current_internal_format),
269 gl_surf_ptr->initial_upload_done == FALSE, TRUE, 0, 0) == DD_OK) {
270 upload_surface_to_tex_memory(NULL, 0, 0, &(gl_surf_ptr->surface_ptr));
271 upload_surface_to_tex_memory_release();
272 gl_surf_ptr->dirty_flag = SURFACE_MEMORY;
273 gl_surf_ptr->initial_upload_done = TRUE;
274 } else {
275 ERR("Problem for upload of texture %d (level = %d / initial done = %d).\n",
276 gl_surf_ptr->tex_name, surf_ptr->mipmap_level, gl_surf_ptr->initial_upload_done);
280 if (surf_ptr->surface_desc.ddsCaps.dwCaps & DDSCAPS_MIPMAP) {
281 surf_ptr = get_sub_mimaplevel(surf_ptr);
282 } else {
283 surf_ptr = NULL;
287 *(gl_surf_ptr->global_dirty_flag) = SURFACE_MEMORY;
289 return DD_OK;
292 HRESULT WINAPI
293 Main_IDirect3DTextureImpl_1_Initialize(LPDIRECT3DTEXTURE iface,
294 LPDIRECT3DDEVICE lpDirect3DDevice,
295 LPDIRECTDRAWSURFACE lpDDSurface)
297 ICOM_THIS_FROM(IDirectDrawSurfaceImpl, IDirect3DTexture, iface);
298 FIXME("(%p/%p)->(%p,%p) no-op...\n", This, iface, lpDirect3DDevice, lpDDSurface);
299 return DD_OK;
302 static HRESULT
303 gltex_setcolorkey_cb(IDirectDrawSurfaceImpl *This, DWORD dwFlags, LPDDCOLORKEY ckey )
305 IDirect3DTextureGLImpl *glThis = (IDirect3DTextureGLImpl *) This->tex_private;
307 if (glThis->dirty_flag == SURFACE_GL) {
308 GLuint cur_tex;
310 TRACE(" flushing GL texture back to memory.\n");
312 ENTER_GL();
313 glGetIntegerv(GL_TEXTURE_BINDING_2D, &cur_tex);
314 glBindTexture(GL_TEXTURE_2D, glThis->tex_name);
315 gltex_download_texture(This);
316 glBindTexture(GL_TEXTURE_2D, cur_tex);
317 LEAVE_GL();
320 glThis->dirty_flag = SURFACE_MEMORY_DIRTY;
321 *(glThis->global_dirty_flag) = SURFACE_MEMORY_DIRTY;
322 /* TODO: check color-keying on mipmapped surfaces... */
324 return DD_OK;
327 HRESULT
328 gltex_blt(IDirectDrawSurfaceImpl *This, LPRECT rdst,
329 LPDIRECTDRAWSURFACE7 src, LPRECT rsrc,
330 DWORD dwFlags, LPDDBLTFX lpbltfx)
332 if (src != NULL) {
333 IDirectDrawSurfaceImpl *src_ptr = ICOM_OBJECT(IDirectDrawSurfaceImpl, IDirectDrawSurface7, src);
334 if (src_ptr->surface_desc.ddsCaps.dwCaps & DDSCAPS_3DDEVICE) {
335 FIXME("Blt from framebuffer to texture - unsupported now, please report !\n");
338 return DDERR_INVALIDPARAMS;
341 HRESULT
342 gltex_bltfast(IDirectDrawSurfaceImpl *surf_ptr, DWORD dstx,
343 DWORD dsty, LPDIRECTDRAWSURFACE7 src,
344 LPRECT rsrc, DWORD trans)
346 if (src != NULL) {
347 IDirectDrawSurfaceImpl *src_ptr = ICOM_OBJECT(IDirectDrawSurfaceImpl, IDirectDrawSurface7, src);
349 if ((src_ptr->surface_desc.ddsCaps.dwCaps & DDSCAPS_3DDEVICE) &&
350 ((trans & (DDBLTFAST_SRCCOLORKEY | DDBLTFAST_DESTCOLORKEY)) == 0)) {
351 /* This is a blt without color keying... We can use the direct copy. */
352 RECT rsrc2;
353 DWORD width, height;
354 GLuint cur_tex;
355 IDirect3DTextureGLImpl *gl_surf_ptr = surf_ptr->tex_private;
356 int y;
358 if (rsrc == NULL) {
359 WARN("rsrc is NULL\n");
360 rsrc = &rsrc2;
362 rsrc->left = 0;
363 rsrc->top = 0;
364 rsrc->right = src_ptr->surface_desc.dwWidth;
365 rsrc->bottom = src_ptr->surface_desc.dwHeight;
368 width = rsrc->right - rsrc->left;
369 height = rsrc->bottom - rsrc->top;
371 if (((dstx + width) > surf_ptr->surface_desc.dwWidth) ||
372 ((dsty + height) > surf_ptr->surface_desc.dwHeight)) {
373 FIXME("Does not handle clipping yet in FB => Texture blits !\n");
374 return DDERR_INVALIDPARAMS;
377 if ((width == 0) || (height == 0)) {
378 return DD_OK;
381 TRACE(" direct frame buffer => texture BltFast override.\n");
383 ENTER_GL();
385 glGetIntegerv(GL_TEXTURE_BINDING_2D, &cur_tex);
386 glBindTexture(GL_TEXTURE_2D, gl_surf_ptr->tex_name);
388 if ((gl_surf_ptr->dirty_flag == SURFACE_MEMORY_DIRTY) &&
389 !((dstx == 0) && (dsty == 0) &&
390 (width == surf_ptr->surface_desc.dwWidth) && (height == surf_ptr->surface_desc.dwHeight))) {
391 /* If not 'full size' and the surface is dirty, first flush it to GL before doing the copy. */
392 if (upload_surface_to_tex_memory_init(surf_ptr, surf_ptr->mipmap_level, &(gl_surf_ptr->current_internal_format),
393 gl_surf_ptr->initial_upload_done == FALSE, TRUE, 0, 0) == DD_OK) {
394 upload_surface_to_tex_memory(NULL, 0, 0, &(gl_surf_ptr->surface_ptr));
395 upload_surface_to_tex_memory_release();
396 gl_surf_ptr->dirty_flag = SURFACE_MEMORY;
397 gl_surf_ptr->initial_upload_done = TRUE;
398 } else {
399 glBindTexture(GL_TEXTURE_2D, cur_tex);
400 LEAVE_GL();
401 ERR("Error at texture upload !\n");
402 return DDERR_INVALIDPARAMS;
406 /* This is a hack and would need some clean-up :-) */
407 if (gl_surf_ptr->initial_upload_done == FALSE) {
408 if (upload_surface_to_tex_memory_init(surf_ptr, surf_ptr->mipmap_level, &(gl_surf_ptr->current_internal_format),
409 TRUE, TRUE, 0, 0) == DD_OK) {
410 upload_surface_to_tex_memory(NULL, 0, 0, &(gl_surf_ptr->surface_ptr));
411 upload_surface_to_tex_memory_release();
412 gl_surf_ptr->dirty_flag = SURFACE_MEMORY;
413 gl_surf_ptr->initial_upload_done = TRUE;
414 } else {
415 glBindTexture(GL_TEXTURE_2D, cur_tex);
416 LEAVE_GL();
417 ERR("Error at texture upload (initial case) !\n");
418 return DDERR_INVALIDPARAMS;
422 if ((src_ptr->surface_desc.ddsCaps.dwCaps & (DDSCAPS_FRONTBUFFER|DDSCAPS_PRIMARYSURFACE)) != 0)
423 glReadBuffer(GL_FRONT);
424 else if ((src_ptr->surface_desc.ddsCaps.dwCaps & (DDSCAPS_BACKBUFFER)) == (DDSCAPS_BACKBUFFER))
425 glReadBuffer(GL_BACK);
426 else {
427 ERR("Wrong surface type for locking !\n");
428 glBindTexture(GL_TEXTURE_2D, cur_tex);
429 LEAVE_GL();
430 return DDERR_INVALIDPARAMS;
433 for (y = (src_ptr->surface_desc.dwHeight - rsrc->top - 1);
434 y >= (src_ptr->surface_desc.dwHeight - (rsrc->top + height));
435 y--) {
436 glCopyTexSubImage2D(GL_TEXTURE_2D, surf_ptr->mipmap_level,
437 dstx, dsty,
438 rsrc->left, y,
439 width, 1);
440 dsty++;
443 glBindTexture(GL_TEXTURE_2D, cur_tex);
444 LEAVE_GL();
446 /* The SURFACE_GL case is not handled by the 'global' dirty flag */
447 gl_surf_ptr->dirty_flag = SURFACE_GL;
449 return DD_OK;
452 return DDERR_INVALIDPARAMS;
455 HRESULT WINAPI
456 Main_IDirect3DTextureImpl_2_1T_PaletteChanged(LPDIRECT3DTEXTURE2 iface,
457 DWORD dwStart,
458 DWORD dwCount)
460 ICOM_THIS_FROM(IDirectDrawSurfaceImpl, IDirect3DTexture2, iface);
461 FIXME("(%p/%p)->(%08lx,%08lx): stub!\n", This, iface, dwStart, dwCount);
462 return DD_OK;
465 HRESULT WINAPI
466 Main_IDirect3DTextureImpl_1_Unload(LPDIRECT3DTEXTURE iface)
468 ICOM_THIS_FROM(IDirectDrawSurfaceImpl, IDirect3DTexture, iface);
469 FIXME("(%p/%p)->(): stub!\n", This, iface);
470 return DD_OK;
473 HRESULT WINAPI
474 Main_IDirect3DTextureImpl_2_1T_GetHandle(LPDIRECT3DTEXTURE2 iface,
475 LPDIRECT3DDEVICE2 lpDirect3DDevice2,
476 LPD3DTEXTUREHANDLE lpHandle)
478 ICOM_THIS_FROM(IDirectDrawSurfaceImpl, IDirect3DTexture2, iface);
479 IDirect3DDeviceImpl *lpDeviceImpl = ICOM_OBJECT(IDirect3DDeviceImpl, IDirect3DDevice2, lpDirect3DDevice2);
481 TRACE("(%p/%p)->(%p,%p)\n", This, iface, lpDirect3DDevice2, lpHandle);
483 /* The handle is simply the pointer to the implementation structure */
484 *lpHandle = (D3DTEXTUREHANDLE) This;
486 TRACE(" returning handle %08lx.\n", *lpHandle);
488 /* Now set the device for this texture */
489 This->d3ddevice = lpDeviceImpl;
491 return D3D_OK;
494 HRESULT WINAPI
495 Main_IDirect3DTextureImpl_2_1T_Load(LPDIRECT3DTEXTURE2 iface,
496 LPDIRECT3DTEXTURE2 lpD3DTexture2)
498 ICOM_THIS_FROM(IDirectDrawSurfaceImpl, IDirect3DTexture2, iface);
499 FIXME("(%p/%p)->(%p): stub!\n", This, iface, lpD3DTexture2);
500 return DD_OK;
503 static void gltex_set_palette(IDirectDrawSurfaceImpl* This, IDirectDrawPaletteImpl* pal)
505 IDirect3DTextureGLImpl *glThis = (IDirect3DTextureGLImpl *) This->tex_private;
507 if (glThis->dirty_flag == SURFACE_GL) {
508 GLuint cur_tex;
510 TRACE(" flushing GL texture back to memory.\n");
512 ENTER_GL();
513 glGetIntegerv(GL_TEXTURE_BINDING_2D, &cur_tex);
514 glBindTexture(GL_TEXTURE_2D, glThis->tex_name);
515 gltex_download_texture(This);
516 glBindTexture(GL_TEXTURE_2D, cur_tex);
517 LEAVE_GL();
520 /* First call the previous set_palette function */
521 glThis->set_palette(This, pal);
523 /* And set the dirty flag */
524 glThis->dirty_flag = SURFACE_MEMORY_DIRTY;
525 *(glThis->global_dirty_flag) = SURFACE_MEMORY_DIRTY;
527 /* TODO: check palette on mipmapped surfaces...
528 TODO: do we need to re-upload in case of usage of the paletted texture extension ? */
531 static void
532 gltex_final_release(IDirectDrawSurfaceImpl *This)
534 IDirect3DTextureGLImpl *glThis = (IDirect3DTextureGLImpl *) This->tex_private;
535 DWORD mem_used;
536 int i;
538 TRACE(" deleting texture with GL id %d.\n", glThis->tex_name);
540 /* And delete texture handle */
541 ENTER_GL();
542 if (glThis->tex_name != 0)
543 glDeleteTextures(1, &(glThis->tex_name));
544 LEAVE_GL();
546 if (glThis->surface_ptr != NULL)
547 HeapFree(GetProcessHeap(), 0, glThis->surface_ptr);
549 /* And if this texture was the current one, remove it at the device level */
550 if (This->d3ddevice != NULL)
551 for (i = 0; i < MAX_TEXTURES; i++)
552 if (This->d3ddevice->current_texture[i] == This)
553 This->d3ddevice->current_texture[i] = NULL;
555 /* All this should be part of main surface management not just a hack for texture.. */
556 if (glThis->loaded) {
557 mem_used = This->surface_desc.dwHeight *
558 This->surface_desc.u1.lPitch;
559 This->ddraw_owner->free_memory(This->ddraw_owner, mem_used);
562 glThis->final_release(This);
565 static void
566 gltex_lock_update(IDirectDrawSurfaceImpl* This, LPCRECT pRect, DWORD dwFlags)
568 IDirect3DTextureGLImpl *glThis = (IDirect3DTextureGLImpl *) This->tex_private;
570 glThis->lock_update(This, pRect, dwFlags);
573 static void
574 gltex_unlock_update(IDirectDrawSurfaceImpl* This, LPCRECT pRect)
576 IDirect3DTextureGLImpl *glThis = (IDirect3DTextureGLImpl *) This->tex_private;
578 glThis->unlock_update(This, pRect);
580 /* Set the dirty flag according to the lock type */
581 if ((This->lastlocktype & DDLOCK_READONLY) == 0) {
582 glThis->dirty_flag = SURFACE_MEMORY_DIRTY;
583 *(glThis->global_dirty_flag) = SURFACE_MEMORY_DIRTY;
587 HRESULT WINAPI
588 GL_IDirect3DTextureImpl_2_1T_Load(LPDIRECT3DTEXTURE2 iface,
589 LPDIRECT3DTEXTURE2 lpD3DTexture2)
591 ICOM_THIS_FROM(IDirectDrawSurfaceImpl, IDirect3DTexture2, iface);
592 IDirectDrawSurfaceImpl *src_ptr = ICOM_OBJECT(IDirectDrawSurfaceImpl, IDirect3DTexture2, lpD3DTexture2);
593 IDirectDrawSurfaceImpl *dst_ptr = This;
594 HRESULT ret_value = D3D_OK;
596 TRACE("(%p/%p)->(%p)\n", This, iface, lpD3DTexture2);
598 if (((src_ptr->surface_desc.ddsCaps.dwCaps & DDSCAPS_MIPMAP) != (dst_ptr->surface_desc.ddsCaps.dwCaps & DDSCAPS_MIPMAP)) ||
599 (src_ptr->surface_desc.u2.dwMipMapCount != dst_ptr->surface_desc.u2.dwMipMapCount)) {
600 ERR("Trying to load surfaces with different mip-map counts !\n");
603 /* Now loop through all mipmap levels and load all of them... */
604 while (1) {
605 IDirect3DTextureGLImpl *gl_dst_ptr = (IDirect3DTextureGLImpl *) dst_ptr->tex_private;
606 DDSURFACEDESC *src_d, *dst_d;
608 if (gl_dst_ptr != NULL) {
609 if (gl_dst_ptr->loaded == FALSE) {
610 /* Only check memory for not already loaded texture... */
611 DWORD mem_used = dst_ptr->surface_desc.dwHeight * dst_ptr->surface_desc.u1.lPitch;
612 if (This->ddraw_owner->allocate_memory(This->ddraw_owner, mem_used) < 0) {
613 TRACE(" out of virtual memory... Warning application.\n");
614 return D3DERR_TEXTURE_LOAD_FAILED;
617 gl_dst_ptr->loaded = TRUE;
620 TRACE(" copying surface %p to surface %p (mipmap level %d)\n", src_ptr, dst_ptr, src_ptr->mipmap_level);
622 if ( dst_ptr->surface_desc.ddsCaps.dwCaps & DDSCAPS_ALLOCONLOAD )
623 /* If the surface is not allocated and its location is not yet specified,
624 force it to video memory */
625 if ( !(dst_ptr->surface_desc.ddsCaps.dwCaps & (DDSCAPS_SYSTEMMEMORY|DDSCAPS_VIDEOMEMORY)) )
626 dst_ptr->surface_desc.ddsCaps.dwCaps |= DDSCAPS_VIDEOMEMORY;
628 /* Suppress the ALLOCONLOAD flag */
629 dst_ptr->surface_desc.ddsCaps.dwCaps &= ~DDSCAPS_ALLOCONLOAD;
631 /* After seeing some logs, not sure at all about this... */
632 if (dst_ptr->palette == NULL) {
633 dst_ptr->palette = src_ptr->palette;
634 if (src_ptr->palette != NULL) IDirectDrawPalette_AddRef(ICOM_INTERFACE(src_ptr->palette, IDirectDrawPalette));
635 } else {
636 if (src_ptr->palette != NULL) {
637 PALETTEENTRY palent[256];
638 IDirectDrawPalette_GetEntries(ICOM_INTERFACE(src_ptr->palette, IDirectDrawPalette),
639 0, 0, 256, palent);
640 IDirectDrawPalette_SetEntries(ICOM_INTERFACE(dst_ptr->palette, IDirectDrawPalette),
641 0, 0, 256, palent);
645 /* Copy one surface on the other */
646 dst_d = (DDSURFACEDESC *)&(dst_ptr->surface_desc);
647 src_d = (DDSURFACEDESC *)&(src_ptr->surface_desc);
649 if ((src_d->dwWidth != dst_d->dwWidth) || (src_d->dwHeight != dst_d->dwHeight)) {
650 /* Should also check for same pixel format, u1.lPitch, ... */
651 ERR("Error in surface sizes\n");
652 return D3DERR_TEXTURE_LOAD_FAILED;
653 } else {
654 /* LPDIRECT3DDEVICE2 d3dd = (LPDIRECT3DDEVICE2) This->D3Ddevice; */
655 /* I should put a macro for the calculus of bpp */
657 /* Copy also the ColorKeying stuff */
658 if (src_d->dwFlags & DDSD_CKSRCBLT) {
659 dst_d->dwFlags |= DDSD_CKSRCBLT;
660 dst_d->ddckCKSrcBlt.dwColorSpaceLowValue = src_d->ddckCKSrcBlt.dwColorSpaceLowValue;
661 dst_d->ddckCKSrcBlt.dwColorSpaceHighValue = src_d->ddckCKSrcBlt.dwColorSpaceHighValue;
664 /* Copy the main memory texture into the surface that corresponds to the OpenGL
665 texture object. */
666 memcpy(dst_d->lpSurface, src_d->lpSurface, src_d->u1.lPitch * src_d->dwHeight);
668 if (gl_dst_ptr != NULL) {
669 /* If the GetHandle was not done, it is an error... */
670 if (gl_dst_ptr->tex_name == 0) ERR("Unbound GL texture !!!\n");
672 /* Set this texture as dirty */
673 gl_dst_ptr->dirty_flag = SURFACE_MEMORY_DIRTY;
674 *(gl_dst_ptr->global_dirty_flag) = SURFACE_MEMORY_DIRTY;
678 if (src_ptr->surface_desc.ddsCaps.dwCaps & DDSCAPS_MIPMAP) {
679 src_ptr = get_sub_mimaplevel(src_ptr);
680 } else {
681 src_ptr = NULL;
683 if (dst_ptr->surface_desc.ddsCaps.dwCaps & DDSCAPS_MIPMAP) {
684 dst_ptr = get_sub_mimaplevel(dst_ptr);
685 } else {
686 dst_ptr = NULL;
689 if ((src_ptr == NULL) || (dst_ptr == NULL)) {
690 if (src_ptr != dst_ptr) {
691 ERR(" Loading surface with different mipmap structure !!!\n");
693 break;
697 return ret_value;
700 HRESULT WINAPI
701 Thunk_IDirect3DTextureImpl_2_QueryInterface(LPDIRECT3DTEXTURE2 iface,
702 REFIID riid,
703 LPVOID* obp)
705 TRACE("(%p)->(%s,%p) thunking to IDirectDrawSurface7 interface.\n", iface, debugstr_guid(riid), obp);
706 return IDirectDrawSurface7_QueryInterface(COM_INTERFACE_CAST(IDirectDrawSurfaceImpl, IDirect3DTexture2, IDirectDrawSurface7, iface),
707 riid,
708 obp);
711 ULONG WINAPI
712 Thunk_IDirect3DTextureImpl_2_AddRef(LPDIRECT3DTEXTURE2 iface)
714 TRACE("(%p)->() thunking to IDirectDrawSurface7 interface.\n", iface);
715 return IDirectDrawSurface7_AddRef(COM_INTERFACE_CAST(IDirectDrawSurfaceImpl, IDirect3DTexture2, IDirectDrawSurface7, iface));
718 ULONG WINAPI
719 Thunk_IDirect3DTextureImpl_2_Release(LPDIRECT3DTEXTURE2 iface)
721 TRACE("(%p)->() thunking to IDirectDrawSurface7 interface.\n", iface);
722 return IDirectDrawSurface7_Release(COM_INTERFACE_CAST(IDirectDrawSurfaceImpl, IDirect3DTexture2, IDirectDrawSurface7, iface));
725 HRESULT WINAPI
726 Thunk_IDirect3DTextureImpl_1_QueryInterface(LPDIRECT3DTEXTURE iface,
727 REFIID riid,
728 LPVOID* obp)
730 TRACE("(%p)->(%s,%p) thunking to IDirectDrawSurface7 interface.\n", iface, debugstr_guid(riid), obp);
731 return IDirectDrawSurface7_QueryInterface(COM_INTERFACE_CAST(IDirectDrawSurfaceImpl, IDirect3DTexture, IDirectDrawSurface7, iface),
732 riid,
733 obp);
736 ULONG WINAPI
737 Thunk_IDirect3DTextureImpl_1_AddRef(LPDIRECT3DTEXTURE iface)
739 TRACE("(%p)->() thunking to IDirectDrawSurface7 interface.\n", iface);
740 return IDirectDrawSurface7_AddRef(COM_INTERFACE_CAST(IDirectDrawSurfaceImpl, IDirect3DTexture, IDirectDrawSurface7, iface));
743 ULONG WINAPI
744 Thunk_IDirect3DTextureImpl_1_Release(LPDIRECT3DTEXTURE iface)
746 TRACE("(%p)->() thunking to IDirectDrawSurface7 interface.\n", iface);
747 return IDirectDrawSurface7_Release(COM_INTERFACE_CAST(IDirectDrawSurfaceImpl, IDirect3DTexture, IDirectDrawSurface7, iface));
750 HRESULT WINAPI
751 Thunk_IDirect3DTextureImpl_1_PaletteChanged(LPDIRECT3DTEXTURE iface,
752 DWORD dwStart,
753 DWORD dwCount)
755 TRACE("(%p)->(%08lx,%08lx) thunking to IDirect3DTexture2 interface.\n", iface, dwStart, dwCount);
756 return IDirect3DTexture2_PaletteChanged(COM_INTERFACE_CAST(IDirectDrawSurfaceImpl, IDirect3DTexture, IDirect3DTexture2, iface),
757 dwStart,
758 dwCount);
761 HRESULT WINAPI
762 Thunk_IDirect3DTextureImpl_1_GetHandle(LPDIRECT3DTEXTURE iface,
763 LPDIRECT3DDEVICE lpDirect3DDevice,
764 LPD3DTEXTUREHANDLE lpHandle)
766 TRACE("(%p)->(%p,%p) thunking to IDirect3DTexture2 interface.\n", iface, lpDirect3DDevice, lpHandle);
767 return IDirect3DTexture2_GetHandle(COM_INTERFACE_CAST(IDirectDrawSurfaceImpl, IDirect3DTexture, IDirect3DTexture2, iface),
768 COM_INTERFACE_CAST(IDirect3DDeviceImpl, IDirect3DDevice, IDirect3DDevice2, lpDirect3DDevice),
769 lpHandle);
772 HRESULT WINAPI
773 Thunk_IDirect3DTextureImpl_1_Load(LPDIRECT3DTEXTURE iface,
774 LPDIRECT3DTEXTURE lpD3DTexture)
776 TRACE("(%p)->(%p) thunking to IDirect3DTexture2 interface.\n", iface, lpD3DTexture);
777 return IDirect3DTexture2_Load(COM_INTERFACE_CAST(IDirectDrawSurfaceImpl, IDirect3DTexture, IDirect3DTexture2, iface),
778 COM_INTERFACE_CAST(IDirectDrawSurfaceImpl, IDirect3DTexture, IDirect3DTexture2, lpD3DTexture));
781 #if !defined(__STRICT_ANSI__) && defined(__GNUC__)
782 # define XCAST(fun) (typeof(VTABLE_IDirect3DTexture2.fun))
783 #else
784 # define XCAST(fun) (void*)
785 #endif
787 ICOM_VTABLE(IDirect3DTexture2) VTABLE_IDirect3DTexture2 =
789 ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE
790 XCAST(QueryInterface) Thunk_IDirect3DTextureImpl_2_QueryInterface,
791 XCAST(AddRef) Thunk_IDirect3DTextureImpl_2_AddRef,
792 XCAST(Release) Thunk_IDirect3DTextureImpl_2_Release,
793 XCAST(GetHandle) Main_IDirect3DTextureImpl_2_1T_GetHandle,
794 XCAST(PaletteChanged) Main_IDirect3DTextureImpl_2_1T_PaletteChanged,
795 XCAST(Load) GL_IDirect3DTextureImpl_2_1T_Load,
798 #if !defined(__STRICT_ANSI__) && defined(__GNUC__)
799 #undef XCAST
800 #endif
803 #if !defined(__STRICT_ANSI__) && defined(__GNUC__)
804 # define XCAST(fun) (typeof(VTABLE_IDirect3DTexture.fun))
805 #else
806 # define XCAST(fun) (void*)
807 #endif
809 ICOM_VTABLE(IDirect3DTexture) VTABLE_IDirect3DTexture =
811 ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE
812 XCAST(QueryInterface) Thunk_IDirect3DTextureImpl_1_QueryInterface,
813 XCAST(AddRef) Thunk_IDirect3DTextureImpl_1_AddRef,
814 XCAST(Release) Thunk_IDirect3DTextureImpl_1_Release,
815 XCAST(Initialize) Main_IDirect3DTextureImpl_1_Initialize,
816 XCAST(GetHandle) Thunk_IDirect3DTextureImpl_1_GetHandle,
817 XCAST(PaletteChanged) Thunk_IDirect3DTextureImpl_1_PaletteChanged,
818 XCAST(Load) Thunk_IDirect3DTextureImpl_1_Load,
819 XCAST(Unload) Main_IDirect3DTextureImpl_1_Unload,
822 #if !defined(__STRICT_ANSI__) && defined(__GNUC__)
823 #undef XCAST
824 #endif
826 HRESULT d3dtexture_create(IDirectDrawImpl *d3d, IDirectDrawSurfaceImpl *surf, BOOLEAN at_creation,
827 IDirectDrawSurfaceImpl *main)
829 /* First, initialize the texture vtables... */
830 ICOM_INIT_INTERFACE(surf, IDirect3DTexture, VTABLE_IDirect3DTexture);
831 ICOM_INIT_INTERFACE(surf, IDirect3DTexture2, VTABLE_IDirect3DTexture2);
833 /* Only create all the private stuff if we actually have an OpenGL context.. */
834 if (d3d->current_device != NULL) {
835 IDirect3DTextureGLImpl *private;
837 private = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IDirect3DTextureGLImpl));
838 if (private == NULL) return DDERR_OUTOFMEMORY;
840 private->final_release = surf->final_release;
841 private->lock_update = surf->lock_update;
842 private->unlock_update = surf->unlock_update;
843 private->set_palette = surf->set_palette;
845 /* If at creation, we can optimize stuff and wait the first 'unlock' to upload a valid stuff to OpenGL.
846 Otherwise, it will be uploaded here (and may be invalid). */
847 surf->final_release = gltex_final_release;
848 surf->lock_update = gltex_lock_update;
849 surf->unlock_update = gltex_unlock_update;
850 surf->tex_private = private;
851 surf->aux_setcolorkey_cb = gltex_setcolorkey_cb;
852 surf->set_palette = gltex_set_palette;
854 /* We are the only one to use the aux_blt and aux_bltfast overides, so no need
855 to save those... */
856 surf->aux_blt = gltex_blt;
857 surf->aux_bltfast = gltex_bltfast;
859 TRACE(" GL texture created for surface %p (private data at %p)\n", surf, private);
861 ENTER_GL();
862 if (surf->mipmap_level == 0) {
863 glGenTextures(1, &(private->tex_name));
864 if (private->tex_name == 0) ERR("Error at creation of OpenGL texture ID !\n");
865 TRACE(" GL texture id is : %d.\n", private->tex_name);
866 private->__global_dirty_flag = (at_creation == FALSE ? SURFACE_MEMORY_DIRTY : SURFACE_MEMORY);
867 private->global_dirty_flag = &(private->__global_dirty_flag);
868 } else {
869 private->tex_name = ((IDirect3DTextureGLImpl *) (main->tex_private))->tex_name;
870 TRACE(" GL texture id reusing id %d from surface %p (private at %p)).\n", private->tex_name, main, main->tex_private);
871 private->global_dirty_flag = &(((IDirect3DTextureGLImpl *) (main->tex_private))->__global_dirty_flag);
873 LEAVE_GL();
875 /* And set the dirty flag accordingly */
876 private->dirty_flag = (at_creation == FALSE ? SURFACE_MEMORY_DIRTY : SURFACE_MEMORY);
877 private->initial_upload_done = FALSE;
880 return D3D_OK;