| /* Direct3D Texture |
| * Copyright (c) 1998 Lionel ULMER |
| * |
| * This file contains the implementation of interface Direct3DTexture2. |
| * |
| * This library is free software; you can redistribute it and/or |
| * modify it under the terms of the GNU Lesser General Public |
| * License as published by the Free Software Foundation; either |
| * version 2.1 of the License, or (at your option) any later version. |
| * |
| * This library is distributed in the hope that it will be useful, |
| * but WITHOUT ANY WARRANTY; without even the implied warranty of |
| * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
| * Lesser General Public License for more details. |
| * |
| * You should have received a copy of the GNU Lesser General Public |
| * License along with this library; if not, write to the Free Software |
| * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
| */ |
| |
| #include "config.h" |
| |
| #include <stdarg.h> |
| #include <string.h> |
| |
| #define NONAMELESSUNION |
| #define NONAMELESSSTRUCT |
| #include "windef.h" |
| #include "winbase.h" |
| #include "winerror.h" |
| #include "objbase.h" |
| #include "wingdi.h" |
| #include "ddraw.h" |
| #include "d3d.h" |
| #include "wine/debug.h" |
| |
| #include "mesa_private.h" |
| |
| WINE_DEFAULT_DEBUG_CHANNEL(ddraw); |
| WINE_DECLARE_DEBUG_CHANNEL(ddraw_tex); |
| |
| #include <stdio.h> |
| |
| static void |
| snoop_texture(IDirectDrawSurfaceImpl *This) { |
| IDirect3DTextureGLImpl *glThis = (IDirect3DTextureGLImpl *) This->tex_private; |
| char buf[128]; |
| FILE *f; |
| |
| TRACE_(ddraw_tex)("Dumping surface id (%5d) level (%2d) : \n", glThis->tex_name, This->mipmap_level); |
| DDRAW_dump_surface_desc(&(This->surface_desc)); |
| |
| sprintf(buf, "tex_%05d_%02d.pnm", glThis->tex_name, This->mipmap_level); |
| f = fopen(buf, "wb"); |
| DDRAW_dump_surface_to_disk(This, f); |
| } |
| |
| static IDirectDrawSurfaceImpl * |
| get_sub_mimaplevel(IDirectDrawSurfaceImpl *tex_ptr) |
| { |
| /* Now go down the mipmap chain to the next surface */ |
| static const DDSCAPS2 mipmap_caps = { DDSCAPS_MIPMAP | DDSCAPS_TEXTURE, 0, 0, 0 }; |
| LPDIRECTDRAWSURFACE7 next_level; |
| IDirectDrawSurfaceImpl *surf_ptr; |
| HRESULT hr; |
| |
| hr = IDirectDrawSurface7_GetAttachedSurface(ICOM_INTERFACE(tex_ptr, IDirectDrawSurface7), |
| (DDSCAPS2 *) &mipmap_caps, &next_level); |
| if (FAILED(hr)) return NULL; |
| |
| surf_ptr = ICOM_OBJECT(IDirectDrawSurfaceImpl, IDirectDrawSurface7, next_level); |
| IDirectDrawSurface7_Release(next_level); |
| |
| return surf_ptr; |
| } |
| |
| /******************************************************************************* |
| * IDirectSurface callback methods |
| */ |
| |
| HRESULT |
| gltex_download_texture(IDirectDrawSurfaceImpl *surf_ptr) { |
| IDirect3DTextureGLImpl *gl_surf_ptr = (IDirect3DTextureGLImpl *) surf_ptr->tex_private; |
| |
| FIXME("This is not supported yet... Expect some graphical glitches !!!\n"); |
| |
| /* GL and memory are in sync again ... |
| No need to change the 'global' flag as it only handles the 'MEMORY_DIRTY' case. |
| */ |
| gl_surf_ptr->dirty_flag = SURFACE_MEMORY; |
| |
| return DD_OK; |
| } |
| |
| static GLenum |
| convert_min_filter_to_GL(D3DTEXTUREMINFILTER dwMinState, D3DTEXTUREMIPFILTER dwMipState) |
| { |
| GLenum gl_state; |
| |
| if (dwMipState == D3DTFP_NONE) { |
| switch (dwMinState) { |
| case D3DTFN_POINT: gl_state = GL_NEAREST; break; |
| case D3DTFN_LINEAR: gl_state = GL_LINEAR; break; |
| default: gl_state = GL_LINEAR; break; |
| } |
| } else if (dwMipState == D3DTFP_POINT) { |
| switch (dwMinState) { |
| case D3DTFN_POINT: gl_state = GL_NEAREST_MIPMAP_NEAREST; break; |
| case D3DTFN_LINEAR: gl_state = GL_LINEAR_MIPMAP_NEAREST; break; |
| default: gl_state = GL_LINEAR_MIPMAP_NEAREST; break; |
| } |
| } else { |
| switch (dwMinState) { |
| case D3DTFN_POINT: gl_state = GL_NEAREST_MIPMAP_LINEAR; break; |
| case D3DTFN_LINEAR: gl_state = GL_LINEAR_MIPMAP_LINEAR; break; |
| default: gl_state = GL_LINEAR_MIPMAP_LINEAR; break; |
| } |
| } |
| return gl_state; |
| } |
| |
| static GLenum |
| convert_mag_filter_to_GL(D3DTEXTUREMAGFILTER dwState) |
| { |
| GLenum gl_state; |
| |
| switch (dwState) { |
| case D3DTFG_POINT: |
| gl_state = GL_NEAREST; |
| break; |
| case D3DTFG_LINEAR: |
| gl_state = GL_LINEAR; |
| break; |
| default: |
| gl_state = GL_LINEAR; |
| break; |
| } |
| return gl_state; |
| } |
| |
| static GLenum |
| convert_tex_address_to_GL(D3DTEXTUREADDRESS dwState) |
| { |
| GLenum gl_state; |
| switch (dwState) { |
| case D3DTADDRESS_WRAP: gl_state = GL_REPEAT; break; |
| case D3DTADDRESS_CLAMP: gl_state = GL_CLAMP; break; |
| case D3DTADDRESS_BORDER: gl_state = GL_CLAMP_TO_EDGE; break; |
| case D3DTADDRESS_MIRROR: |
| if (GL_extensions.mirrored_repeat == TRUE) { |
| gl_state = GL_MIRRORED_REPEAT_WINE; |
| } else { |
| gl_state = GL_REPEAT; |
| /* This is a TRACE instead of a FIXME as the FIXME was already printed when the game |
| actually set D3DTADDRESS_MIRROR. |
| */ |
| TRACE(" setting GL_REPEAT instead of GL_MIRRORED_REPEAT.\n"); |
| } |
| break; |
| default: gl_state = GL_REPEAT; break; |
| } |
| return gl_state; |
| } |
| |
| HRESULT |
| gltex_upload_texture(IDirectDrawSurfaceImpl *surf_ptr, IDirect3DDeviceImpl *d3ddev, DWORD stage) { |
| IDirect3DTextureGLImpl *gl_surf_ptr = (IDirect3DTextureGLImpl *) surf_ptr->tex_private; |
| IDirect3DDeviceGLImpl *gl_d3ddev = (IDirect3DDeviceGLImpl *) d3ddev; |
| BOOLEAN changed = FALSE; |
| GLenum unit = GL_TEXTURE0_WINE + stage; |
| |
| if (surf_ptr->mipmap_level != 0) { |
| WARN(" application activating a sub-level of the mipmapping chain (level %d) !\n", surf_ptr->mipmap_level); |
| } |
| |
| /* Now check if the texture parameters for this texture are still in-line with what D3D expect |
| us to do.. |
| |
| NOTE: there is no check for the situation where the same texture is bound to multiple stage |
| but with different parameters per stage. |
| */ |
| if ((gl_surf_ptr->tex_parameters == NULL) || |
| (gl_surf_ptr->tex_parameters[D3DTSS_MAXMIPLEVEL - D3DTSS_ADDRESSU] != |
| d3ddev->state_block.texture_stage_state[stage][D3DTSS_MAXMIPLEVEL - 1])) { |
| DWORD max_mip_level; |
| |
| if ((surf_ptr->surface_desc.ddsCaps.dwCaps & DDSCAPS_MIPMAP) == 0) { |
| max_mip_level = 0; |
| } else { |
| max_mip_level = surf_ptr->surface_desc.u2.dwMipMapCount - 1; |
| if (d3ddev->state_block.texture_stage_state[stage][D3DTSS_MAXMIPLEVEL - 1] != 0) { |
| if (max_mip_level >= d3ddev->state_block.texture_stage_state[stage][D3DTSS_MAXMIPLEVEL - 1]) { |
| max_mip_level = d3ddev->state_block.texture_stage_state[stage][D3DTSS_MAXMIPLEVEL - 1] - 1; |
| } |
| } |
| } |
| if (unit != gl_d3ddev->current_active_tex_unit) { |
| GL_extensions.glActiveTexture(unit); |
| gl_d3ddev->current_active_tex_unit = unit; |
| } |
| glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, max_mip_level); |
| changed = TRUE; |
| } |
| |
| if ((gl_surf_ptr->tex_parameters == NULL) || |
| (gl_surf_ptr->tex_parameters[D3DTSS_MAGFILTER - D3DTSS_ADDRESSU] != |
| d3ddev->state_block.texture_stage_state[stage][D3DTSS_MAGFILTER - 1])) { |
| if (unit != gl_d3ddev->current_active_tex_unit) { |
| GL_extensions.glActiveTexture(unit); |
| gl_d3ddev->current_active_tex_unit = unit; |
| } |
| glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, |
| convert_mag_filter_to_GL(d3ddev->state_block.texture_stage_state[stage][D3DTSS_MAGFILTER - 1])); |
| changed = TRUE; |
| } |
| if ((gl_surf_ptr->tex_parameters == NULL) || |
| (gl_surf_ptr->tex_parameters[D3DTSS_MINFILTER - D3DTSS_ADDRESSU] != |
| d3ddev->state_block.texture_stage_state[stage][D3DTSS_MINFILTER - 1]) || |
| (gl_surf_ptr->tex_parameters[D3DTSS_MIPFILTER - D3DTSS_ADDRESSU] != |
| d3ddev->state_block.texture_stage_state[stage][D3DTSS_MIPFILTER - 1])) { |
| if (unit != gl_d3ddev->current_active_tex_unit) { |
| GL_extensions.glActiveTexture(unit); |
| gl_d3ddev->current_active_tex_unit = unit; |
| } |
| glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, |
| convert_min_filter_to_GL(d3ddev->state_block.texture_stage_state[stage][D3DTSS_MINFILTER - 1], |
| d3ddev->state_block.texture_stage_state[stage][D3DTSS_MIPFILTER - 1])); |
| changed = TRUE; |
| } |
| if ((gl_surf_ptr->tex_parameters == NULL) || |
| (gl_surf_ptr->tex_parameters[D3DTSS_ADDRESSU - D3DTSS_ADDRESSU] != |
| d3ddev->state_block.texture_stage_state[stage][D3DTSS_ADDRESSU - 1])) { |
| if (unit != gl_d3ddev->current_active_tex_unit) { |
| GL_extensions.glActiveTexture(unit); |
| gl_d3ddev->current_active_tex_unit = unit; |
| } |
| glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, |
| convert_tex_address_to_GL(d3ddev->state_block.texture_stage_state[stage][D3DTSS_ADDRESSU - 1])); |
| changed = TRUE; |
| } |
| if ((gl_surf_ptr->tex_parameters == NULL) || |
| (gl_surf_ptr->tex_parameters[D3DTSS_ADDRESSV - D3DTSS_ADDRESSU] != |
| d3ddev->state_block.texture_stage_state[stage][D3DTSS_ADDRESSV - 1])) { |
| if (unit != gl_d3ddev->current_active_tex_unit) { |
| GL_extensions.glActiveTexture(unit); |
| gl_d3ddev->current_active_tex_unit = unit; |
| } |
| glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, |
| convert_tex_address_to_GL(d3ddev->state_block.texture_stage_state[stage][D3DTSS_ADDRESSV - 1])); |
| changed = TRUE; |
| } |
| if ((gl_surf_ptr->tex_parameters == NULL) || |
| (gl_surf_ptr->tex_parameters[D3DTSS_BORDERCOLOR - D3DTSS_ADDRESSU] != |
| d3ddev->state_block.texture_stage_state[stage][D3DTSS_BORDERCOLOR - 1])) { |
| GLfloat color[4]; |
| |
| color[0] = ((d3ddev->state_block.texture_stage_state[stage][D3DTSS_BORDERCOLOR - 1] >> 16) & 0xFF) / 255.0; |
| color[1] = ((d3ddev->state_block.texture_stage_state[stage][D3DTSS_BORDERCOLOR - 1] >> 8) & 0xFF) / 255.0; |
| color[2] = ((d3ddev->state_block.texture_stage_state[stage][D3DTSS_BORDERCOLOR - 1] >> 0) & 0xFF) / 255.0; |
| color[3] = ((d3ddev->state_block.texture_stage_state[stage][D3DTSS_BORDERCOLOR - 1] >> 24) & 0xFF) / 255.0; |
| if (unit != gl_d3ddev->current_active_tex_unit) { |
| GL_extensions.glActiveTexture(unit); |
| gl_d3ddev->current_active_tex_unit = unit; |
| } |
| glTexParameterfv(GL_TEXTURE_2D, GL_TEXTURE_BORDER_COLOR, color); |
| changed = TRUE; |
| } |
| |
| if (changed == TRUE) { |
| if (gl_surf_ptr->tex_parameters == NULL) { |
| gl_surf_ptr->tex_parameters = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, |
| sizeof(DWORD) * (D3DTSS_MAXMIPLEVEL + 1 - D3DTSS_ADDRESSU)); |
| } |
| memcpy(gl_surf_ptr->tex_parameters, &(d3ddev->state_block.texture_stage_state[stage][D3DTSS_ADDRESSU - 1]), |
| sizeof(DWORD) * (D3DTSS_MAXMIPLEVEL + 1 - D3DTSS_ADDRESSU)); |
| } |
| |
| if (*(gl_surf_ptr->global_dirty_flag) != SURFACE_MEMORY_DIRTY) { |
| TRACE(" nothing to do - memory copy and GL state in synch for all texture levels.\n"); |
| return DD_OK; |
| } |
| |
| while (surf_ptr != NULL) { |
| IDirect3DTextureGLImpl *gl_surf_ptr = (IDirect3DTextureGLImpl *) surf_ptr->tex_private; |
| |
| if (gl_surf_ptr->dirty_flag != SURFACE_MEMORY_DIRTY) { |
| TRACE(" - level %d already uploaded.\n", surf_ptr->mipmap_level); |
| } else { |
| TRACE(" - uploading texture level %d (initial done = %d).\n", |
| surf_ptr->mipmap_level, gl_surf_ptr->initial_upload_done); |
| |
| /* Texture snooping for the curious :-) */ |
| if (TRACE_ON(ddraw_tex)) { |
| snoop_texture(surf_ptr); |
| } |
| |
| if (unit != gl_d3ddev->current_active_tex_unit) { |
| GL_extensions.glActiveTexture(unit); |
| gl_d3ddev->current_active_tex_unit = unit; |
| } |
| |
| if (upload_surface_to_tex_memory_init(surf_ptr, surf_ptr->mipmap_level, &(gl_surf_ptr->current_internal_format), |
| gl_surf_ptr->initial_upload_done == FALSE, TRUE, 0, 0) == DD_OK) { |
| upload_surface_to_tex_memory(NULL, 0, 0, &(gl_surf_ptr->surface_ptr)); |
| upload_surface_to_tex_memory_release(); |
| gl_surf_ptr->dirty_flag = SURFACE_MEMORY; |
| gl_surf_ptr->initial_upload_done = TRUE; |
| } else { |
| ERR("Problem for upload of texture %d (level = %d / initial done = %d).\n", |
| gl_surf_ptr->tex_name, surf_ptr->mipmap_level, gl_surf_ptr->initial_upload_done); |
| } |
| } |
| |
| if (surf_ptr->surface_desc.ddsCaps.dwCaps & DDSCAPS_MIPMAP) { |
| surf_ptr = get_sub_mimaplevel(surf_ptr); |
| } else { |
| surf_ptr = NULL; |
| } |
| } |
| |
| *(gl_surf_ptr->global_dirty_flag) = SURFACE_MEMORY; |
| |
| return DD_OK; |
| } |
| |
| HRESULT WINAPI |
| Main_IDirect3DTextureImpl_1_Initialize(LPDIRECT3DTEXTURE iface, |
| LPDIRECT3DDEVICE lpDirect3DDevice, |
| LPDIRECTDRAWSURFACE lpDDSurface) |
| { |
| ICOM_THIS_FROM(IDirectDrawSurfaceImpl, IDirect3DTexture, iface); |
| FIXME("(%p/%p)->(%p,%p) no-op...\n", This, iface, lpDirect3DDevice, lpDDSurface); |
| return DD_OK; |
| } |
| |
| static HRESULT |
| gltex_setcolorkey_cb(IDirectDrawSurfaceImpl *This, DWORD dwFlags, LPDDCOLORKEY ckey ) |
| { |
| IDirect3DTextureGLImpl *glThis = (IDirect3DTextureGLImpl *) This->tex_private; |
| |
| if (glThis->dirty_flag == SURFACE_GL) { |
| GLuint cur_tex; |
| |
| TRACE(" flushing GL texture back to memory.\n"); |
| |
| ENTER_GL(); |
| glGetIntegerv(GL_TEXTURE_BINDING_2D, &cur_tex); |
| glBindTexture(GL_TEXTURE_2D, glThis->tex_name); |
| gltex_download_texture(This); |
| glBindTexture(GL_TEXTURE_2D, cur_tex); |
| LEAVE_GL(); |
| } |
| |
| glThis->dirty_flag = SURFACE_MEMORY_DIRTY; |
| *(glThis->global_dirty_flag) = SURFACE_MEMORY_DIRTY; |
| /* TODO: check color-keying on mipmapped surfaces... */ |
| |
| return DD_OK; |
| } |
| |
| HRESULT |
| gltex_blt(IDirectDrawSurfaceImpl *This, LPRECT rdst, |
| LPDIRECTDRAWSURFACE7 src, LPRECT rsrc, |
| DWORD dwFlags, LPDDBLTFX lpbltfx) |
| { |
| if (src != NULL) { |
| IDirectDrawSurfaceImpl *src_ptr = ICOM_OBJECT(IDirectDrawSurfaceImpl, IDirectDrawSurface7, src); |
| if (src_ptr->surface_desc.ddsCaps.dwCaps & DDSCAPS_3DDEVICE) { |
| FIXME("Blt from framebuffer to texture - unsupported now, please report !\n"); |
| } |
| } |
| return DDERR_INVALIDPARAMS; |
| } |
| |
| HRESULT |
| gltex_bltfast(IDirectDrawSurfaceImpl *surf_ptr, DWORD dstx, |
| DWORD dsty, LPDIRECTDRAWSURFACE7 src, |
| LPRECT rsrc, DWORD trans) |
| { |
| if (src != NULL) { |
| IDirectDrawSurfaceImpl *src_ptr = ICOM_OBJECT(IDirectDrawSurfaceImpl, IDirectDrawSurface7, src); |
| |
| if ((src_ptr->surface_desc.ddsCaps.dwCaps & DDSCAPS_3DDEVICE) && |
| ((trans & (DDBLTFAST_SRCCOLORKEY | DDBLTFAST_DESTCOLORKEY)) == 0)) { |
| /* This is a blt without color keying... We can use the direct copy. */ |
| RECT rsrc2; |
| DWORD width, height; |
| GLuint cur_tex; |
| IDirect3DTextureGLImpl *gl_surf_ptr = surf_ptr->tex_private; |
| int y; |
| |
| if (rsrc == NULL) { |
| WARN("rsrc is NULL\n"); |
| rsrc = &rsrc2; |
| |
| rsrc->left = 0; |
| rsrc->top = 0; |
| rsrc->right = src_ptr->surface_desc.dwWidth; |
| rsrc->bottom = src_ptr->surface_desc.dwHeight; |
| } |
| |
| width = rsrc->right - rsrc->left; |
| height = rsrc->bottom - rsrc->top; |
| |
| if (((dstx + width) > surf_ptr->surface_desc.dwWidth) || |
| ((dsty + height) > surf_ptr->surface_desc.dwHeight)) { |
| FIXME("Does not handle clipping yet in FB => Texture blits !\n"); |
| return DDERR_INVALIDPARAMS; |
| } |
| |
| if ((width == 0) || (height == 0)) { |
| return DD_OK; |
| } |
| |
| TRACE(" direct frame buffer => texture BltFast override.\n"); |
| |
| ENTER_GL(); |
| |
| glGetIntegerv(GL_TEXTURE_BINDING_2D, &cur_tex); |
| glBindTexture(GL_TEXTURE_2D, gl_surf_ptr->tex_name); |
| |
| if ((gl_surf_ptr->dirty_flag == SURFACE_MEMORY_DIRTY) && |
| !((dstx == 0) && (dsty == 0) && |
| (width == surf_ptr->surface_desc.dwWidth) && (height == surf_ptr->surface_desc.dwHeight))) { |
| /* If not 'full size' and the surface is dirty, first flush it to GL before doing the copy. */ |
| if (upload_surface_to_tex_memory_init(surf_ptr, surf_ptr->mipmap_level, &(gl_surf_ptr->current_internal_format), |
| gl_surf_ptr->initial_upload_done == FALSE, TRUE, 0, 0) == DD_OK) { |
| upload_surface_to_tex_memory(NULL, 0, 0, &(gl_surf_ptr->surface_ptr)); |
| upload_surface_to_tex_memory_release(); |
| gl_surf_ptr->dirty_flag = SURFACE_MEMORY; |
| gl_surf_ptr->initial_upload_done = TRUE; |
| } else { |
| glBindTexture(GL_TEXTURE_2D, cur_tex); |
| LEAVE_GL(); |
| ERR("Error at texture upload !\n"); |
| return DDERR_INVALIDPARAMS; |
| } |
| } |
| |
| /* This is a hack and would need some clean-up :-) */ |
| if (gl_surf_ptr->initial_upload_done == FALSE) { |
| if (upload_surface_to_tex_memory_init(surf_ptr, surf_ptr->mipmap_level, &(gl_surf_ptr->current_internal_format), |
| TRUE, TRUE, 0, 0) == DD_OK) { |
| upload_surface_to_tex_memory(NULL, 0, 0, &(gl_surf_ptr->surface_ptr)); |
| upload_surface_to_tex_memory_release(); |
| gl_surf_ptr->dirty_flag = SURFACE_MEMORY; |
| gl_surf_ptr->initial_upload_done = TRUE; |
| } else { |
| glBindTexture(GL_TEXTURE_2D, cur_tex); |
| LEAVE_GL(); |
| ERR("Error at texture upload (initial case) !\n"); |
| return DDERR_INVALIDPARAMS; |
| } |
| } |
| |
| if ((src_ptr->surface_desc.ddsCaps.dwCaps & (DDSCAPS_FRONTBUFFER|DDSCAPS_PRIMARYSURFACE)) != 0) |
| glReadBuffer(GL_FRONT); |
| else if ((src_ptr->surface_desc.ddsCaps.dwCaps & (DDSCAPS_BACKBUFFER)) == (DDSCAPS_BACKBUFFER)) |
| glReadBuffer(GL_BACK); |
| else { |
| ERR("Wrong surface type for locking !\n"); |
| glBindTexture(GL_TEXTURE_2D, cur_tex); |
| LEAVE_GL(); |
| return DDERR_INVALIDPARAMS; |
| } |
| |
| for (y = (src_ptr->surface_desc.dwHeight - rsrc->top - 1); |
| y >= (src_ptr->surface_desc.dwHeight - (rsrc->top + height)); |
| y--) { |
| glCopyTexSubImage2D(GL_TEXTURE_2D, surf_ptr->mipmap_level, |
| dstx, dsty, |
| rsrc->left, y, |
| width, 1); |
| dsty++; |
| } |
| |
| glBindTexture(GL_TEXTURE_2D, cur_tex); |
| LEAVE_GL(); |
| |
| /* The SURFACE_GL case is not handled by the 'global' dirty flag */ |
| gl_surf_ptr->dirty_flag = SURFACE_GL; |
| |
| return DD_OK; |
| } |
| } |
| return DDERR_INVALIDPARAMS; |
| } |
| |
| HRESULT WINAPI |
| Main_IDirect3DTextureImpl_2_1T_PaletteChanged(LPDIRECT3DTEXTURE2 iface, |
| DWORD dwStart, |
| DWORD dwCount) |
| { |
| ICOM_THIS_FROM(IDirectDrawSurfaceImpl, IDirect3DTexture2, iface); |
| FIXME("(%p/%p)->(%08lx,%08lx): stub!\n", This, iface, dwStart, dwCount); |
| return DD_OK; |
| } |
| |
| HRESULT WINAPI |
| Main_IDirect3DTextureImpl_1_Unload(LPDIRECT3DTEXTURE iface) |
| { |
| ICOM_THIS_FROM(IDirectDrawSurfaceImpl, IDirect3DTexture, iface); |
| FIXME("(%p/%p)->(): stub!\n", This, iface); |
| return DD_OK; |
| } |
| |
| HRESULT WINAPI |
| Main_IDirect3DTextureImpl_2_1T_GetHandle(LPDIRECT3DTEXTURE2 iface, |
| LPDIRECT3DDEVICE2 lpDirect3DDevice2, |
| LPD3DTEXTUREHANDLE lpHandle) |
| { |
| ICOM_THIS_FROM(IDirectDrawSurfaceImpl, IDirect3DTexture2, iface); |
| IDirect3DDeviceImpl *lpDeviceImpl = ICOM_OBJECT(IDirect3DDeviceImpl, IDirect3DDevice2, lpDirect3DDevice2); |
| |
| TRACE("(%p/%p)->(%p,%p)\n", This, iface, lpDirect3DDevice2, lpHandle); |
| |
| /* The handle is simply the pointer to the implementation structure */ |
| *lpHandle = (D3DTEXTUREHANDLE) This; |
| |
| TRACE(" returning handle %08lx.\n", *lpHandle); |
| |
| /* Now set the device for this texture */ |
| This->d3ddevice = lpDeviceImpl; |
| |
| return D3D_OK; |
| } |
| |
| HRESULT WINAPI |
| Main_IDirect3DTextureImpl_2_1T_Load(LPDIRECT3DTEXTURE2 iface, |
| LPDIRECT3DTEXTURE2 lpD3DTexture2) |
| { |
| ICOM_THIS_FROM(IDirectDrawSurfaceImpl, IDirect3DTexture2, iface); |
| FIXME("(%p/%p)->(%p): stub!\n", This, iface, lpD3DTexture2); |
| return DD_OK; |
| } |
| |
| static void gltex_set_palette(IDirectDrawSurfaceImpl* This, IDirectDrawPaletteImpl* pal) |
| { |
| IDirect3DTextureGLImpl *glThis = (IDirect3DTextureGLImpl *) This->tex_private; |
| |
| if (glThis->dirty_flag == SURFACE_GL) { |
| GLuint cur_tex; |
| |
| TRACE(" flushing GL texture back to memory.\n"); |
| |
| ENTER_GL(); |
| glGetIntegerv(GL_TEXTURE_BINDING_2D, &cur_tex); |
| glBindTexture(GL_TEXTURE_2D, glThis->tex_name); |
| gltex_download_texture(This); |
| glBindTexture(GL_TEXTURE_2D, cur_tex); |
| LEAVE_GL(); |
| } |
| |
| /* First call the previous set_palette function */ |
| glThis->set_palette(This, pal); |
| |
| /* And set the dirty flag */ |
| glThis->dirty_flag = SURFACE_MEMORY_DIRTY; |
| *(glThis->global_dirty_flag) = SURFACE_MEMORY_DIRTY; |
| |
| /* TODO: check palette on mipmapped surfaces... |
| TODO: do we need to re-upload in case of usage of the paletted texture extension ? */ |
| } |
| |
| static void |
| gltex_final_release(IDirectDrawSurfaceImpl *This) |
| { |
| IDirect3DTextureGLImpl *glThis = (IDirect3DTextureGLImpl *) This->tex_private; |
| DWORD mem_used; |
| int i; |
| |
| TRACE(" deleting texture with GL id %d.\n", glThis->tex_name); |
| |
| /* And delete texture handle */ |
| ENTER_GL(); |
| if (glThis->tex_name != 0) |
| glDeleteTextures(1, &(glThis->tex_name)); |
| LEAVE_GL(); |
| |
| if (glThis->surface_ptr != NULL) |
| HeapFree(GetProcessHeap(), 0, glThis->surface_ptr); |
| |
| /* And if this texture was the current one, remove it at the device level */ |
| if (This->d3ddevice != NULL) |
| for (i = 0; i < MAX_TEXTURES; i++) |
| if (This->d3ddevice->current_texture[i] == This) |
| This->d3ddevice->current_texture[i] = NULL; |
| |
| /* All this should be part of main surface management not just a hack for texture.. */ |
| if (glThis->loaded) { |
| mem_used = This->surface_desc.dwHeight * |
| This->surface_desc.u1.lPitch; |
| This->ddraw_owner->free_memory(This->ddraw_owner, mem_used); |
| } |
| |
| glThis->final_release(This); |
| } |
| |
| static void |
| gltex_lock_update(IDirectDrawSurfaceImpl* This, LPCRECT pRect, DWORD dwFlags) |
| { |
| IDirect3DTextureGLImpl *glThis = (IDirect3DTextureGLImpl *) This->tex_private; |
| |
| glThis->lock_update(This, pRect, dwFlags); |
| } |
| |
| static void |
| gltex_unlock_update(IDirectDrawSurfaceImpl* This, LPCRECT pRect) |
| { |
| IDirect3DTextureGLImpl *glThis = (IDirect3DTextureGLImpl *) This->tex_private; |
| |
| glThis->unlock_update(This, pRect); |
| |
| /* Set the dirty flag according to the lock type */ |
| if ((This->lastlocktype & DDLOCK_READONLY) == 0) { |
| glThis->dirty_flag = SURFACE_MEMORY_DIRTY; |
| *(glThis->global_dirty_flag) = SURFACE_MEMORY_DIRTY; |
| } |
| } |
| |
| HRESULT WINAPI |
| GL_IDirect3DTextureImpl_2_1T_Load(LPDIRECT3DTEXTURE2 iface, |
| LPDIRECT3DTEXTURE2 lpD3DTexture2) |
| { |
| ICOM_THIS_FROM(IDirectDrawSurfaceImpl, IDirect3DTexture2, iface); |
| IDirectDrawSurfaceImpl *src_ptr = ICOM_OBJECT(IDirectDrawSurfaceImpl, IDirect3DTexture2, lpD3DTexture2); |
| IDirectDrawSurfaceImpl *dst_ptr = This; |
| HRESULT ret_value = D3D_OK; |
| |
| TRACE("(%p/%p)->(%p)\n", This, iface, lpD3DTexture2); |
| |
| if (((src_ptr->surface_desc.ddsCaps.dwCaps & DDSCAPS_MIPMAP) != (dst_ptr->surface_desc.ddsCaps.dwCaps & DDSCAPS_MIPMAP)) || |
| (src_ptr->surface_desc.u2.dwMipMapCount != dst_ptr->surface_desc.u2.dwMipMapCount)) { |
| ERR("Trying to load surfaces with different mip-map counts !\n"); |
| } |
| |
| /* Now loop through all mipmap levels and load all of them... */ |
| while (1) { |
| IDirect3DTextureGLImpl *gl_dst_ptr = (IDirect3DTextureGLImpl *) dst_ptr->tex_private; |
| DDSURFACEDESC *src_d, *dst_d; |
| |
| if (gl_dst_ptr != NULL) { |
| if (gl_dst_ptr->loaded == FALSE) { |
| /* Only check memory for not already loaded texture... */ |
| DWORD mem_used = dst_ptr->surface_desc.dwHeight * dst_ptr->surface_desc.u1.lPitch; |
| if (This->ddraw_owner->allocate_memory(This->ddraw_owner, mem_used) < 0) { |
| TRACE(" out of virtual memory... Warning application.\n"); |
| return D3DERR_TEXTURE_LOAD_FAILED; |
| } |
| } |
| gl_dst_ptr->loaded = TRUE; |
| } |
| |
| TRACE(" copying surface %p to surface %p (mipmap level %d)\n", src_ptr, dst_ptr, src_ptr->mipmap_level); |
| |
| if ( dst_ptr->surface_desc.ddsCaps.dwCaps & DDSCAPS_ALLOCONLOAD ) |
| /* If the surface is not allocated and its location is not yet specified, |
| force it to video memory */ |
| if ( !(dst_ptr->surface_desc.ddsCaps.dwCaps & (DDSCAPS_SYSTEMMEMORY|DDSCAPS_VIDEOMEMORY)) ) |
| dst_ptr->surface_desc.ddsCaps.dwCaps |= DDSCAPS_VIDEOMEMORY; |
| |
| /* Suppress the ALLOCONLOAD flag */ |
| dst_ptr->surface_desc.ddsCaps.dwCaps &= ~DDSCAPS_ALLOCONLOAD; |
| |
| /* After seeing some logs, not sure at all about this... */ |
| if (dst_ptr->palette == NULL) { |
| dst_ptr->palette = src_ptr->palette; |
| if (src_ptr->palette != NULL) IDirectDrawPalette_AddRef(ICOM_INTERFACE(src_ptr->palette, IDirectDrawPalette)); |
| } else { |
| if (src_ptr->palette != NULL) { |
| PALETTEENTRY palent[256]; |
| IDirectDrawPalette_GetEntries(ICOM_INTERFACE(src_ptr->palette, IDirectDrawPalette), |
| 0, 0, 256, palent); |
| IDirectDrawPalette_SetEntries(ICOM_INTERFACE(dst_ptr->palette, IDirectDrawPalette), |
| 0, 0, 256, palent); |
| } |
| } |
| |
| /* Copy one surface on the other */ |
| dst_d = (DDSURFACEDESC *)&(dst_ptr->surface_desc); |
| src_d = (DDSURFACEDESC *)&(src_ptr->surface_desc); |
| |
| if ((src_d->dwWidth != dst_d->dwWidth) || (src_d->dwHeight != dst_d->dwHeight)) { |
| /* Should also check for same pixel format, u1.lPitch, ... */ |
| ERR("Error in surface sizes\n"); |
| return D3DERR_TEXTURE_LOAD_FAILED; |
| } else { |
| /* LPDIRECT3DDEVICE2 d3dd = (LPDIRECT3DDEVICE2) This->D3Ddevice; */ |
| /* I should put a macro for the calculus of bpp */ |
| |
| /* Copy also the ColorKeying stuff */ |
| if (src_d->dwFlags & DDSD_CKSRCBLT) { |
| dst_d->dwFlags |= DDSD_CKSRCBLT; |
| dst_d->ddckCKSrcBlt.dwColorSpaceLowValue = src_d->ddckCKSrcBlt.dwColorSpaceLowValue; |
| dst_d->ddckCKSrcBlt.dwColorSpaceHighValue = src_d->ddckCKSrcBlt.dwColorSpaceHighValue; |
| } |
| |
| /* Copy the main memory texture into the surface that corresponds to the OpenGL |
| texture object. */ |
| memcpy(dst_d->lpSurface, src_d->lpSurface, src_d->u1.lPitch * src_d->dwHeight); |
| |
| if (gl_dst_ptr != NULL) { |
| /* If the GetHandle was not done, it is an error... */ |
| if (gl_dst_ptr->tex_name == 0) ERR("Unbound GL texture !!!\n"); |
| |
| /* Set this texture as dirty */ |
| gl_dst_ptr->dirty_flag = SURFACE_MEMORY_DIRTY; |
| *(gl_dst_ptr->global_dirty_flag) = SURFACE_MEMORY_DIRTY; |
| } |
| } |
| |
| if (src_ptr->surface_desc.ddsCaps.dwCaps & DDSCAPS_MIPMAP) { |
| src_ptr = get_sub_mimaplevel(src_ptr); |
| } else { |
| src_ptr = NULL; |
| } |
| if (dst_ptr->surface_desc.ddsCaps.dwCaps & DDSCAPS_MIPMAP) { |
| dst_ptr = get_sub_mimaplevel(dst_ptr); |
| } else { |
| dst_ptr = NULL; |
| } |
| |
| if ((src_ptr == NULL) || (dst_ptr == NULL)) { |
| if (src_ptr != dst_ptr) { |
| ERR(" Loading surface with different mipmap structure !!!\n"); |
| } |
| break; |
| } |
| } |
| |
| return ret_value; |
| } |
| |
| HRESULT WINAPI |
| Thunk_IDirect3DTextureImpl_2_QueryInterface(LPDIRECT3DTEXTURE2 iface, |
| REFIID riid, |
| LPVOID* obp) |
| { |
| TRACE("(%p)->(%s,%p) thunking to IDirectDrawSurface7 interface.\n", iface, debugstr_guid(riid), obp); |
| return IDirectDrawSurface7_QueryInterface(COM_INTERFACE_CAST(IDirectDrawSurfaceImpl, IDirect3DTexture2, IDirectDrawSurface7, iface), |
| riid, |
| obp); |
| } |
| |
| ULONG WINAPI |
| Thunk_IDirect3DTextureImpl_2_AddRef(LPDIRECT3DTEXTURE2 iface) |
| { |
| TRACE("(%p)->() thunking to IDirectDrawSurface7 interface.\n", iface); |
| return IDirectDrawSurface7_AddRef(COM_INTERFACE_CAST(IDirectDrawSurfaceImpl, IDirect3DTexture2, IDirectDrawSurface7, iface)); |
| } |
| |
| ULONG WINAPI |
| Thunk_IDirect3DTextureImpl_2_Release(LPDIRECT3DTEXTURE2 iface) |
| { |
| TRACE("(%p)->() thunking to IDirectDrawSurface7 interface.\n", iface); |
| return IDirectDrawSurface7_Release(COM_INTERFACE_CAST(IDirectDrawSurfaceImpl, IDirect3DTexture2, IDirectDrawSurface7, iface)); |
| } |
| |
| HRESULT WINAPI |
| Thunk_IDirect3DTextureImpl_1_QueryInterface(LPDIRECT3DTEXTURE iface, |
| REFIID riid, |
| LPVOID* obp) |
| { |
| TRACE("(%p)->(%s,%p) thunking to IDirectDrawSurface7 interface.\n", iface, debugstr_guid(riid), obp); |
| return IDirectDrawSurface7_QueryInterface(COM_INTERFACE_CAST(IDirectDrawSurfaceImpl, IDirect3DTexture, IDirectDrawSurface7, iface), |
| riid, |
| obp); |
| } |
| |
| ULONG WINAPI |
| Thunk_IDirect3DTextureImpl_1_AddRef(LPDIRECT3DTEXTURE iface) |
| { |
| TRACE("(%p)->() thunking to IDirectDrawSurface7 interface.\n", iface); |
| return IDirectDrawSurface7_AddRef(COM_INTERFACE_CAST(IDirectDrawSurfaceImpl, IDirect3DTexture, IDirectDrawSurface7, iface)); |
| } |
| |
| ULONG WINAPI |
| Thunk_IDirect3DTextureImpl_1_Release(LPDIRECT3DTEXTURE iface) |
| { |
| TRACE("(%p)->() thunking to IDirectDrawSurface7 interface.\n", iface); |
| return IDirectDrawSurface7_Release(COM_INTERFACE_CAST(IDirectDrawSurfaceImpl, IDirect3DTexture, IDirectDrawSurface7, iface)); |
| } |
| |
| HRESULT WINAPI |
| Thunk_IDirect3DTextureImpl_1_PaletteChanged(LPDIRECT3DTEXTURE iface, |
| DWORD dwStart, |
| DWORD dwCount) |
| { |
| TRACE("(%p)->(%08lx,%08lx) thunking to IDirect3DTexture2 interface.\n", iface, dwStart, dwCount); |
| return IDirect3DTexture2_PaletteChanged(COM_INTERFACE_CAST(IDirectDrawSurfaceImpl, IDirect3DTexture, IDirect3DTexture2, iface), |
| dwStart, |
| dwCount); |
| } |
| |
| HRESULT WINAPI |
| Thunk_IDirect3DTextureImpl_1_GetHandle(LPDIRECT3DTEXTURE iface, |
| LPDIRECT3DDEVICE lpDirect3DDevice, |
| LPD3DTEXTUREHANDLE lpHandle) |
| { |
| TRACE("(%p)->(%p,%p) thunking to IDirect3DTexture2 interface.\n", iface, lpDirect3DDevice, lpHandle); |
| return IDirect3DTexture2_GetHandle(COM_INTERFACE_CAST(IDirectDrawSurfaceImpl, IDirect3DTexture, IDirect3DTexture2, iface), |
| COM_INTERFACE_CAST(IDirect3DDeviceImpl, IDirect3DDevice, IDirect3DDevice2, lpDirect3DDevice), |
| lpHandle); |
| } |
| |
| HRESULT WINAPI |
| Thunk_IDirect3DTextureImpl_1_Load(LPDIRECT3DTEXTURE iface, |
| LPDIRECT3DTEXTURE lpD3DTexture) |
| { |
| TRACE("(%p)->(%p) thunking to IDirect3DTexture2 interface.\n", iface, lpD3DTexture); |
| return IDirect3DTexture2_Load(COM_INTERFACE_CAST(IDirectDrawSurfaceImpl, IDirect3DTexture, IDirect3DTexture2, iface), |
| COM_INTERFACE_CAST(IDirectDrawSurfaceImpl, IDirect3DTexture, IDirect3DTexture2, lpD3DTexture)); |
| } |
| |
| #if !defined(__STRICT_ANSI__) && defined(__GNUC__) |
| # define XCAST(fun) (typeof(VTABLE_IDirect3DTexture2.fun)) |
| #else |
| # define XCAST(fun) (void*) |
| #endif |
| |
| ICOM_VTABLE(IDirect3DTexture2) VTABLE_IDirect3DTexture2 = |
| { |
| ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE |
| XCAST(QueryInterface) Thunk_IDirect3DTextureImpl_2_QueryInterface, |
| XCAST(AddRef) Thunk_IDirect3DTextureImpl_2_AddRef, |
| XCAST(Release) Thunk_IDirect3DTextureImpl_2_Release, |
| XCAST(GetHandle) Main_IDirect3DTextureImpl_2_1T_GetHandle, |
| XCAST(PaletteChanged) Main_IDirect3DTextureImpl_2_1T_PaletteChanged, |
| XCAST(Load) GL_IDirect3DTextureImpl_2_1T_Load, |
| }; |
| |
| #if !defined(__STRICT_ANSI__) && defined(__GNUC__) |
| #undef XCAST |
| #endif |
| |
| |
| #if !defined(__STRICT_ANSI__) && defined(__GNUC__) |
| # define XCAST(fun) (typeof(VTABLE_IDirect3DTexture.fun)) |
| #else |
| # define XCAST(fun) (void*) |
| #endif |
| |
| ICOM_VTABLE(IDirect3DTexture) VTABLE_IDirect3DTexture = |
| { |
| ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE |
| XCAST(QueryInterface) Thunk_IDirect3DTextureImpl_1_QueryInterface, |
| XCAST(AddRef) Thunk_IDirect3DTextureImpl_1_AddRef, |
| XCAST(Release) Thunk_IDirect3DTextureImpl_1_Release, |
| XCAST(Initialize) Main_IDirect3DTextureImpl_1_Initialize, |
| XCAST(GetHandle) Thunk_IDirect3DTextureImpl_1_GetHandle, |
| XCAST(PaletteChanged) Thunk_IDirect3DTextureImpl_1_PaletteChanged, |
| XCAST(Load) Thunk_IDirect3DTextureImpl_1_Load, |
| XCAST(Unload) Main_IDirect3DTextureImpl_1_Unload, |
| }; |
| |
| #if !defined(__STRICT_ANSI__) && defined(__GNUC__) |
| #undef XCAST |
| #endif |
| |
| HRESULT d3dtexture_create(IDirectDrawImpl *d3d, IDirectDrawSurfaceImpl *surf, BOOLEAN at_creation, |
| IDirectDrawSurfaceImpl *main) |
| { |
| /* First, initialize the texture vtables... */ |
| ICOM_INIT_INTERFACE(surf, IDirect3DTexture, VTABLE_IDirect3DTexture); |
| ICOM_INIT_INTERFACE(surf, IDirect3DTexture2, VTABLE_IDirect3DTexture2); |
| |
| /* Only create all the private stuff if we actually have an OpenGL context.. */ |
| if (d3d->current_device != NULL) { |
| IDirect3DTextureGLImpl *private; |
| |
| private = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IDirect3DTextureGLImpl)); |
| if (private == NULL) return DDERR_OUTOFMEMORY; |
| |
| private->final_release = surf->final_release; |
| private->lock_update = surf->lock_update; |
| private->unlock_update = surf->unlock_update; |
| private->set_palette = surf->set_palette; |
| |
| /* If at creation, we can optimize stuff and wait the first 'unlock' to upload a valid stuff to OpenGL. |
| Otherwise, it will be uploaded here (and may be invalid). */ |
| surf->final_release = gltex_final_release; |
| surf->lock_update = gltex_lock_update; |
| surf->unlock_update = gltex_unlock_update; |
| surf->tex_private = private; |
| surf->aux_setcolorkey_cb = gltex_setcolorkey_cb; |
| surf->set_palette = gltex_set_palette; |
| |
| /* We are the only one to use the aux_blt and aux_bltfast overides, so no need |
| to save those... */ |
| surf->aux_blt = gltex_blt; |
| surf->aux_bltfast = gltex_bltfast; |
| |
| TRACE(" GL texture created for surface %p (private data at %p)\n", surf, private); |
| |
| ENTER_GL(); |
| if (surf->mipmap_level == 0) { |
| glGenTextures(1, &(private->tex_name)); |
| if (private->tex_name == 0) ERR("Error at creation of OpenGL texture ID !\n"); |
| TRACE(" GL texture id is : %d.\n", private->tex_name); |
| private->__global_dirty_flag = (at_creation == FALSE ? SURFACE_MEMORY_DIRTY : SURFACE_MEMORY); |
| private->global_dirty_flag = &(private->__global_dirty_flag); |
| } else { |
| private->tex_name = ((IDirect3DTextureGLImpl *) (main->tex_private))->tex_name; |
| TRACE(" GL texture id reusing id %d from surface %p (private at %p)).\n", private->tex_name, main, main->tex_private); |
| private->global_dirty_flag = &(((IDirect3DTextureGLImpl *) (main->tex_private))->__global_dirty_flag); |
| } |
| LEAVE_GL(); |
| |
| /* And set the dirty flag accordingly */ |
| private->dirty_flag = (at_creation == FALSE ? SURFACE_MEMORY_DIRTY : SURFACE_MEMORY); |
| private->initial_upload_done = FALSE; |
| } |
| |
| return D3D_OK; |
| } |