Creating Texture Surfaces

[Previous] [Next]

In Microsoft DirectX 7, textures are actually DirectDraw surfaces. To create a new surface for a texture and copy a bitmap as a texture into it, you could use the following CreateTextureFromBitmap routine. This routine also turns on texture management (described later) for hardware Direct3D devices.

 //------------------------------------------------------------------- // Name: CreateTextureFromBitmap // Desc: Uses a bitmap to create a texture for the specified device.  //       This code gets the attributes of the texture from the  //       bitmap, creates the texture, and then copies the bitmap into //       the texture. //------------------------------------------------------------------- static LPDIRECTDRAWSURFACE7 CreateTextureFromBitmap(                                  LPDIRECT3DDEVICE7 pd3dDevice,                                 HBITMAP hbm ) {     LPDIRECTDRAWSURFACE7 pddsTexture;     HRESULT hr;     // Get the device caps so that you can check whether the device      // has any constraints when using textures.     D3DDEVICEDESC7 ddDesc;     if( FAILED( pd3dDevice->GetCaps( &ddDesc ) ) )         return NULL;     // Get the bitmap structure (to extract width, height, and bpp).     BITMAP bm;     GetObject( hbm, sizeof(BITMAP), &bm );     DWORD dwWidth  = (DWORD)bm.bmWidth;     DWORD dwHeight = (DWORD)bm.bmHeight;     // Set up the new surface description for the texture. Because      // we're using the texture management attribute, Direct3D does     // a lot of the dirty work for us.     DDSURFACEDESC2 ddsd;     ZeroMemory( &ddsd, sizeof(DDSURFACEDESC2) );     ddsd.dwSize          = sizeof(DDSURFACEDESC2);     ddsd.dwFlags         = DDSD_CAPS | DDSD_HEIGHT |                            DDSD_WIDTH | DDSD_PIXELFORMAT;     ddsd.ddsCaps.dwCaps  = DDSCAPS_TEXTURE;     ddsd.dwWidth         = dwWidth;     ddsd.dwHeight        = dwHeight;     // Turn on texture management for hardware devices.     if( ddDesc.deviceGUID == IID_IDirect3DHALDevice )         ddsd.ddsCaps.dwCaps2 = DDSCAPS2_TEXTUREMANAGE;     else if( ddDesc.deviceGUID == IID_IDirect3DTnLHalDevice )         ddsd.ddsCaps.dwCaps2 = DDSCAPS2_TEXTUREMANAGE;     else         ddsd.ddsCaps.dwCaps |= DDSCAPS_SYSTEMMEMORY;     // Adjust width and height if the driver requires you to.     if( ddDesc.dpcTriCaps.dwTextureCaps & D3DPTEXTURECAPS_POW2 )     {         for( ddsd.dwWidth=1;  dwWidth>ddsd.dwWidth;              ddsd.dwWidth<<=1 );         for( ddsd.dwHeight=1; dwHeight>ddsd.dwHeight;              ddsd.dwHeight<<=1 );     }     if( ddDesc.dpcTriCaps.dwTextureCaps & D3DPTEXTURECAPS_SQUAREONLY )     {         if( ddsd.dwWidth > ddsd.dwHeight )             ddsd.dwHeight = ddsd.dwWidth;         else             ddsd.dwWidth  = ddsd.dwHeight;     }     // Enumerate the texture formats, and find the closest device-     // supported texture pixel format. The TextureSearchCallback      // function here is simply looking for a 16-bit texture. Real      // applications might be interested in other formats, such as     // for alpha textures, bump maps, and so on.     pd3dDevice->EnumTextureFormats( TextureSearchCallback,                                      &ddsd.ddpfPixelFormat );     if( 0L == ddsd.ddpfPixelFormat.dwRGBBitCount )         return NULL;     // Get the device's render target so that we can use the render      // target to get a pointer to a DDraw object. We need the      // DirectDraw interface for creating surfaces.     LPDIRECTDRAWSURFACE7 pddsRender;     LPDIRECTDRAW7        pDD;     pd3dDevice->GetRenderTarget( &pddsRender );     pddsRender->GetDDInterface( (VOID**)&pDD );     pddsRender->Release();     // Create a new surface for the texture.     if( FAILED( hr = pDD->CreateSurface( &ddsd, &pddsTexture,                                          NULL ) ) )     {         pDD->Release();         return NULL;     }     // Done with DDraw.     pDD->Release();     // Now copy the bitmap to the texture surface. To do this, we're     // creating a device context (DC) for the bitmap and a DC for      // the surface so that we can use the BitBlt() call to copy the     // actual bits.     // Get a DC for the bitmap.     HDC hdcBitmap = CreateCompatibleDC( NULL );     if( NULL == hdcBitmap )     {         pddsTexture->Release();         return NULL;     }     SelectObject( hdcBitmap, hbm );     // Get a DC for the surface.     HDC hdcTexture;     if( SUCCEEDED( pddsTexture->GetDC( &hdcTexture ) ) )     {         // Copy the bitmap image to the surface.         BitBlt( hdcTexture, 0, 0, bm.bmWidth, bm.bmHeight, hdcBitmap,                 0, 0, SRCCOPY );         pddsTexture->ReleaseDC( hdcTexture );     }     DeleteDC( hdcBitmap );     // Return the newly created texture.     return pddsTexture; } 

Palettized Textures

Although a simple texture surface like the one in the previous code will work for many texturing needs, you'll often want to use more advanced approaches so that your applications use less memory or to enhance the application's visual effects. The first of these approaches involves using palettized textures, which are texture surfaces that use an attached palette. Palettized textures represent the simplest form of texture compression (which is described later in this chapter). Palettized textures are DirectDrawSurface7 objects that you create by specifying the DDSCAPS_TEXTURE flag and using one of the DDPF_PALETTEINDEXEDn pixel formats (in which n is 1, 2, 4, or 8). Palettized textures allow you to save a large amount of memory (much more than using RGBA colors for every pixel allows) and are thus useful for many applications.

To create a palettized texture, you must specify the DirectDraw and Direct3D capabilities you need. Specify these capabilities in the DDSURFACEDESC2 structure used to create the surface. You specify dimensions for the surface when you create it, along with the DDSCAPS_TEXTURE flag and one of the DDPF_PALETTEINDEXEDn pixel-format flags. After creating this surface, you'll create and initialize a DirectDrawPalette object by using the IDirectDraw7::CreatePalette method.

The last step in creating a palettized texture is to attach the palette to a surface by using the IDirectDrawSurface7::SetPalette method. If you forget to attach the palette, an access violation will occur during rendering.

Each pixel in a palettized surface (a surface with a palette attached to it) is an index to a table of values held within the attached DirectDrawPalette object. You should use the IDirect3DDevice7::EnumTextureFormats method to identify the texture formats that the current driver supports.

The following code shows how to create a texture that uses a palette:

 //------------------------------------------------------------------- // Name: CopyBitmapToSurface // Desc: Copies the image of a bitmap into a surface //------------------------------------------------------------------- HRESULT TextureContainer::CopyBitmapToSurface() {     // Get a DDraw object to create a temporary surface.     LPDIRECTDRAW7 pDD;     m_pddsSurface->GetDDInterface( (VOID**)&pDD );     // Get the bitmap structure (to extract width, height, and bpp).     BITMAP bm;     GetObject( m_hbmBitmap, sizeof(BITMAP), &bm );     // Set up the new surface description.     DDSURFACEDESC2 ddsd;     ddsd.dwSize = sizeof(ddsd);     m_pddsSurface->GetSurfaceDesc( &ddsd );     ddsd.dwFlags          = DDSD_CAPS | DDSD_HEIGHT | DDSD_WIDTH |                             DDSD_PIXELFORMAT | DDSD_TEXTURESTAGE;     ddsd.ddsCaps.dwCaps   = DDSCAPS_TEXTURE | DDSCAPS_SYSTEMMEMORY;     ddsd.ddsCaps.dwCaps2  = 0L;     ddsd.dwWidth          = bm.bmWidth;     ddsd.dwHeight         = bm.bmHeight;     // Create a new surface for the texture.     LPDIRECTDRAWSURFACE7 pddsTempSurface;     HRESULT hr;     if( FAILED( hr = pDD->CreateSurface( &ddsd, &pddsTempSurface,                                          NULL ) ) )     {         pDD->Release();         return hr;     }     // Get a DC for the bitmap.     HDC hdcBitmap = CreateCompatibleDC( NULL );     if( NULL == hdcBitmap )     {         pddsTempSurface->Release();         pDD->Release();         return hr;     }     SelectObject( hdcBitmap, m_hbmBitmap );     // Handle palettized textures. You'll need to attach a palette.     if( ddsd.ddpfPixelFormat.dwRGBBitCount == 8 )     {         LPDIRECTDRAWPALETTE  pPalette;         DWORD dwPaletteFlags = DDPCAPS_8BIT|DDPCAPS_ALLOW256;         DWORD pe[256];         WORD  wNumColors     = GetDIBColorTable( hdcBitmap, 0, 256,                                                   (RGBQUAD*)pe );         // Create the color table.         for( WORD i=0; i<wNumColors; i++ )         {             pe[i] = RGB(GetBValue(pe[i]),                         GetGValue(pe[i]),                         GetRValue(pe[i]));             // Handle textures with transparent pixels.             if( m_dwFlags & (D3DTEXTR_TRANSPARENTWHITE |                              D3DTEXTR_TRANSPARENTBLACK) )             {                 // Set alpha for opaque pixels.                 if( m_dwFlags & D3DTEXTR_TRANSPARENTBLACK )                 {                     if( pe[i] != 0x00000000 )                         pe[i] |= 0xff000000;                 }                 else if( m_dwFlags & D3DTEXTR_TRANSPARENTWHITE )                 {                     if( pe[i] != 0x00ffffff )                         pe[i] |= 0xff000000;                 }             }         }         // Add the DDPCAPS_ALPHA flag for textures with transparent         // pixels.         if( m_dwFlags & (D3DTEXTR_TRANSPARENTWHITE |                          D3DTEXTR_TRANSPARENTBLACK))             dwPaletteFlags |= DDPCAPS_ALPHA;         // Create and attach a palette.         pDD->CreatePalette(dwPaletteFlags,(PALETTEENTRY*)pe,                            &pPalette, NULL);         pddsTempSurface->SetPalette( pPalette );         m_pddsSurface->SetPalette( pPalette );         SAFE_RELEASE( pPalette );     }     // Copy the bitmap image to the surface.     HDC hdcSurface;     if( SUCCEEDED( pddsTempSurface->GetDC( &hdcSurface ) ) )     {         BitBlt( hdcSurface, 0, 0, bm.bmWidth, bm.bmHeight, hdcBitmap,                 0, 0, SRCCOPY );         pddsTempSurface->ReleaseDC( hdcSurface );     }     DeleteDC( hdcBitmap );     // Copy the temporary surface to the real texture surface.     m_pddsSurface->Blt( NULL, pddsTempSurface, NULL,                         DDBLT_WAIT, NULL );     // Done with the temporary surface.     pddsTempSurface->Release();     // For textures with real alpha (not palettized), set     // transparent bits.     if( ddsd.ddpfPixelFormat.dwRGBAlphaBitMask )     {         if(m_dwFlags & (D3DTEXTR_TRANSPARENTWHITE |                         D3DTEXTR_TRANSPARENTBLACK) )         {             // Lock the texture surface.             DDSURFACEDESC2 ddsd;             ddsd.dwSize = sizeof(ddsd);             while( m_pddsSurface->Lock( NULL, &ddsd, 0, NULL ) ==                    DDERR_WASSTILLDRAWING );             DWORD dwAlphaMask =                 ddsd.ddpfPixelFormat.dwRGBAlphaBitMask;             DWORD dwRGBMask   = ( ddsd.ddpfPixelFormat.dwRBitMask |                                   ddsd.ddpfPixelFormat.dwGBitMask |                                   ddsd.ddpfPixelFormat.dwBBitMask );             DWORD dwColorkey  = 0x00000000; // Color key on black             if( m_dwFlags & D3DTEXTR_TRANSPARENTWHITE )                 dwColorkey = dwRGBMask;     // Color key on white             // Add an opaque alpha value to each non-color-keyed pixel.             for( DWORD y=0; y<ddsd.dwHeight; y++ )             {                 WORD*  p16 =                     (WORD*)((BYTE*)ddsd.lpSurface + y*ddsd.lPitch);                 DWORD* p32 =                    (DWORD*)((BYTE*)ddsd.lpSurface + y*ddsd.lPitch);                 for( DWORD x=0; x<ddsd.dwWidth; x++ )                 {                     if( ddsd.ddpfPixelFormat.dwRGBBitCount == 16 )                     {                         if( ( *p16 &= dwRGBMask ) != dwColorkey )                             *p16 |= dwAlphaMask;                         p16++;                     }                     if( ddsd.ddpfPixelFormat.dwRGBBitCount == 32 )                     {                         if( ( *p32 &= dwRGBMask ) != dwColorkey )                             *p32 |= dwAlphaMask;                         p32++;                     }                 }             }             m_pddsSurface->Unlock( NULL );         }     }     pDD->Release();     return S_OK; } 



Inside Direct3D
Inside Direct3D (Dv-Mps Inside)
ISBN: 0735606137
EAN: 2147483647
Year: 1999
Pages: 131

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net