Lets do some graphics: DirectDraw, Part 1

I always wanted to do stuff with DirectDraw. And when I saw the iPhone UI the urge intensified. But somehow the topic seemed esoteric to me and eluded me for quite some time, or, to put it in other words, laziness won over me (:



Anyways, I was going through the Donuts sample game provided by Microsoft which comes with Win Mob 6 Professional SDK installation. Here is the path:



<InstallDir>\Samples\PocketPC\CPP\win32\directx\DDraw\Donuts2



It seemed a bit too complicated for a first timer and truly I was a held back a little. So I decided to go through some tutorials first  and stop trying to be superman (: This post is what I found. Its quite old and pretty basic but gives you good understanding of what things are and where they stand. Donuts started to make a little sense now (:



The post mentioned about a few samples like DDEX1, DDEX2 etc. and I saw that these were present in the same SDK directory. I was happy to have found a step by step tutorial for DirectDraw. But when I built and tried to run the samples on the emulator the applications failed with a message box saying "This device does not support backbuffers". Of course, you don’t have to be Einstein to figure that the emulator doesn’t support back buffers. Donuts was the only application that ran ): So I got back looking at Donuts’ code. I saw that they were handling the absense of a back buffer intelligently. They got the capabilities of the device:



    lpDD->lpVtbl->GetCaps(lpDD, &ddCaps, &ddHelCaps);



    if (!(ddCaps.ddsCaps.dwCaps & DDSCAPS_BACKBUFFER) || !(ddCaps.ddsCaps.dwCaps & DDSCAPS_FLIP))

    {

        bSingleBuffer = TRUE;

    }



and depending on whether the device supported back buffers or not created other appropriate buffers/surfaces



    // Create surfaces

    memset( &ddsd, 0, sizeof( ddsd ) );

    ddsd.dwSize = sizeof( ddsd );

    if (bSingleBuffer)

    {

        printf("bSingleBuffer is TRUE\n");

        ddsd.dwFlags = DDSD_CAPS;

        ddsd.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE;

    }

    else

    {

        printf("bSingleBuffer is FALSE\n");

        ddsd.dwFlags = DDSD_CAPS | DDSD_BACKBUFFERCOUNT;

        ddsd.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE | DDSCAPS_FLIP;

        ddsd.dwBackBufferCount = 1;

    }



    ddrval = lpDD->lpVtbl->CreateSurface( lpDD, &ddsd, &lpFrontBuffer, NULL );

    if (ddrval != DD_OK)

    {

        if (ddrval == DDERR_NOFLIPHW)

            return CleanupAndExit(TEXT("******** Display driver doesn’t support flipping surfaces. ********"));

 

        return CleanupAndExit(TEXT("CreateSurface FrontBuffer Failed!"));

    }



    if (bSingleBuffer)

    {

        ddsd.dwFlags = DDSD_WIDTH | DDSD_HEIGHT;

        ddsd.dwWidth = ScreenX;

        ddsd.dwHeight = ScreenY;

        ddrval = lpDD->lpVtbl->CreateSurface( lpDD, &ddsd, &lpBackBuffer, NULL );

        if (ddrval != DD_OK)

        {

            return CleanupAndExit(TEXT("CreateSurface BackBuffer Failed!"));

        }

    }

    else

    {

        ddrval = lpFrontBuffer->lpVtbl->EnumAttachedSurfaces( lpFrontBuffer, &lpBackBuffer, EnumFunction);

        if (ddrval != DD_OK)

        {

            return CleanupAndExit(TEXT("EnumAttachedSurfaces Failed!"));

        }

    }



So this was interesting. I thought I could try to do the same for the DDEX1 sample. I played around with the code a bit; added handling for single buffer changed the Flip() api into Blt(), because that is what Donuts did



    while( 1 )

    {

        if (bSingleBuffer)

        {

            //copy back buffer to front.

            ddrval = lpFrontBuffer->lpVtbl->Blt( lpFrontBuffer, &dest, lpBackBuffer, &src, dwTransType, NULL );

        }

        else

        {

            ddrval = lpFrontBuffer->lpVtbl->Flip( lpFrontBuffer, NULL, 0);

        }



        if( ddrval == DD_OK )

        {

            break;

        }

        if( ddrval == DDERR_SURFACELOST )

        {

            if( !RestoreSurfaces() )

            {

                return;

            }

        }

        if( ddrval != DDERR_WASSTILLDRAWING )

        {

            break;

        }

    }



And voila! It worked (: It showed a screen flip flopping with blinking text. If you have gone through the tutorial above you probably know what Flip() and Blt() do. The only problem I ran into was, to the Blt() function I was passing "DDBLT_KEYSRC" as the second last parameter, and it wasn’t showing anything. I tried "DDBLT_KEYDEST" too but same result. So since the final parameter (a pointer to a structure) was NULL anyways, I passed 0 as the second last parameter. It worked.



You can check the documentation of Blt() here.

More details about the changes I made to DDEX1 and other stuff about DirectDraw, coming soon.

Leave a Reply

Your email address will not be published. Required fields are marked *