| /* 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 <string.h> | |
| #define NONAMELESSUNION | |
| #define NONAMELESSSTRUCT | |
| #include "windef.h" | |
| #include "winerror.h" | |
| #include "objbase.h" | |
| #include "ddraw.h" | |
| #include "d3d.h" | |
| #include "wine/debug.h" | |
| #include "mesa_private.h" | |
| WINE_DEFAULT_DEBUG_CHANNEL(ddraw); | |
| /* Define this if you want to save to a file all the textures used by a game | |
| (can be funny to see how they managed to cram all the pictures in | |
| texture memory) */ | |
| #undef TEXTURE_SNOOP | |
| #ifdef TEXTURE_SNOOP | |
| #include <stdio.h> | |
| static void | |
| snoop_texture(IDirectDrawSurfaceImpl *This) { | |
| IDirect3DTextureGLImpl *glThis = (IDirect3DTextureGLImpl *) This->tex_private; | |
| char buf[128]; | |
| FILE *f; | |
| sprintf(buf, "tex_%05d.pnm", glThis->tex_name); | |
| f = fopen(buf, "wb"); | |
| DDRAW_dump_surface_to_disk(This, f); | |
| } | |
| #else | |
| #define snoop_texture(a) | |
| #endif | |
| /******************************************************************************* | |
| * IDirectSurface callback methods | |
| */ | |
| HRESULT | |
| gltex_upload_texture(IDirectDrawSurfaceImpl *This) { | |
| IDirect3DTextureGLImpl *glThis = (IDirect3DTextureGLImpl *) This->tex_private; | |
| #if 0 | |
| static BOOL color_table_queried = FALSE; | |
| #endif | |
| void (*ptr_ColorTableEXT) (GLenum target, GLenum internalformat, | |
| GLsizei width, GLenum format, GLenum type, const GLvoid *table) = NULL; | |
| BOOL upload_done = FALSE; | |
| BOOL error = FALSE; | |
| GLenum format = GL_RGBA, pixel_format = GL_UNSIGNED_BYTE; /* This is only to prevent warnings.. */ | |
| VOID *surface = NULL; | |
| DDSURFACEDESC *src_d = (DDSURFACEDESC *)&(This->surface_desc); | |
| glBindTexture(GL_TEXTURE_2D, glThis->tex_name); | |
| if (glThis->dirty_flag == FALSE) { | |
| TRACE(" activating OpenGL texture id %d.\n", glThis->tex_name); | |
| return DD_OK; | |
| } else { | |
| TRACE(" activating and uploading texture id %d (initial done = %d).\n", glThis->tex_name, glThis->initial_upload_done); | |
| } | |
| /* Texture snooping for the curious :-) */ | |
| snoop_texture(This); | |
| if (src_d->ddpfPixelFormat.dwFlags & DDPF_PALETTEINDEXED8) { | |
| /* **************** | |
| Paletted Texture | |
| **************** */ | |
| IDirectDrawPaletteImpl* pal = This->palette; | |
| BYTE table[256][4]; | |
| int i; | |
| #if 0 | |
| if (color_table_queried == FALSE) { | |
| ptr_ColorTableEXT = | |
| ((Mesa_DeviceCapabilities *) ((x11_dd_private *) This->surface->s.ddraw->d->private)->device_capabilities)->ptr_ColorTableEXT; | |
| } | |
| #endif | |
| if (pal == NULL) { | |
| /* Upload a black texture. The real one will be uploaded on palette change */ | |
| WARN("Palettized texture Loading with a NULL palette !\n"); | |
| memset(table, 0, 256 * 4); | |
| } else { | |
| /* Get the surface's palette */ | |
| for (i = 0; i < 256; i++) { | |
| table[i][0] = pal->palents[i].peRed; | |
| table[i][1] = pal->palents[i].peGreen; | |
| table[i][2] = pal->palents[i].peBlue; | |
| if ((src_d->dwFlags & DDSD_CKSRCBLT) && | |
| (i >= src_d->ddckCKSrcBlt.dwColorSpaceLowValue) && | |
| (i <= src_d->ddckCKSrcBlt.dwColorSpaceHighValue)) | |
| /* We should maybe here put a more 'neutral' color than the standard bright purple | |
| one often used by application to prevent the nice purple borders when bi-linear | |
| filtering is on */ | |
| table[i][3] = 0x00; | |
| else | |
| table[i][3] = 0xFF; | |
| } | |
| } | |
| if (ptr_ColorTableEXT != NULL) { | |
| /* use Paletted Texture Extension */ | |
| ptr_ColorTableEXT(GL_TEXTURE_2D, /* target */ | |
| GL_RGBA, /* internal format */ | |
| 256, /* table size */ | |
| GL_RGBA, /* table format */ | |
| GL_UNSIGNED_BYTE, /* table type */ | |
| table); /* the color table */ | |
| glTexImage2D(GL_TEXTURE_2D, /* target */ | |
| This->mipmap_level, /* level */ | |
| GL_COLOR_INDEX8_EXT, /* internal format */ | |
| src_d->dwWidth, src_d->dwHeight, /* width, height */ | |
| 0, /* border */ | |
| GL_COLOR_INDEX, /* texture format */ | |
| GL_UNSIGNED_BYTE, /* texture type */ | |
| src_d->lpSurface); /* the texture */ | |
| upload_done = TRUE; | |
| } else { | |
| DWORD i; | |
| BYTE *src = (BYTE *) src_d->lpSurface, *dst; | |
| surface = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, src_d->dwWidth * src_d->dwHeight * sizeof(DWORD)); | |
| dst = (BYTE *) surface; | |
| for (i = 0; i < src_d->dwHeight * src_d->dwWidth; i++) { | |
| BYTE color = *src++; | |
| *dst++ = table[color][0]; | |
| *dst++ = table[color][1]; | |
| *dst++ = table[color][2]; | |
| *dst++ = table[color][3]; | |
| } | |
| format = GL_RGBA; | |
| pixel_format = GL_UNSIGNED_BYTE; | |
| } | |
| } else if (src_d->ddpfPixelFormat.dwFlags & DDPF_RGB) { | |
| /* ************ | |
| RGB Textures | |
| ************ */ | |
| if (src_d->ddpfPixelFormat.u1.dwRGBBitCount == 8) { | |
| if ((src_d->ddpfPixelFormat.u2.dwRBitMask == 0xE0) && | |
| (src_d->ddpfPixelFormat.u3.dwGBitMask == 0x1C) && | |
| (src_d->ddpfPixelFormat.u4.dwBBitMask == 0x03)) { | |
| /* ********************** | |
| GL_UNSIGNED_BYTE_3_3_2 | |
| ********************** */ | |
| if (src_d->dwFlags & DDSD_CKSRCBLT) { | |
| /* This texture format will never be used.. So do not care about color keying | |
| up until the point in time it will be needed :-) */ | |
| error = TRUE; | |
| } else { | |
| format = GL_RGB; | |
| pixel_format = GL_UNSIGNED_BYTE_3_3_2; | |
| } | |
| } else { | |
| error = TRUE; | |
| } | |
| } else if (src_d->ddpfPixelFormat.u1.dwRGBBitCount == 16) { | |
| if ((src_d->ddpfPixelFormat.u2.dwRBitMask == 0xF800) && | |
| (src_d->ddpfPixelFormat.u3.dwGBitMask == 0x07E0) && | |
| (src_d->ddpfPixelFormat.u4.dwBBitMask == 0x001F) && | |
| (src_d->ddpfPixelFormat.u5.dwRGBAlphaBitMask == 0x0000)) { | |
| if (src_d->dwFlags & DDSD_CKSRCBLT) { | |
| /* Converting the 565 format in 5551 packed to emulate color-keying. | |
| Note : in all these conversion, it would be best to average the averaging | |
| pixels to get the color of the pixel that will be color-keyed to | |
| prevent 'color bleeding'. This will be done later on if ever it is | |
| too visible. | |
| Note2: when using color-keying + alpha, are the alpha bits part of the | |
| color-space or not ? | |
| */ | |
| DWORD i; | |
| WORD *src = (WORD *) src_d->lpSurface, *dst; | |
| surface = (WORD *) HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, src_d->dwWidth * src_d->dwHeight * sizeof(WORD)); | |
| dst = (WORD *) surface; | |
| for (i = 0; i < src_d->dwHeight * src_d->dwWidth; i++) { | |
| WORD color = *src++; | |
| *dst = ((color & 0xFFC0) | ((color & 0x1F) << 1)); | |
| if ((color < src_d->ddckCKSrcBlt.dwColorSpaceLowValue) || | |
| (color > src_d->ddckCKSrcBlt.dwColorSpaceHighValue)) | |
| *dst |= 0x0001; | |
| dst++; | |
| } | |
| format = GL_RGBA; | |
| pixel_format = GL_UNSIGNED_SHORT_5_5_5_1; | |
| } else { | |
| format = GL_RGB; | |
| pixel_format = GL_UNSIGNED_SHORT_5_6_5; | |
| } | |
| } else if ((src_d->ddpfPixelFormat.u2.dwRBitMask == 0xF800) && | |
| (src_d->ddpfPixelFormat.u3.dwGBitMask == 0x07C0) && | |
| (src_d->ddpfPixelFormat.u4.dwBBitMask == 0x003E) && | |
| (src_d->ddpfPixelFormat.u5.dwRGBAlphaBitMask == 0x0001)) { | |
| format = GL_RGBA; | |
| pixel_format = GL_UNSIGNED_SHORT_5_5_5_1; | |
| if (src_d->dwFlags & DDSD_CKSRCBLT) { | |
| /* Change the alpha value of the color-keyed pixels to emulate color-keying. */ | |
| DWORD i; | |
| WORD *src = (WORD *) src_d->lpSurface, *dst; | |
| surface = (WORD *) HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, src_d->dwWidth * src_d->dwHeight * sizeof(WORD)); | |
| dst = (WORD *) surface; | |
| for (i = 0; i < src_d->dwHeight * src_d->dwWidth; i++) { | |
| WORD color = *src++; | |
| *dst = color & 0xFFFE; | |
| if ((color < src_d->ddckCKSrcBlt.dwColorSpaceLowValue) || | |
| (color > src_d->ddckCKSrcBlt.dwColorSpaceHighValue)) | |
| *dst |= color & 0x0001; | |
| dst++; | |
| } | |
| } | |
| } else if ((src_d->ddpfPixelFormat.u2.dwRBitMask == 0xF000) && | |
| (src_d->ddpfPixelFormat.u3.dwGBitMask == 0x0F00) && | |
| (src_d->ddpfPixelFormat.u4.dwBBitMask == 0x00F0) && | |
| (src_d->ddpfPixelFormat.u5.dwRGBAlphaBitMask == 0x000F)) { | |
| format = GL_RGBA; | |
| pixel_format = GL_UNSIGNED_SHORT_4_4_4_4; | |
| if (src_d->dwFlags & DDSD_CKSRCBLT) { | |
| /* Change the alpha value of the color-keyed pixels to emulate color-keying. */ | |
| DWORD i; | |
| WORD *src = (WORD *) src_d->lpSurface, *dst; | |
| surface = (WORD *) HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, src_d->dwWidth * src_d->dwHeight * sizeof(WORD)); | |
| dst = (WORD *) surface; | |
| for (i = 0; i < src_d->dwHeight * src_d->dwWidth; i++) { | |
| WORD color = *src++; | |
| *dst = color & 0xFFF0; | |
| if ((color < src_d->ddckCKSrcBlt.dwColorSpaceLowValue) || | |
| (color > src_d->ddckCKSrcBlt.dwColorSpaceHighValue)) | |
| *dst |= color & 0x000F; | |
| dst++; | |
| } | |
| } | |
| } else if ((src_d->ddpfPixelFormat.u2.dwRBitMask == 0x0F00) && | |
| (src_d->ddpfPixelFormat.u3.dwGBitMask == 0x00F0) && | |
| (src_d->ddpfPixelFormat.u4.dwBBitMask == 0x000F) && | |
| (src_d->ddpfPixelFormat.u5.dwRGBAlphaBitMask == 0xF000)) { | |
| /* Move the four Alpha bits... */ | |
| DWORD i; | |
| WORD *src = (WORD *) src_d->lpSurface, *dst; | |
| surface = (WORD *) HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, src_d->dwWidth * src_d->dwHeight * sizeof(WORD)); | |
| dst = surface; | |
| if (src_d->dwFlags & DDSD_CKSRCBLT) { | |
| for (i = 0; i < src_d->dwHeight * src_d->dwWidth; i++) { | |
| WORD color = *src++; | |
| *dst = (color & 0x0FFF) << 4; | |
| if ((color < src_d->ddckCKSrcBlt.dwColorSpaceLowValue) || | |
| (color > src_d->ddckCKSrcBlt.dwColorSpaceHighValue)) | |
| *dst |= (color & 0xF000) >> 12; | |
| dst++; | |
| } | |
| } else { | |
| for (i = 0; i < src_d->dwHeight * src_d->dwWidth; i++) { | |
| WORD color = *src++; | |
| *dst++ = (((color & 0x0FFF) << 4) | | |
| ((color & 0xF000) >> 12)); | |
| } | |
| } | |
| format = GL_RGBA; | |
| pixel_format = GL_UNSIGNED_SHORT_4_4_4_4; | |
| } else if ((src_d->ddpfPixelFormat.u2.dwRBitMask == 0x7C00) && | |
| (src_d->ddpfPixelFormat.u3.dwGBitMask == 0x03E0) && | |
| (src_d->ddpfPixelFormat.u4.dwBBitMask == 0x001F) && | |
| (src_d->ddpfPixelFormat.u5.dwRGBAlphaBitMask == 0x8000)) { | |
| /* Converting the 1555 format in 5551 packed */ | |
| DWORD i; | |
| WORD *src = (WORD *) src_d->lpSurface, *dst; | |
| surface = (WORD *) HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, src_d->dwWidth * src_d->dwHeight * sizeof(WORD)); | |
| dst = (WORD *) surface; | |
| if (src_d->dwFlags & DDSD_CKSRCBLT) { | |
| for (i = 0; i < src_d->dwHeight * src_d->dwWidth; i++) { | |
| WORD color = *src++; | |
| *dst = (color & 0x7FFF) << 1; | |
| if ((color < src_d->ddckCKSrcBlt.dwColorSpaceLowValue) || | |
| (color > src_d->ddckCKSrcBlt.dwColorSpaceHighValue)) | |
| *dst |= (color & 0x8000) >> 15; | |
| dst++; | |
| } | |
| } else { | |
| for (i = 0; i < src_d->dwHeight * src_d->dwWidth; i++) { | |
| WORD color = *src++; | |
| *dst++ = (((color & 0x7FFF) << 1) | | |
| ((color & 0x8000) >> 15)); | |
| } | |
| } | |
| format = GL_RGBA; | |
| pixel_format = GL_UNSIGNED_SHORT_5_5_5_1; | |
| } else { | |
| error = TRUE; | |
| } | |
| } else if (src_d->ddpfPixelFormat.u1.dwRGBBitCount == 24) { | |
| if ((src_d->ddpfPixelFormat.u2.dwRBitMask == 0x00FF0000) && | |
| (src_d->ddpfPixelFormat.u3.dwGBitMask == 0x0000FF00) && | |
| (src_d->ddpfPixelFormat.u4.dwBBitMask == 0x000000FF) && | |
| (src_d->ddpfPixelFormat.u5.dwRGBAlphaBitMask == 0x00000000)) { | |
| if (src_d->dwFlags & DDSD_CKSRCBLT) { | |
| /* This is a pain :-) */ | |
| DWORD i; | |
| BYTE *src = (BYTE *) src_d->lpSurface; | |
| DWORD *dst; | |
| surface = (DWORD *) HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, src_d->dwWidth * src_d->dwHeight * sizeof(DWORD)); | |
| dst = (DWORD *) surface; | |
| for (i = 0; i < src_d->dwHeight * src_d->dwWidth; i++) { | |
| DWORD color = *((DWORD *) src) & 0x00FFFFFF; | |
| src += 3; | |
| *dst = *src++ << 8; | |
| if ((color < src_d->ddckCKSrcBlt.dwColorSpaceLowValue) || | |
| (color > src_d->ddckCKSrcBlt.dwColorSpaceHighValue)) | |
| *dst |= 0xFF; | |
| dst++; | |
| } | |
| format = GL_RGBA; | |
| pixel_format = GL_UNSIGNED_INT_8_8_8_8; | |
| } else { | |
| format = GL_BGR; | |
| pixel_format = GL_UNSIGNED_BYTE; | |
| } | |
| } else { | |
| error = TRUE; | |
| } | |
| } else if (src_d->ddpfPixelFormat.u1.dwRGBBitCount == 32) { | |
| if ((src_d->ddpfPixelFormat.u2.dwRBitMask == 0xFF000000) && | |
| (src_d->ddpfPixelFormat.u3.dwGBitMask == 0x00FF0000) && | |
| (src_d->ddpfPixelFormat.u4.dwBBitMask == 0x0000FF00) && | |
| (src_d->ddpfPixelFormat.u5.dwRGBAlphaBitMask == 0x000000FF)) { | |
| if (src_d->dwFlags & DDSD_CKSRCBLT) { | |
| /* Just use the alpha component to handle color-keying... */ | |
| DWORD i; | |
| DWORD *src = (DWORD *) src_d->lpSurface, *dst; | |
| surface = (DWORD *) HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, src_d->dwWidth * src_d->dwHeight * sizeof(DWORD)); | |
| dst = (DWORD *) surface; | |
| for (i = 0; i < src_d->dwHeight * src_d->dwWidth; i++) { | |
| DWORD color = *src++; | |
| *dst = color & 0xFFFFFF00; | |
| if ((color < src_d->ddckCKSrcBlt.dwColorSpaceLowValue) || | |
| (color > src_d->ddckCKSrcBlt.dwColorSpaceHighValue)) | |
| *dst |= color & 0x000000FF; | |
| dst++; | |
| } | |
| } | |
| format = GL_RGBA; | |
| pixel_format = GL_UNSIGNED_INT_8_8_8_8; | |
| } else if ((src_d->ddpfPixelFormat.u2.dwRBitMask == 0x00FF0000) && | |
| (src_d->ddpfPixelFormat.u3.dwGBitMask == 0x0000FF00) && | |
| (src_d->ddpfPixelFormat.u4.dwBBitMask == 0x000000FF) && | |
| (src_d->ddpfPixelFormat.u5.dwRGBAlphaBitMask == 0x00000000)) { | |
| /* Just add an alpha component and handle color-keying... */ | |
| DWORD i; | |
| DWORD *src = (DWORD *) src_d->lpSurface, *dst; | |
| surface = (DWORD *) HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, src_d->dwWidth * src_d->dwHeight * sizeof(DWORD)); | |
| dst = (DWORD *) surface; | |
| if (src_d->dwFlags & DDSD_CKSRCBLT) { | |
| for (i = 0; i < src_d->dwHeight * src_d->dwWidth; i++) { | |
| DWORD color = *src++; | |
| *dst = color << 8; | |
| if ((color < src_d->ddckCKSrcBlt.dwColorSpaceLowValue) || | |
| (color > src_d->ddckCKSrcBlt.dwColorSpaceHighValue)) | |
| *dst |= 0xFF; | |
| dst++; | |
| } | |
| } else { | |
| for (i = 0; i < src_d->dwHeight * src_d->dwWidth; i++) { | |
| *dst++ = (*src++ << 8) | 0xFF; | |
| } | |
| } | |
| format = GL_RGBA; | |
| pixel_format = GL_UNSIGNED_INT_8_8_8_8; | |
| } else { | |
| error = TRUE; | |
| } | |
| } else { | |
| error = TRUE; | |
| } | |
| } else { | |
| error = TRUE; | |
| } | |
| if ((upload_done == FALSE) && (error == FALSE)) { | |
| if (glThis->initial_upload_done == FALSE) { | |
| glTexImage2D(GL_TEXTURE_2D, | |
| This->mipmap_level, | |
| format, | |
| src_d->dwWidth, src_d->dwHeight, | |
| 0, | |
| format, | |
| pixel_format, | |
| surface == NULL ? src_d->lpSurface : surface); | |
| glThis->initial_upload_done = TRUE; | |
| } else { | |
| glTexSubImage2D(GL_TEXTURE_2D, | |
| This->mipmap_level, | |
| 0, 0, | |
| src_d->dwWidth, src_d->dwHeight, | |
| format, | |
| pixel_format, | |
| surface == NULL ? src_d->lpSurface : surface); | |
| } | |
| if (surface) HeapFree(GetProcessHeap(), 0, surface); | |
| } else if (error == TRUE) { | |
| if (ERR_ON(ddraw)) { | |
| ERR("Unsupported pixel format for textures : \n"); | |
| DDRAW_dump_pixelformat(&src_d->ddpfPixelFormat); | |
| } | |
| } | |
| glThis->dirty_flag = FALSE; | |
| 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; | |
| glThis->dirty_flag = TRUE; | |
| return DD_OK; | |
| } | |
| 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; | |
| /* First call the previous set_palette function */ | |
| glThis->set_palette(This, pal); | |
| /* And set the dirty flag */ | |
| glThis->dirty_flag = TRUE; | |
| } | |
| 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(); | |
| /* 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 = TRUE; | |
| } | |
| HRESULT WINAPI | |
| GL_IDirect3DTextureImpl_2_1T_Load(LPDIRECT3DTEXTURE2 iface, | |
| LPDIRECT3DTEXTURE2 lpD3DTexture2) | |
| { | |
| ICOM_THIS_FROM(IDirectDrawSurfaceImpl, IDirect3DTexture2, iface); | |
| IDirect3DTextureGLImpl *glThis = (IDirect3DTextureGLImpl *) This->tex_private; | |
| IDirectDrawSurfaceImpl *lpD3DTextureImpl = ICOM_OBJECT(IDirectDrawSurfaceImpl, IDirect3DTexture2, lpD3DTexture2); | |
| DWORD mem_used; | |
| DDSURFACEDESC *src_d, *dst_d; | |
| HRESULT ret_value = D3D_OK; | |
| TRACE("(%p/%p)->(%p)\n", This, iface, lpD3DTexture2); | |
| if (glThis != NULL) { | |
| if (glThis->loaded == FALSE) { | |
| /* Only check memory for not already loaded texture... */ | |
| mem_used = This->surface_desc.dwHeight * | |
| This->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; | |
| } | |
| } | |
| glThis->loaded = TRUE; | |
| } | |
| TRACE("Copied surface %p to surface %p\n", lpD3DTextureImpl, This); | |
| if ( This->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 ( !(This->surface_desc.ddsCaps.dwCaps & (DDSCAPS_SYSTEMMEMORY|DDSCAPS_VIDEOMEMORY)) ) | |
| This->surface_desc.ddsCaps.dwCaps |= DDSCAPS_VIDEOMEMORY; | |
| /* Suppress the ALLOCONLOAD flag */ | |
| This->surface_desc.ddsCaps.dwCaps &= ~DDSCAPS_ALLOCONLOAD; | |
| /* After seeing some logs, not sure at all about this... */ | |
| if (This->palette == NULL) { | |
| This->palette = lpD3DTextureImpl->palette; | |
| if (lpD3DTextureImpl->palette != NULL) IDirectDrawPalette_AddRef(ICOM_INTERFACE(lpD3DTextureImpl->palette, | |
| IDirectDrawPalette)); | |
| } else { | |
| if (lpD3DTextureImpl->palette != NULL) { | |
| PALETTEENTRY palent[256]; | |
| IDirectDrawPalette *pal_int = ICOM_INTERFACE(lpD3DTextureImpl->palette, IDirectDrawPalette); | |
| IDirectDrawPalette_GetEntries(pal_int, 0, 0, 256, palent); | |
| IDirectDrawPalette_SetEntries(ICOM_INTERFACE(This->palette, IDirectDrawPalette), | |
| 0, 0, 256, palent); | |
| } | |
| } | |
| /* Copy one surface on the other */ | |
| dst_d = (DDSURFACEDESC *)&(This->surface_desc); | |
| src_d = (DDSURFACEDESC *)&(lpD3DTextureImpl->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 (glThis != NULL) { | |
| /* If the GetHandle was not done, it is an error... */ | |
| if (glThis->tex_name == 0) ERR("Unbound GL texture !!!\n"); | |
| /* Set this texture as dirty */ | |
| glThis->dirty_flag = TRUE; | |
| } | |
| } | |
| 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(IDirect3DImpl *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; | |
| 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 created for surface %p (private data at %p and GL id %d).\n", surf, private, private->tex_name); | |
| } else { | |
| private->tex_name = ((IDirect3DTextureGLImpl *) (main->tex_private))->tex_name; | |
| TRACE(" GL texture created for surface %p (private data at %p and GL id reusing id %d from surface %p (%p)).\n", | |
| surf, private, private->tex_name, main, main->tex_private); | |
| } | |
| LEAVE_GL(); | |
| /* And set the dirty flag accordingly */ | |
| private->dirty_flag = (at_creation == FALSE); | |
| private->initial_upload_done = FALSE; | |
| } | |
| return D3D_OK; | |
| } |