Avoid referencing stackframe.h from outside kernel32.
[wine/testsucceed.git] / dlls / ddraw / d3dtexture.c
blob2a88e78c994f4d546fd8456d145c4e050cfee1a9
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 <stdarg.h>
24 #include <string.h>
26 #define NONAMELESSUNION
27 #define NONAMELESSSTRUCT
28 #include "windef.h"
29 #include "winbase.h"
30 #include "winerror.h"
31 #include "objbase.h"
32 #include "wingdi.h"
33 #include "ddraw.h"
34 #include "d3d.h"
35 #include "wine/debug.h"
37 #include "mesa_private.h"
39 WINE_DEFAULT_DEBUG_CHANNEL(ddraw);
40 WINE_DECLARE_DEBUG_CHANNEL(ddraw_tex);
42 #include <stdio.h>
44 static void
45 snoop_texture(IDirectDrawSurfaceImpl *This) {
46 IDirect3DTextureGLImpl *glThis = (IDirect3DTextureGLImpl *) This->tex_private;
47 char buf[128];
48 FILE *f;
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);
54 f = fopen(buf, "wb");
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;
65 HRESULT hr;
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);
74 return surf_ptr;
77 /*******************************************************************************
78 * IDirectSurface callback methods
81 HRESULT
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;
92 return DD_OK;
95 static GLenum
96 convert_min_filter_to_GL(D3DTEXTUREMINFILTER dwMinState, D3DTEXTUREMIPFILTER dwMipState)
98 GLenum gl_state;
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;
112 } else {
113 switch (dwMinState) {
114 case D3DTFN_POINT: gl_state = GL_NEAREST_MIPMAP_LINEAR; break;
115 case D3DTFN_LINEAR: gl_state = GL_LINEAR_MIPMAP_LINEAR; break;
116 default: gl_state = GL_LINEAR_MIPMAP_LINEAR; break;
119 return gl_state;
122 static GLenum
123 convert_mag_filter_to_GL(D3DTEXTUREMAGFILTER dwState)
125 GLenum gl_state;
127 switch (dwState) {
128 case D3DTFG_POINT:
129 gl_state = GL_NEAREST;
130 break;
131 case D3DTFG_LINEAR:
132 gl_state = GL_LINEAR;
133 break;
134 default:
135 gl_state = GL_LINEAR;
136 break;
138 return gl_state;
141 static GLenum
142 convert_tex_address_to_GL(D3DTEXTUREADDRESS dwState)
144 GLenum gl_state;
145 switch (dwState) {
146 case D3DTADDRESS_WRAP: gl_state = GL_REPEAT; break;
147 case D3DTADDRESS_CLAMP: gl_state = GL_CLAMP; break;
148 case D3DTADDRESS_BORDER: gl_state = GL_CLAMP_TO_EDGE; break;
149 case D3DTADDRESS_MIRROR:
150 if (GL_extensions.mirrored_repeat) {
151 gl_state = GL_MIRRORED_REPEAT_WINE;
152 } else {
153 gl_state = GL_REPEAT;
154 /* This is a TRACE instead of a FIXME as the FIXME was already printed when the game
155 actually set D3DTADDRESS_MIRROR.
157 TRACE(" setting GL_REPEAT instead of GL_MIRRORED_REPEAT.\n");
159 break;
160 default: gl_state = GL_REPEAT; break;
162 return gl_state;
165 HRESULT
166 gltex_upload_texture(IDirectDrawSurfaceImpl *surf_ptr, IDirect3DDeviceImpl *d3ddev, DWORD stage) {
167 IDirect3DTextureGLImpl *gl_surf_ptr = (IDirect3DTextureGLImpl *) surf_ptr->tex_private;
168 IDirect3DDeviceGLImpl *gl_d3ddev = (IDirect3DDeviceGLImpl *) d3ddev;
169 BOOLEAN changed = FALSE;
170 GLenum unit = GL_TEXTURE0_WINE + stage;
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
177 us to do..
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])) {
185 DWORD max_mip_level;
187 if ((surf_ptr->surface_desc.ddsCaps.dwCaps & DDSCAPS_MIPMAP) == 0) {
188 max_mip_level = 0;
189 } else {
190 max_mip_level = surf_ptr->surface_desc.u2.dwMipMapCount - 1;
191 if (d3ddev->state_block.texture_stage_state[stage][D3DTSS_MAXMIPLEVEL - 1] != 0) {
192 if (max_mip_level >= d3ddev->state_block.texture_stage_state[stage][D3DTSS_MAXMIPLEVEL - 1]) {
193 max_mip_level = d3ddev->state_block.texture_stage_state[stage][D3DTSS_MAXMIPLEVEL - 1] - 1;
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);
202 changed = TRUE;
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]));
214 changed = TRUE;
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]));
228 changed = TRUE;
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]));
239 changed = TRUE;
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]));
250 changed = TRUE;
252 if ((gl_surf_ptr->tex_parameters == NULL) ||
253 (gl_surf_ptr->tex_parameters[D3DTSS_BORDERCOLOR - D3DTSS_ADDRESSU] !=
254 d3ddev->state_block.texture_stage_state[stage][D3DTSS_BORDERCOLOR - 1])) {
255 GLfloat color[4];
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);
266 changed = TRUE;
269 if (changed) {
270 if (gl_surf_ptr->tex_parameters == NULL) {
271 gl_surf_ptr->tex_parameters = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
272 sizeof(DWORD) * (D3DTSS_MAXMIPLEVEL + 1 - D3DTSS_ADDRESSU));
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");
280 return DD_OK;
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);
288 } else {
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;
308 } else {
309 ERR("Problem for upload of texture %d (level = %d / initial done = %d).\n",
310 gl_surf_ptr->tex_name, surf_ptr->mipmap_level, gl_surf_ptr->initial_upload_done);
314 if (surf_ptr->surface_desc.ddsCaps.dwCaps & DDSCAPS_MIPMAP) {
315 surf_ptr = get_sub_mimaplevel(surf_ptr);
316 } else {
317 surf_ptr = NULL;
321 *(gl_surf_ptr->global_dirty_flag) = SURFACE_MEMORY;
323 return DD_OK;
326 HRESULT WINAPI
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);
333 return DD_OK;
336 static HRESULT
337 gltex_setcolorkey_cb(IDirectDrawSurfaceImpl *This, DWORD dwFlags, LPDDCOLORKEY ckey )
339 IDirect3DTextureGLImpl *glThis = (IDirect3DTextureGLImpl *) This->tex_private;
341 if (glThis->dirty_flag == SURFACE_GL) {
342 GLuint cur_tex;
344 TRACE(" flushing GL texture back to memory.\n");
346 ENTER_GL();
347 glGetIntegerv(GL_TEXTURE_BINDING_2D, &cur_tex);
348 glBindTexture(GL_TEXTURE_2D, glThis->tex_name);
349 gltex_download_texture(This);
350 glBindTexture(GL_TEXTURE_2D, cur_tex);
351 LEAVE_GL();
354 glThis->dirty_flag = SURFACE_MEMORY_DIRTY;
355 *(glThis->global_dirty_flag) = SURFACE_MEMORY_DIRTY;
356 /* TODO: check color-keying on mipmapped surfaces... */
358 return DD_OK;
361 HRESULT
362 gltex_blt(IDirectDrawSurfaceImpl *This, LPRECT rdst,
363 LPDIRECTDRAWSURFACE7 src, LPRECT rsrc,
364 DWORD dwFlags, LPDDBLTFX lpbltfx)
366 if (src != NULL) {
367 IDirectDrawSurfaceImpl *src_ptr = ICOM_OBJECT(IDirectDrawSurfaceImpl, IDirectDrawSurface7, src);
368 if (src_ptr->surface_desc.ddsCaps.dwCaps & DDSCAPS_3DDEVICE) {
369 FIXME("Blt from framebuffer to texture - unsupported now, please report !\n");
372 return DDERR_INVALIDPARAMS;
375 HRESULT
376 gltex_bltfast(IDirectDrawSurfaceImpl *surf_ptr, DWORD dstx,
377 DWORD dsty, LPDIRECTDRAWSURFACE7 src,
378 LPRECT rsrc, DWORD trans)
380 if (src != NULL) {
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. */
386 RECT rsrc2;
387 DWORD width, height;
388 GLuint cur_tex;
389 IDirect3DTextureGLImpl *gl_surf_ptr = surf_ptr->tex_private;
390 int y;
392 if (rsrc == NULL) {
393 WARN("rsrc is NULL\n");
394 rsrc = &rsrc2;
396 rsrc->left = 0;
397 rsrc->top = 0;
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)) {
412 return DD_OK;
415 TRACE(" direct frame buffer => texture BltFast override.\n");
417 ENTER_GL();
419 glGetIntegerv(GL_TEXTURE_BINDING_2D, &cur_tex);
420 /* This call is to create the actual texture name in GL (as we do 'late' ID creation) */
421 gltex_get_tex_name(surf_ptr);
422 glBindTexture(GL_TEXTURE_2D, gl_surf_ptr->tex_name);
424 if ((gl_surf_ptr->dirty_flag == SURFACE_MEMORY_DIRTY) &&
425 !((dstx == 0) && (dsty == 0) &&
426 (width == surf_ptr->surface_desc.dwWidth) && (height == surf_ptr->surface_desc.dwHeight))) {
427 /* If not 'full size' and the surface is dirty, first flush it to GL before doing the copy. */
428 if (upload_surface_to_tex_memory_init(surf_ptr, surf_ptr->mipmap_level, &(gl_surf_ptr->current_internal_format),
429 gl_surf_ptr->initial_upload_done == FALSE, TRUE, 0, 0) == DD_OK) {
430 upload_surface_to_tex_memory(NULL, 0, 0, &(gl_surf_ptr->surface_ptr));
431 upload_surface_to_tex_memory_release();
432 gl_surf_ptr->dirty_flag = SURFACE_MEMORY;
433 gl_surf_ptr->initial_upload_done = TRUE;
434 } else {
435 glBindTexture(GL_TEXTURE_2D, cur_tex);
436 LEAVE_GL();
437 ERR("Error at texture upload !\n");
438 return DDERR_INVALIDPARAMS;
442 /* This is a hack and would need some clean-up :-) */
443 if (gl_surf_ptr->initial_upload_done == FALSE) {
444 if (upload_surface_to_tex_memory_init(surf_ptr, surf_ptr->mipmap_level, &(gl_surf_ptr->current_internal_format),
445 TRUE, TRUE, 0, 0) == DD_OK) {
446 upload_surface_to_tex_memory(NULL, 0, 0, &(gl_surf_ptr->surface_ptr));
447 upload_surface_to_tex_memory_release();
448 gl_surf_ptr->dirty_flag = SURFACE_MEMORY;
449 gl_surf_ptr->initial_upload_done = TRUE;
450 } else {
451 glBindTexture(GL_TEXTURE_2D, cur_tex);
452 LEAVE_GL();
453 ERR("Error at texture upload (initial case) !\n");
454 return DDERR_INVALIDPARAMS;
458 if ((src_ptr->surface_desc.ddsCaps.dwCaps & (DDSCAPS_FRONTBUFFER|DDSCAPS_PRIMARYSURFACE)) != 0)
459 glReadBuffer(GL_FRONT);
460 else if ((src_ptr->surface_desc.ddsCaps.dwCaps & (DDSCAPS_BACKBUFFER)) == (DDSCAPS_BACKBUFFER))
461 glReadBuffer(GL_BACK);
462 else {
463 ERR("Wrong surface type for locking !\n");
464 glBindTexture(GL_TEXTURE_2D, cur_tex);
465 LEAVE_GL();
466 return DDERR_INVALIDPARAMS;
469 for (y = (src_ptr->surface_desc.dwHeight - rsrc->top - 1);
470 y >= (src_ptr->surface_desc.dwHeight - (rsrc->top + height));
471 y--) {
472 glCopyTexSubImage2D(GL_TEXTURE_2D, surf_ptr->mipmap_level,
473 dstx, dsty,
474 rsrc->left, y,
475 width, 1);
476 dsty++;
479 glBindTexture(GL_TEXTURE_2D, cur_tex);
480 LEAVE_GL();
482 /* The SURFACE_GL case is not handled by the 'global' dirty flag */
483 gl_surf_ptr->dirty_flag = SURFACE_GL;
485 return DD_OK;
488 return DDERR_INVALIDPARAMS;
491 HRESULT WINAPI
492 Main_IDirect3DTextureImpl_2_1T_PaletteChanged(LPDIRECT3DTEXTURE2 iface,
493 DWORD dwStart,
494 DWORD dwCount)
496 ICOM_THIS_FROM(IDirectDrawSurfaceImpl, IDirect3DTexture2, iface);
497 FIXME("(%p/%p)->(%08lx,%08lx): stub!\n", This, iface, dwStart, dwCount);
498 return DD_OK;
501 HRESULT WINAPI
502 Main_IDirect3DTextureImpl_1_Unload(LPDIRECT3DTEXTURE iface)
504 ICOM_THIS_FROM(IDirectDrawSurfaceImpl, IDirect3DTexture, iface);
505 FIXME("(%p/%p)->(): stub!\n", This, iface);
506 return DD_OK;
509 HRESULT WINAPI
510 Main_IDirect3DTextureImpl_2_1T_GetHandle(LPDIRECT3DTEXTURE2 iface,
511 LPDIRECT3DDEVICE2 lpDirect3DDevice2,
512 LPD3DTEXTUREHANDLE lpHandle)
514 ICOM_THIS_FROM(IDirectDrawSurfaceImpl, IDirect3DTexture2, iface);
515 IDirect3DDeviceImpl *lpDeviceImpl = ICOM_OBJECT(IDirect3DDeviceImpl, IDirect3DDevice2, lpDirect3DDevice2);
517 TRACE("(%p/%p)->(%p,%p)\n", This, iface, lpDirect3DDevice2, lpHandle);
519 /* The handle is simply the pointer to the implementation structure */
520 *lpHandle = (D3DTEXTUREHANDLE) This;
522 TRACE(" returning handle %08lx.\n", *lpHandle);
524 /* Now set the device for this texture */
525 This->d3ddevice = lpDeviceImpl;
527 return D3D_OK;
530 HRESULT WINAPI
531 Main_IDirect3DTextureImpl_2_1T_Load(LPDIRECT3DTEXTURE2 iface,
532 LPDIRECT3DTEXTURE2 lpD3DTexture2)
534 ICOM_THIS_FROM(IDirectDrawSurfaceImpl, IDirect3DTexture2, iface);
535 FIXME("(%p/%p)->(%p): stub!\n", This, iface, lpD3DTexture2);
536 return DD_OK;
539 static void gltex_set_palette(IDirectDrawSurfaceImpl* This, IDirectDrawPaletteImpl* pal)
541 IDirect3DTextureGLImpl *glThis = (IDirect3DTextureGLImpl *) This->tex_private;
543 if (glThis->dirty_flag == SURFACE_GL) {
544 GLuint cur_tex;
546 TRACE(" flushing GL texture back to memory.\n");
548 ENTER_GL();
549 glGetIntegerv(GL_TEXTURE_BINDING_2D, &cur_tex);
550 glBindTexture(GL_TEXTURE_2D, glThis->tex_name);
551 gltex_download_texture(This);
552 glBindTexture(GL_TEXTURE_2D, cur_tex);
553 LEAVE_GL();
556 /* First call the previous set_palette function */
557 glThis->set_palette(This, pal);
559 /* And set the dirty flag */
560 glThis->dirty_flag = SURFACE_MEMORY_DIRTY;
561 *(glThis->global_dirty_flag) = SURFACE_MEMORY_DIRTY;
563 /* TODO: check palette on mipmapped surfaces...
564 TODO: do we need to re-upload in case of usage of the paletted texture extension ? */
567 static void
568 gltex_final_release(IDirectDrawSurfaceImpl *This)
570 IDirect3DTextureGLImpl *glThis = (IDirect3DTextureGLImpl *) This->tex_private;
571 DWORD mem_used;
572 int i;
574 TRACE(" deleting texture with GL id %d.\n", glThis->tex_name);
576 /* And delete texture handle */
577 ENTER_GL();
578 if (glThis->tex_name != 0)
579 glDeleteTextures(1, &(glThis->tex_name));
580 LEAVE_GL();
582 HeapFree(GetProcessHeap(), 0, glThis->surface_ptr);
584 /* And if this texture was the current one, remove it at the device level */
585 if (This->d3ddevice != NULL)
586 for (i = 0; i < MAX_TEXTURES; i++)
587 if (This->d3ddevice->current_texture[i] == This)
588 This->d3ddevice->current_texture[i] = NULL;
590 /* All this should be part of main surface management not just a hack for texture.. */
591 if (glThis->loaded) {
592 mem_used = This->surface_desc.dwHeight *
593 This->surface_desc.u1.lPitch;
594 This->ddraw_owner->free_memory(This->ddraw_owner, mem_used);
597 glThis->final_release(This);
600 static void
601 gltex_lock_update(IDirectDrawSurfaceImpl* This, LPCRECT pRect, DWORD dwFlags)
603 IDirect3DTextureGLImpl *glThis = (IDirect3DTextureGLImpl *) This->tex_private;
605 glThis->lock_update(This, pRect, dwFlags);
608 static void
609 gltex_unlock_update(IDirectDrawSurfaceImpl* This, LPCRECT pRect)
611 IDirect3DTextureGLImpl *glThis = (IDirect3DTextureGLImpl *) This->tex_private;
613 glThis->unlock_update(This, pRect);
615 /* Set the dirty flag according to the lock type */
616 if ((This->lastlocktype & DDLOCK_READONLY) == 0) {
617 glThis->dirty_flag = SURFACE_MEMORY_DIRTY;
618 *(glThis->global_dirty_flag) = SURFACE_MEMORY_DIRTY;
622 HRESULT WINAPI
623 GL_IDirect3DTextureImpl_2_1T_Load(LPDIRECT3DTEXTURE2 iface,
624 LPDIRECT3DTEXTURE2 lpD3DTexture2)
626 ICOM_THIS_FROM(IDirectDrawSurfaceImpl, IDirect3DTexture2, iface);
627 IDirectDrawSurfaceImpl *src_ptr = ICOM_OBJECT(IDirectDrawSurfaceImpl, IDirect3DTexture2, lpD3DTexture2);
628 IDirectDrawSurfaceImpl *dst_ptr = This;
629 HRESULT ret_value = D3D_OK;
631 TRACE("(%p/%p)->(%p)\n", This, iface, lpD3DTexture2);
633 if (((src_ptr->surface_desc.ddsCaps.dwCaps & DDSCAPS_MIPMAP) != (dst_ptr->surface_desc.ddsCaps.dwCaps & DDSCAPS_MIPMAP)) ||
634 (src_ptr->surface_desc.u2.dwMipMapCount != dst_ptr->surface_desc.u2.dwMipMapCount)) {
635 ERR("Trying to load surfaces with different mip-map counts !\n");
638 /* Now loop through all mipmap levels and load all of them... */
639 while (1) {
640 IDirect3DTextureGLImpl *gl_dst_ptr = (IDirect3DTextureGLImpl *) dst_ptr->tex_private;
641 DDSURFACEDESC *src_d, *dst_d;
643 if (gl_dst_ptr != NULL) {
644 if (gl_dst_ptr->loaded == FALSE) {
645 /* Only check memory for not already loaded texture... */
646 DWORD mem_used;
647 if (dst_ptr->surface_desc.u4.ddpfPixelFormat.dwFlags & DDPF_FOURCC)
648 mem_used = dst_ptr->surface_desc.u1.dwLinearSize;
649 else
650 mem_used = dst_ptr->surface_desc.dwHeight * dst_ptr->surface_desc.u1.lPitch;
651 if (This->ddraw_owner->allocate_memory(This->ddraw_owner, mem_used) < 0) {
652 TRACE(" out of virtual memory... Warning application.\n");
653 return D3DERR_TEXTURE_LOAD_FAILED;
656 gl_dst_ptr->loaded = TRUE;
659 TRACE(" copying surface %p to surface %p (mipmap level %d)\n", src_ptr, dst_ptr, src_ptr->mipmap_level);
661 if ( dst_ptr->surface_desc.ddsCaps.dwCaps & DDSCAPS_ALLOCONLOAD )
662 /* If the surface is not allocated and its location is not yet specified,
663 force it to video memory */
664 if ( !(dst_ptr->surface_desc.ddsCaps.dwCaps & (DDSCAPS_SYSTEMMEMORY|DDSCAPS_VIDEOMEMORY)) )
665 dst_ptr->surface_desc.ddsCaps.dwCaps |= DDSCAPS_VIDEOMEMORY;
667 /* Suppress the ALLOCONLOAD flag */
668 dst_ptr->surface_desc.ddsCaps.dwCaps &= ~DDSCAPS_ALLOCONLOAD;
670 /* After seeing some logs, not sure at all about this... */
671 if (dst_ptr->palette == NULL) {
672 dst_ptr->palette = src_ptr->palette;
673 if (src_ptr->palette != NULL) IDirectDrawPalette_AddRef(ICOM_INTERFACE(src_ptr->palette, IDirectDrawPalette));
674 } else {
675 if (src_ptr->palette != NULL) {
676 PALETTEENTRY palent[256];
677 IDirectDrawPalette_GetEntries(ICOM_INTERFACE(src_ptr->palette, IDirectDrawPalette),
678 0, 0, 256, palent);
679 IDirectDrawPalette_SetEntries(ICOM_INTERFACE(dst_ptr->palette, IDirectDrawPalette),
680 0, 0, 256, palent);
684 /* Copy one surface on the other */
685 dst_d = (DDSURFACEDESC *)&(dst_ptr->surface_desc);
686 src_d = (DDSURFACEDESC *)&(src_ptr->surface_desc);
688 if ((src_d->dwWidth != dst_d->dwWidth) || (src_d->dwHeight != dst_d->dwHeight)) {
689 /* Should also check for same pixel format, u1.lPitch, ... */
690 ERR("Error in surface sizes\n");
691 return D3DERR_TEXTURE_LOAD_FAILED;
692 } else {
693 /* LPDIRECT3DDEVICE2 d3dd = (LPDIRECT3DDEVICE2) This->D3Ddevice; */
694 /* I should put a macro for the calculus of bpp */
696 /* Copy also the ColorKeying stuff */
697 if (src_d->dwFlags & DDSD_CKSRCBLT) {
698 dst_d->dwFlags |= DDSD_CKSRCBLT;
699 dst_d->ddckCKSrcBlt.dwColorSpaceLowValue = src_d->ddckCKSrcBlt.dwColorSpaceLowValue;
700 dst_d->ddckCKSrcBlt.dwColorSpaceHighValue = src_d->ddckCKSrcBlt.dwColorSpaceHighValue;
703 /* Copy the main memory texture into the surface that corresponds to the OpenGL
704 texture object. */
705 if (dst_ptr->surface_desc.u4.ddpfPixelFormat.dwFlags & DDPF_FOURCC)
706 memcpy(dst_d->lpSurface, src_d->lpSurface, src_ptr->surface_desc.u1.dwLinearSize);
707 else
708 memcpy(dst_d->lpSurface, src_d->lpSurface, src_d->u1.lPitch * src_d->dwHeight);
710 if (gl_dst_ptr != NULL) {
711 /* Set this texture as dirty */
712 gl_dst_ptr->dirty_flag = SURFACE_MEMORY_DIRTY;
713 *(gl_dst_ptr->global_dirty_flag) = SURFACE_MEMORY_DIRTY;
717 if (src_ptr->surface_desc.ddsCaps.dwCaps & DDSCAPS_MIPMAP) {
718 src_ptr = get_sub_mimaplevel(src_ptr);
719 } else {
720 src_ptr = NULL;
722 if (dst_ptr->surface_desc.ddsCaps.dwCaps & DDSCAPS_MIPMAP) {
723 dst_ptr = get_sub_mimaplevel(dst_ptr);
724 } else {
725 dst_ptr = NULL;
728 if ((src_ptr == NULL) || (dst_ptr == NULL)) {
729 if (src_ptr != dst_ptr) {
730 ERR(" Loading surface with different mipmap structure !!!\n");
732 break;
736 return ret_value;
739 HRESULT WINAPI
740 Thunk_IDirect3DTextureImpl_2_QueryInterface(LPDIRECT3DTEXTURE2 iface,
741 REFIID riid,
742 LPVOID* obp)
744 TRACE("(%p)->(%s,%p) thunking to IDirectDrawSurface7 interface.\n", iface, debugstr_guid(riid), obp);
745 return IDirectDrawSurface7_QueryInterface(COM_INTERFACE_CAST(IDirectDrawSurfaceImpl, IDirect3DTexture2, IDirectDrawSurface7, iface),
746 riid,
747 obp);
750 ULONG WINAPI
751 Thunk_IDirect3DTextureImpl_2_AddRef(LPDIRECT3DTEXTURE2 iface)
753 TRACE("(%p)->() thunking to IDirectDrawSurface7 interface.\n", iface);
754 return IDirectDrawSurface7_AddRef(COM_INTERFACE_CAST(IDirectDrawSurfaceImpl, IDirect3DTexture2, IDirectDrawSurface7, iface));
757 ULONG WINAPI
758 Thunk_IDirect3DTextureImpl_2_Release(LPDIRECT3DTEXTURE2 iface)
760 TRACE("(%p)->() thunking to IDirectDrawSurface7 interface.\n", iface);
761 return IDirectDrawSurface7_Release(COM_INTERFACE_CAST(IDirectDrawSurfaceImpl, IDirect3DTexture2, IDirectDrawSurface7, iface));
764 HRESULT WINAPI
765 Thunk_IDirect3DTextureImpl_1_QueryInterface(LPDIRECT3DTEXTURE iface,
766 REFIID riid,
767 LPVOID* obp)
769 TRACE("(%p)->(%s,%p) thunking to IDirectDrawSurface7 interface.\n", iface, debugstr_guid(riid), obp);
770 return IDirectDrawSurface7_QueryInterface(COM_INTERFACE_CAST(IDirectDrawSurfaceImpl, IDirect3DTexture, IDirectDrawSurface7, iface),
771 riid,
772 obp);
775 ULONG WINAPI
776 Thunk_IDirect3DTextureImpl_1_AddRef(LPDIRECT3DTEXTURE iface)
778 TRACE("(%p)->() thunking to IDirectDrawSurface7 interface.\n", iface);
779 return IDirectDrawSurface7_AddRef(COM_INTERFACE_CAST(IDirectDrawSurfaceImpl, IDirect3DTexture, IDirectDrawSurface7, iface));
782 ULONG WINAPI
783 Thunk_IDirect3DTextureImpl_1_Release(LPDIRECT3DTEXTURE iface)
785 TRACE("(%p)->() thunking to IDirectDrawSurface7 interface.\n", iface);
786 return IDirectDrawSurface7_Release(COM_INTERFACE_CAST(IDirectDrawSurfaceImpl, IDirect3DTexture, IDirectDrawSurface7, iface));
789 HRESULT WINAPI
790 Thunk_IDirect3DTextureImpl_1_PaletteChanged(LPDIRECT3DTEXTURE iface,
791 DWORD dwStart,
792 DWORD dwCount)
794 TRACE("(%p)->(%08lx,%08lx) thunking to IDirect3DTexture2 interface.\n", iface, dwStart, dwCount);
795 return IDirect3DTexture2_PaletteChanged(COM_INTERFACE_CAST(IDirectDrawSurfaceImpl, IDirect3DTexture, IDirect3DTexture2, iface),
796 dwStart,
797 dwCount);
800 HRESULT WINAPI
801 Thunk_IDirect3DTextureImpl_1_GetHandle(LPDIRECT3DTEXTURE iface,
802 LPDIRECT3DDEVICE lpDirect3DDevice,
803 LPD3DTEXTUREHANDLE lpHandle)
805 TRACE("(%p)->(%p,%p) thunking to IDirect3DTexture2 interface.\n", iface, lpDirect3DDevice, lpHandle);
806 return IDirect3DTexture2_GetHandle(COM_INTERFACE_CAST(IDirectDrawSurfaceImpl, IDirect3DTexture, IDirect3DTexture2, iface),
807 COM_INTERFACE_CAST(IDirect3DDeviceImpl, IDirect3DDevice, IDirect3DDevice2, lpDirect3DDevice),
808 lpHandle);
811 HRESULT WINAPI
812 Thunk_IDirect3DTextureImpl_1_Load(LPDIRECT3DTEXTURE iface,
813 LPDIRECT3DTEXTURE lpD3DTexture)
815 TRACE("(%p)->(%p) thunking to IDirect3DTexture2 interface.\n", iface, lpD3DTexture);
816 return IDirect3DTexture2_Load(COM_INTERFACE_CAST(IDirectDrawSurfaceImpl, IDirect3DTexture, IDirect3DTexture2, iface),
817 COM_INTERFACE_CAST(IDirectDrawSurfaceImpl, IDirect3DTexture, IDirect3DTexture2, lpD3DTexture));
820 #if !defined(__STRICT_ANSI__) && defined(__GNUC__)
821 # define XCAST(fun) (typeof(VTABLE_IDirect3DTexture2.fun))
822 #else
823 # define XCAST(fun) (void*)
824 #endif
826 IDirect3DTexture2Vtbl VTABLE_IDirect3DTexture2 =
828 XCAST(QueryInterface) Thunk_IDirect3DTextureImpl_2_QueryInterface,
829 XCAST(AddRef) Thunk_IDirect3DTextureImpl_2_AddRef,
830 XCAST(Release) Thunk_IDirect3DTextureImpl_2_Release,
831 XCAST(GetHandle) Main_IDirect3DTextureImpl_2_1T_GetHandle,
832 XCAST(PaletteChanged) Main_IDirect3DTextureImpl_2_1T_PaletteChanged,
833 XCAST(Load) GL_IDirect3DTextureImpl_2_1T_Load,
836 #if !defined(__STRICT_ANSI__) && defined(__GNUC__)
837 #undef XCAST
838 #endif
841 #if !defined(__STRICT_ANSI__) && defined(__GNUC__)
842 # define XCAST(fun) (typeof(VTABLE_IDirect3DTexture.fun))
843 #else
844 # define XCAST(fun) (void*)
845 #endif
847 IDirect3DTextureVtbl VTABLE_IDirect3DTexture =
849 XCAST(QueryInterface) Thunk_IDirect3DTextureImpl_1_QueryInterface,
850 XCAST(AddRef) Thunk_IDirect3DTextureImpl_1_AddRef,
851 XCAST(Release) Thunk_IDirect3DTextureImpl_1_Release,
852 XCAST(Initialize) Main_IDirect3DTextureImpl_1_Initialize,
853 XCAST(GetHandle) Thunk_IDirect3DTextureImpl_1_GetHandle,
854 XCAST(PaletteChanged) Thunk_IDirect3DTextureImpl_1_PaletteChanged,
855 XCAST(Load) Thunk_IDirect3DTextureImpl_1_Load,
856 XCAST(Unload) Main_IDirect3DTextureImpl_1_Unload,
859 #if !defined(__STRICT_ANSI__) && defined(__GNUC__)
860 #undef XCAST
861 #endif
863 HRESULT d3dtexture_create(IDirectDrawImpl *d3d, IDirectDrawSurfaceImpl *surf, BOOLEAN at_creation,
864 IDirectDrawSurfaceImpl *main)
866 /* First, initialize the texture vtables... */
867 ICOM_INIT_INTERFACE(surf, IDirect3DTexture, VTABLE_IDirect3DTexture);
868 ICOM_INIT_INTERFACE(surf, IDirect3DTexture2, VTABLE_IDirect3DTexture2);
870 /* Only create all the private stuff if we actually have an OpenGL context.. */
871 if (d3d->current_device != NULL) {
872 IDirect3DTextureGLImpl *private;
874 private = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IDirect3DTextureGLImpl));
875 if (private == NULL) return DDERR_OUTOFMEMORY;
877 surf->tex_private = private;
879 private->final_release = surf->final_release;
880 private->lock_update = surf->lock_update;
881 private->unlock_update = surf->unlock_update;
882 private->set_palette = surf->set_palette;
884 /* If at creation, we can optimize stuff and wait the first 'unlock' to upload a valid stuff to OpenGL.
885 Otherwise, it will be uploaded here (and may be invalid). */
886 surf->final_release = gltex_final_release;
887 surf->lock_update = gltex_lock_update;
888 surf->unlock_update = gltex_unlock_update;
889 surf->aux_setcolorkey_cb = gltex_setcolorkey_cb;
890 surf->set_palette = gltex_set_palette;
892 /* We are the only one to use the aux_blt and aux_bltfast overrides, so no need
893 to save those... */
894 surf->aux_blt = gltex_blt;
895 surf->aux_bltfast = gltex_bltfast;
897 TRACE(" GL texture created for surface %p (private data at %p)\n", surf, private);
899 /* Do not create the OpenGL texture id here as some game generate textures from a different thread which
900 cause problems.. */
901 private->tex_name = 0;
902 if (surf->mipmap_level == 0) {
903 private->main = NULL;
904 private->global_dirty_flag = &(private->__global_dirty_flag);
905 } else {
906 private->main = main;
907 private->global_dirty_flag = &(((IDirect3DTextureGLImpl *) (private->main->tex_private))->__global_dirty_flag);
909 private->initial_upload_done = FALSE;
912 return D3D_OK;
915 GLuint gltex_get_tex_name(IDirectDrawSurfaceImpl *surf)
917 IDirect3DTextureGLImpl *private = (IDirect3DTextureGLImpl *) (surf->tex_private);
919 if (private->tex_name == 0) {
920 /* The texture was not created yet... */
921 ENTER_GL();
922 if (surf->mipmap_level == 0) {
923 glGenTextures(1, &(private->tex_name));
924 if (private->tex_name == 0) ERR("Error at creation of OpenGL texture ID !\n");
925 TRACE(" GL texture id is : %d.\n", private->tex_name);
926 private->__global_dirty_flag = SURFACE_MEMORY_DIRTY;
927 } else {
928 private->tex_name = gltex_get_tex_name(private->main);
929 TRACE(" GL texture id reusing id %d from surface %p (private at %p)).\n", private->tex_name, private->main, private->main->tex_private);
931 LEAVE_GL();
933 /* And set the dirty flag accordingly */
934 private->dirty_flag = SURFACE_MEMORY_DIRTY;
936 return ((IDirect3DTextureGLImpl *) (surf->tex_private))->tex_name;