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