0
\$\begingroup\$

The following is my working code. Everything functions and I can animate my sprite but the sprite has no transparency color. It has a white background on every frame. I am using DirectX 7.0 and 32BPP BMP files. My sprite is in a rectangular box. It uses 2D images and I have my own code to animate in 3D using static images, to fool the observer.

void Surface::Create(int width, int height, SURFACE &the_surface)
{
    TRACE("Surface::Create invoked width = %i height = %0i\n", width, height); // the width and height in this TRACE statement must equal that in Surface::Write 

    LPDIRECTDRAW7 pDDraw = Video::GetDdraw(); 
    
    // clear the structure
    memset(&the_surface.desc, 0, sizeof(the_surface.desc));
    the_surface.desc.dwSize = sizeof(the_surface.desc);

    //memset(&the_surface.ddsurf, 0, sizeof(the_surface.ddsurf));
    
    // --------
    //
    // We want to allocate system memory to cache the bit map image
    // that is not the primary surface or back buffer surface
    // later we will want to detect direct draw hardware so we
    // can write to either system memory or video memory
    // by defualt we write to system memory
    the_surface.desc.dwFlags = DDSD_CAPS | DDSD_HEIGHT | DDSD_WIDTH;
    the_surface.desc.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN | DDSCAPS_SYSTEMMEMORY;
    the_surface.desc.dwWidth        = width;
    the_surface.desc.dwHeight       = height;
    
    try
    {
        //
        // create a complex implicit surface and attach it to ddraw
        // this surface may NOT be detached 
        if (width < 1 || height < 1)            
            throw SURFACE_EXCEPTION;    // should never be here
        hrRetVal = pDDraw->CreateSurface(&the_surface.desc, &the_surface.ddsurf, NULL);
        if (DD_OK != hrRetVal)
            throw SURFACE_EXCEPTION;

        //
        SetColorKey(1,1,the_surface);   // what color do we want to be transparent? default = white my sprite background is white
    }

    catch ( int exception )
    {
        TRACE("%Xh exception caught by Surface::Create hrRetVal was: ", exception);
        Surface::Check(hrRetVal);
        if (exception == SURFACE_EXCEPTION)
        {
            TRACE("SURFACE_EXCEPTION caught by Surface::Create, width = %i, height = %i\n", width, height);
            TRACE("VIDEO_EXCEPTION thrown by Surface::Create\n");
            throw (VIDEO_EXCEPTION);
        }
    }  // end catch
}

void Surface::Write(IMAGE &an_image, SURFACE &into_surface)
{
    TRACE("Surface::Write invoked width = %d height = %d\n", an_image.width, an_image.height); // the width and height in this TRACE statement must equal that in Surface::Create 
    try
    {
        // what part of the surface do we want to lock?
        // all of it
        into_surface.surfrect.left   = 0;
        into_surface.surfrect.top    = 0;
        into_surface.surfrect.right  = an_image.width;
        into_surface.surfrect.bottom = an_image.height;
                            
        // frame-buffer access
        // obtain access to the entire direct draw surface created by Surface::Create
        hrRetVal = into_surface.ddsurf->Lock(&into_surface.surfrect, &into_surface.desc, DDLOCK_SURFACEMEMORYPTR | DDLOCK_NOSYSLOCK | DDLOCK_WAIT, 0);
        if (DD_OK != hrRetVal)
            throw (SURFACE_EXCEPTION);

        //-------------
        //
        // Copy bitmap bits from bmp image to direct draw surface
        //
        DWORD* to_video = (DWORD*)(into_surface.desc.lpSurface);                    // cast the surface pointer
        DWORD* from_image = (DWORD*)(&an_image.buffer[((an_image.width) * (an_image.height - 1))]);
        DWORD pixelsperrow = into_surface.desc.lPitch / (BYTESPERPIXEL);
        DWORD* SurfacePtr = (DWORD*)into_surface.desc.lpSurface;                // cast the surface pointer

        // copy a row at a time
        for (int i = 0; i < an_image.height; i++)           // copy from [0,0] upper left to [0, image height]
        {
                wmemcpy((wchar_t*)to_video, (wchar_t*)from_image, an_image.width * 2);      // copy to_video system memory, from bmp image count of characters to copy in this case, copy the entire line
                
                to_video += pixelsperrow;                   // next line in video, lPitch is returned by lock

                // previous line in memory
                from_image -= an_image.width;
        }
        // release access of the direct draw surface important
        hrRetVal = into_surface.ddsurf->Unlock(NULL);
        if ( DD_OK != hrRetVal)
            throw (SURFACE_EXCEPTION);
    }  // end try

    catch ( int exception )
    {
        TRACE("%Xh exception caught by Surface::Write hrRetVal was: ", exception);
        Check(hrRetVal);
    }  // end catch
}

void Surface::Show(int row, int col, SURFACE &the_surface)
{
    TRACE("Surface::Show invoked.\n");

    LPDIRECTDRAWSURFACE7 backsurf = Video::GetBackSurface();

    // perform a source copy blit or transparent blit using a source
    // or destination color key. This method will always attempt an
    // asynchronous blit if this is supported by the hardware

    TRACE("surface.rect TR = [%d, %d] BL = [%d, %d]\n", the_surface.surfrect.top, the_surface.surfrect.left, the_surface.surfrect.bottom, the_surface.surfrect.right);
    hrRetVal = backsurf->BltFast(row, col, the_surface.ddsurf, &the_surface.surfrect, DDBLTFAST_SRCCOLORKEY | DDBLTFAST_WAIT);
    if ( DD_OK != hrRetVal)
    {
        TRACE("Surface::Show hrRetVal was: ");
        Check(hrRetVal);
    }
}

void Surface::SetColorKey(DWORD low,DWORD high, SURFACE &the_surface)
{
    TRACE("Surface::SetColorKey invoked\n");
    DDCOLORKEY ddck;    // transparent colors
    
    ddck.dwColorSpaceLowValue=low;
    ddck.dwColorSpaceHighValue=high;

    TRACE("ColorKey is Low = %u, High = %u\n", low, high);
        
    hrRetVal = the_surface.ddsurf->SetColorKey(DDCKEY_SRCBLT, &ddck);
    Check(hrRetVal);
}
\$\endgroup\$
2
  • \$\begingroup\$ You're using a method that works with colour-key transparency. That's like when you find a spritesheet where the background is all a painful lime green or magenta to say "don't draw this pixel". It sounds like what you want is alpha-blended transparency, where you have a separate colour channel that contains a translucency value that can be anywhere between completely opaque and completely invisible, with partially see-through in-between. Alpha transparency is not what BltFast does, because it requires blending colour values, not just copying (blitting) them. \$\endgroup\$
    – DMGregory
    Dec 8 '20 at 16:39
  • \$\begingroup\$ Thank you for the insight. I have a no code sample of the executable and graphics files. Here: github.com/david-harding I have since implemented the gamepad code from xinput.h as recommended in another post. The arrows cause the sprite to move and escape will terminate the program. I created the gfx files with a sprite librarian I will go back and look to see how I handle the alpha channel. Thank you again. -- davidh \$\endgroup\$
    – DHarding
    Dec 8 '20 at 17:03
0
\$\begingroup\$
// we load 32 bit BMP files into a directx back surface
// first we setup the directx primary surface and back surface
// we then instantiate a SURFACE class object, which when created we set the color key
// here this method is called for all surfaces, equally for background or sprite ADT
// for the sprite ADT we are usign a cirularly linked dynamic queue template which works nicely
// for loading all of a given sprites bmp images
// in my case we converted legacy 8 bit bmp files to 32 bit using NCH Suite of software specifically Pixillion Plus Image Converter
//
// The solution to the post was the one line consiting of: SetColorKey(0xffffff, 0xffffff, the_surface);
//
// we also took previous feedback to heart and change BltFast to Blt in Surface::Show.
// i.e. hrRetVal = frontsurf->Blt(&rcFill, the_surface.ddsurf, (tagRECT*)&the_surface.surfrect, DDBLT_WAIT | DDBLT_KEYSRC, &the_surface.ddbltfx);
// Following is the working code
void Surface::Create(int width, int height, SURFACE &the_surface)
{
    TRACE("Surface::Create invoked width = %i height = %0i\n", width, height); // the width and height in this TRACE statement must equal that in Surface::Write 

    LPDIRECTDRAW7 pDDraw = Video::GetDdraw(); 
        
    memset(&the_surface.desc, 0, sizeof(the_surface.desc));
    the_surface.desc.dwSize = sizeof(the_surface.desc);

    
    // --------
    //
    // We want to allocate system memory to cache the bit map image
    // that is not the primary surface or back buffer surface
    // later we will want to detect direct draw hardware so we
    // can write to either system memory or video memory
    the_surface.desc.dwFlags = DDSD_CAPS | DDSD_HEIGHT | DDSD_WIDTH; 
    the_surface.desc.ddsCaps.dwCaps = DDSCAPS_VIDEOMEMORY;
    the_surface.desc.dwWidth        = width;
    the_surface.desc.dwHeight       = height;
    
    try
    {
    
        //
        // create a complex implicit surface and attach it to ddraw
        // this surface may NOT be detached 
        if (width < 1 || height < 1)
            throw SURFACE_EXCEPTION;
        hrRetVal = pDDraw->CreateSurface(&the_surface.desc, &the_surface.ddsurf, NULL);
        if (DD_OK != hrRetVal)
            throw SURFACE_EXCEPTION;

        // the next line of code is the solution to this post
        SetColorKey(0xffffff, 0xffffff, the_surface); // what color do we want to be transparent? default = white; using white

    }


    catch ( int exception )
    {

        TRACE("%Xh exception caught by Surface::Create hrRetVal was: ", exception);
        Surface::Check(hrRetVal);
        if (exception == SURFACE_EXCEPTION)
        {
            TRACE("SURFACE_EXCEPTION caught by Surface::Create, width = %i, height = %i\n", width, height);
            TRACE("VIDEO_EXCEPTION thrown by Surface::Create\n");
            throw (VIDEO_EXCEPTION);
        }

    }  // end catch

} // end Surface::Create
\$\endgroup\$

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .