/******************************Module*Header*******************************\ * Module Name: ddtex.c * * wgl DirectDraw texture support * * Created: 02-10-1997 * Author: Drew Bliss [drewb] * * Copyright (c) 1993-1997 Microsoft Corporation \**************************************************************************/ #include "precomp.h" #pragma hdrstop #include "gencx.h" // Simple surface description for supported texture formats #define DDTF_BGRA 0 #define DDTF_BGR 1 #define DDTF_PALETTED 2 typedef struct _DDTEXFORMAT { int iFormat; int cColorBits; } DDTEXFORMAT; // Supported formats static DDTEXFORMAT ddtfFormats[] = { DDTF_BGRA, 32, DDTF_BGR, 32, DDTF_PALETTED, 8 }; #define NDDTF (sizeof(ddtfFormats)/sizeof(ddtfFormats[0])) /******************************Public*Routine******************************\ * * DescribeDdtf * * Fill out a DDSURFACEDESC from a DDTEXFORMAT * * History: * Tue Sep 03 18:16:50 1996 -by- Drew Bliss [drewb] * Created * \**************************************************************************/ void DescribeDdtf(DDTEXFORMAT *pddtf, DDSURFACEDESC *pddsd) { memset(pddsd, 0, sizeof(*pddsd)); pddsd->dwSize = sizeof(*pddsd); pddsd->dwFlags = DDSD_CAPS | DDSD_PIXELFORMAT; pddsd->ddsCaps.dwCaps = DDSCAPS_MIPMAP | DDSCAPS_TEXTURE; pddsd->ddpfPixelFormat.dwFlags = DDPF_RGB; pddsd->ddpfPixelFormat.dwRGBBitCount = pddtf->cColorBits; switch(pddtf->iFormat) { case DDTF_BGRA: pddsd->dwFlags |= DDSD_ALPHABITDEPTH; pddsd->dwAlphaBitDepth = pddtf->cColorBits/4; pddsd->ddsCaps.dwCaps |= DDSCAPS_ALPHA; pddsd->ddpfPixelFormat.dwFlags |= DDPF_ALPHAPIXELS; // Fall through case DDTF_BGR: switch(pddtf->cColorBits) { case 32: pddsd->ddpfPixelFormat.dwRBitMask = 0xff0000; pddsd->ddpfPixelFormat.dwGBitMask = 0xff00; pddsd->ddpfPixelFormat.dwBBitMask = 0xff; if (pddtf->iFormat == DDTF_BGRA) { pddsd->ddpfPixelFormat.dwRGBAlphaBitMask = 0xff000000; } break; } break; case DDTF_PALETTED: switch(pddtf->cColorBits) { case 1: pddsd->ddpfPixelFormat.dwFlags |= DDPF_PALETTEINDEXED1; break; case 2: pddsd->ddpfPixelFormat.dwFlags |= DDPF_PALETTEINDEXED2; break; case 4: pddsd->ddpfPixelFormat.dwFlags |= DDPF_PALETTEINDEXED4; break; case 8: pddsd->ddpfPixelFormat.dwFlags |= DDPF_PALETTEINDEXED8; break; } break; } } /******************************Public*Routine******************************\ * * CacheTextureFormats * * Creates list of valid texture formats for a context * * History: * Fri Sep 27 16:14:29 1996 -by- Drew Bliss [drewb] * Created * \**************************************************************************/ BOOL CacheTextureFormats(PLRC plrc) { int i; int nFmts; int nMcdFmts; DDTEXFORMAT *pddtf; DDSURFACEDESC *pddsdAlloc, *pddsd; __GLGENcontext *gengc; ASSERTOPENGL(plrc->pddsdTexFormats == NULL, "CacheTextureFormats overwriting cache\n"); if (plrc->dhrc != 0) { // Call the ICD if (plrc->pGLDriver->pfnDrvEnumTextureFormats == NULL) { nFmts = 0; } else { nFmts = plrc->pGLDriver->pfnDrvEnumTextureFormats(0, NULL); if (nFmts < 0) { return FALSE; } } } else { gengc = (__GLGENcontext *)GLTEB_SRVCONTEXT(); ASSERTOPENGL(gengc != NULL, "No server context\n"); nFmts = NDDTF; nMcdFmts = 0; #if MCD_VER_MAJOR >= 2 || (MCD_VER_MAJOR == 1 && MCD_VER_MINOR >= 0x10) if (gengc->pMcdState != NULL && McdDriverInfo.mcdDriver.pMCDrvGetTextureFormats != NULL) { nMcdFmts = GenMcdGetTextureFormats(gengc, 0, NULL); if (nMcdFmts < 0) { SetLastError(ERROR_NOT_ENOUGH_MEMORY); return FALSE; } nFmts += nMcdFmts; } #endif // 1.1 } pddsdAlloc = (DDSURFACEDESC *)ALLOC(sizeof(DDSURFACEDESC)*nFmts); if (pddsdAlloc == NULL) { return FALSE; } if (plrc->dhrc != 0) { if (nFmts > 0) { nFmts = plrc->pGLDriver->pfnDrvEnumTextureFormats(nFmts, pddsdAlloc); if (nFmts < 0) { FREE(pddsdAlloc); return FALSE; } } } else { pddsd = pddsdAlloc; pddtf = ddtfFormats; for (i = 0; i < NDDTF; i++) { DescribeDdtf(pddtf, pddsd); pddtf++; pddsd++; } if (gengc->pMcdState != NULL && nMcdFmts > 0) { nMcdFmts = GenMcdGetTextureFormats(gengc, nMcdFmts, pddsd); if (nMcdFmts < 0) { FREE(pddsdAlloc); SetLastError(ERROR_NOT_ENOUGH_MEMORY); return FALSE; } } } plrc->pddsdTexFormats = pddsdAlloc; plrc->nDdTexFormats = nFmts; return TRUE; } /******************************Public*Routine******************************\ * * wglEnumTextureFormats * * Enumerates texture formats supported for DirectDraw surfaces * * History: * Tue Sep 03 17:52:17 1996 -by- Drew Bliss [drewb] * Created * \**************************************************************************/ #ifdef ALLOW_DDTEX BOOL WINAPI wglEnumTextureFormats(WGLENUMTEXTUREFORMATSCALLBACK pfnCallback, LPVOID pvUser) { int i; DDSURFACEDESC *pddsd; BOOL bRet = TRUE; PLRC plrc; plrc = GLTEB_CLTCURRENTRC(); if (plrc == NULL) { SetLastError(ERROR_INVALID_FUNCTION); return FALSE; } glFlush(); if (plrc->pddsdTexFormats == NULL && !CacheTextureFormats(plrc)) { return FALSE; } pddsd = plrc->pddsdTexFormats; for (i = 0; i < plrc->nDdTexFormats; i++) { if (!pfnCallback(pddsd, pvUser)) { break; } pddsd++; } // Should this return FALSE if the enumeration was terminated? return bRet; } #endif /******************************Public*Routine******************************\ * * wglBindDirectDrawTexture * * Makes a DirectDraw surface the current 2D texture source * * History: * Tue Sep 03 17:53:43 1996 -by- Drew Bliss [drewb] * Created * \**************************************************************************/ BOOL WINAPI wglBindDirectDrawTexture(LPDIRECTDRAWSURFACE pdds) { DDSURFACEDESC ddsd; int i; DDSURFACEDESC *pddsd; __GLcontext *gc; int iLev = 0; PLRC plrc; LPDIRECTDRAWSURFACE apdds[__GL_WGL_MAX_MIPMAP_LEVEL]; GLuint ulFlags; plrc = GLTEB_CLTCURRENTRC(); if (plrc == NULL) { SetLastError(ERROR_INVALID_FUNCTION); return FALSE; } glFlush(); if (plrc->dhrc != 0) { if (plrc->pGLDriver->pfnDrvBindDirectDrawTexture == NULL) { SetLastError(ERROR_INVALID_FUNCTION); return FALSE; } } else { gc = (__GLcontext *)GLTEB_SRVCONTEXT(); ASSERTOPENGL(gc != NULL, "No server context\n"); } if (pdds == NULL) { // Clear any previous binding if (plrc->dhrc != 0) { return plrc->pGLDriver->pfnDrvBindDirectDrawTexture(pdds); } else { glsrvUnbindDirectDrawTexture(gc); // If we're just unbinding, we're done return TRUE; } } memset(&ddsd, 0, sizeof(ddsd)); ddsd.dwSize = sizeof(ddsd); if (pdds->lpVtbl->GetSurfaceDesc(pdds, &ddsd) != DD_OK) { return FALSE; } // Surface must be a texture // Surface must have a width and height which are powers of two if ((ddsd.dwFlags & (DDSD_CAPS | DDSD_PIXELFORMAT | DDSD_WIDTH | DDSD_HEIGHT)) != (DDSD_CAPS | DDSD_PIXELFORMAT | DDSD_WIDTH | DDSD_HEIGHT) || (ddsd.ddsCaps.dwCaps & DDSCAPS_TEXTURE) == 0 || (ddsd.dwWidth & (ddsd.dwWidth-1)) != 0 || (ddsd.dwHeight & (ddsd.dwHeight-1)) != 0) { return FALSE; } // Surface must match a supported format if (plrc->pddsdTexFormats == NULL && !CacheTextureFormats(plrc)) { return FALSE; } pddsd = plrc->pddsdTexFormats; for (i = 0; i < plrc->nDdTexFormats; i++) { if (ddsd.ddpfPixelFormat.dwFlags & DDPF_RGB) { if (ddsd.ddpfPixelFormat.dwRGBBitCount == (DWORD)pddsd->ddpfPixelFormat.dwRGBBitCount) { if (ddsd.ddpfPixelFormat.dwRBitMask != pddsd->ddpfPixelFormat.dwRBitMask || ddsd.ddpfPixelFormat.dwGBitMask != pddsd->ddpfPixelFormat.dwGBitMask || ddsd.ddpfPixelFormat.dwBBitMask != pddsd->ddpfPixelFormat.dwBBitMask) { return FALSE; } else { break; } } } else { if ((ddsd.ddpfPixelFormat.dwFlags & (DDPF_PALETTEINDEXED1 | DDPF_PALETTEINDEXED2 | DDPF_PALETTEINDEXED4 | DDPF_PALETTEINDEXED8)) != (pddsd->ddpfPixelFormat.dwFlags & (DDPF_PALETTEINDEXED1 | DDPF_PALETTEINDEXED2 | DDPF_PALETTEINDEXED4 | DDPF_PALETTEINDEXED8))) { return FALSE; } else { break; } } pddsd++; } if (i == plrc->nDdTexFormats) { return FALSE; } ulFlags = 0; if (i < NDDTF) { ulFlags |= DDTEX_GENERIC_FORMAT; } if (plrc->dhrc != 0) { return plrc->pGLDriver->pfnDrvBindDirectDrawTexture(pdds); } pdds->lpVtbl->AddRef(pdds); // Track whether the texture is in video memory or not. ulFlags |= DDTEX_VIDEO_MEMORY; if ((ddsd.ddsCaps.dwCaps & DDSCAPS_VIDEOMEMORY) == 0) { ulFlags &= ~DDTEX_VIDEO_MEMORY; } // If mipmaps are given, all mipmaps must be present if (ddsd.ddsCaps.dwCaps & DDSCAPS_MIPMAP) { DWORD dwWidth; DWORD dwHeight; LONG lPitch; int cColorBits; LPDIRECTDRAWSURFACE pddsMipmap, pddsNext; DDSCAPS ddscaps; DDSURFACEDESC ddsdMipmap; // Determine pixel depth if (ddsd.ddpfPixelFormat.dwFlags & DDPF_PALETTEINDEXED1) { cColorBits = 1; } else if (ddsd.ddpfPixelFormat.dwFlags & DDPF_PALETTEINDEXED2) { cColorBits = 2; } else if (ddsd.ddpfPixelFormat.dwFlags & DDPF_PALETTEINDEXED4) { cColorBits = 4; } else if (ddsd.ddpfPixelFormat.dwFlags & DDPF_PALETTEINDEXED8) { cColorBits = 8; } else { ASSERTOPENGL(ddsd.ddpfPixelFormat.dwFlags & DDPF_RGB, "DDPF_RGB expected\n"); cColorBits = DdPixDepthToCount(pddsd->ddpfPixelFormat.dwRGBBitCount); } dwWidth = ddsd.dwWidth; dwHeight = ddsd.dwHeight; // Compute pitch from pixel depth. The generic texturing code // doesn't support a pitch that differs from the natural pitch // given the width and depth of the surface. lPitch = (cColorBits*dwWidth+7)/8; if (ddsd.lPitch != lPitch) { goto CleanMipmap; } pddsMipmap = pdds; ddscaps.dwCaps = DDSCAPS_TEXTURE | DDSCAPS_MIPMAP; ddsdMipmap.dwSize = sizeof(DDSURFACEDESC); for (;;) { apdds[iLev++] = pddsMipmap; if (pddsMipmap->lpVtbl-> GetSurfaceDesc(pddsMipmap, &ddsdMipmap) != DD_OK || ((ddsdMipmap.ddpfPixelFormat.dwFlags & DDPF_RGB) && ddsdMipmap.ddpfPixelFormat.dwRGBBitCount != ddsd.ddpfPixelFormat.dwRGBBitCount) || ((ddsdMipmap.ddpfPixelFormat.dwFlags & DDPF_RGB) == 0 && (ddsdMipmap.ddpfPixelFormat.dwFlags & (DDPF_PALETTEINDEXED1 | DDPF_PALETTEINDEXED2 | DDPF_PALETTEINDEXED4 | DDPF_PALETTEINDEXED8)) != (ddsd.ddpfPixelFormat.dwFlags & (DDPF_PALETTEINDEXED1 | DDPF_PALETTEINDEXED2 | DDPF_PALETTEINDEXED4 | DDPF_PALETTEINDEXED8))) || ddsdMipmap.dwWidth != dwWidth || ddsdMipmap.dwHeight != dwHeight || ddsdMipmap.lPitch != lPitch) { goto CleanMipmap; } if ((ddsdMipmap.ddsCaps.dwCaps & DDSCAPS_VIDEOMEMORY) == 0) { ulFlags &= ~DDTEX_VIDEO_MEMORY; } if (iLev > gc->constants.maxMipMapLevel || (dwWidth == 1 && dwHeight == 1)) { break; } if (pddsMipmap->lpVtbl-> GetAttachedSurface(pddsMipmap, &ddscaps, &pddsNext) != DD_OK) { goto CleanMipmap; } pddsMipmap = pddsNext; if (dwWidth != 1) { dwWidth >>= 1; lPitch >>= 1; } if (dwHeight != 1) { dwHeight >>= 1; } } } else { apdds[iLev++] = pdds; } if (glsrvBindDirectDrawTexture(gc, iLev, apdds, &ddsd, ulFlags)) { return TRUE; } CleanMipmap: while (--iLev >= 0) { apdds[iLev]->lpVtbl->Release(apdds[iLev]); } return FALSE; }