windows-nt/Source/XPSP1/NT/multimedia/opengl/client/ddtex.c
2020-09-26 16:20:57 +08:00

546 lines
14 KiB
C

/******************************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;
}