Advertisement

What's wrong with LaMothe's bitmap loader?

Started by June 04, 2002 01:49 PM
12 comments, last by Sand_Hawk 22 years, 6 months ago
I''ve heard from several ppl that the code in LaMothe''s for loading bitmaps is wrong. I have found a function wich does the same but what is exactly wrong with the code? Sand Hawk ---------------- -Earth is 98% full. Please delete anybody you can.
----------------(Inspired by Pouya)
i can''t tell you exactly what is wrong, but i can tell you that it produces horribly garbled data. Just look at his example programs. If you run them, 75% of the time, the bitmaps are mangled. Also, I once spent 30 minutes adapting them to a demo program i was writing(needed to load a bitmap quickly), only to find that it outputs garbage to the screen. In short, don''t use them. Win32 API functions and GDI are a lot better(and easier) to use IMHO.

------------------------------
BASIC programmers don''t die, they just GOSUB and don''t return.
------------------------------BASIC programmers don't die, they just GOSUB and don't return.
Advertisement
IIRC there isn''t a lot wrong with his bitmap loading methods, but loading 16 bit bitmaps doesn''t work very well and his colour conversion for 565 is a little broken.
Try using his bitmap loading for 24bit bitmaps to a 32bit surface, those work okay. Yes, GDI might work well, but theres no subsitute for getting a bitmap loader working like that, so you can understand whats happening.

Ballistic Programs
Lamothe's code does have bugs. I am working on chapter 7,
Advanced DirectDraw and Bitmapped Graphics.

In some of his examples, he wrote the bitmap directly to the primary surface, which from reading opinions here, you should never do. So I modified it to write to a back buffer and
flip the page to the primary surface.

I found to good threads dealing with these issues:
thread is a tutorial on loading bitmaps:
http://www.gamedev.net/community/forums/topic.asp?topic_id=84026

thread which discusses the garbled bitmaps on Lamothes code:
http://www.gamedev.net/community/forums/topic.asp?topic_id=78405

If anyone is interested, here is a working version of Lamothe's demo on chapter 7.13, with the cycle animation with the robot aliens:


      //DEFINES////////////////////////////////////#define WIN32_LEAN_AND_MEAN //no MFC, just GDI//INCLUDES////////////////////////////////////#include <windows.h>#include <windowsx.h>#include <mmsystem.h>#include <stdio.h>#include <stdlib.h>#include <io.h> //lseek#include <math.h>#include "ddraw.h" //directdraw header//typestypedef unsigned char  UCHAR;typedef unsigned short USHORT;//MACROS#define KEYDOWN(vk_code) ((GetAsyncKeyState(vk_code)&0x8000) ? 1: 0)#define KEYUP(vk_code) ((GetAsyncKeyState(vk_code) & 0x8000) ? 0: 1)#define DDRAW_INIT_STRUCT(ddstruct) { memset(&ddstruct, 0, sizeof(ddstruct)); ddstruct.dwSize=sizeof(ddstruct);}#define _RGB16BIT555(r,g,b) ((b%32) + ((g%32) << 5) + ((r%32) << 10))#define _RGB16BIT565(r,g,b) ((b%32) + ((g%64) << 5) + ((r%32) << 11))#define _RGB32BIT(a,r,g,b)  (b + (g << 8) + (r << 16) + (a << 24))//GLOBAL DEFINES///////////////////////////////#define WINDOW_CLASS_NAME "WINCLASS"//#define WINDOW_WIDTH 400//#define WINDOW_HEIGHT  300#define SCREEN_WIDTH 640#define SCREEN_HEIGHT 480#define SCREEN_BPP 8#define BITMAP_ID 0x4D42 //universal id for bmp#define MAX_COLORS_PALETTE 256//FUNCTION PROTOTYPES////////////////////////////int Game_Main(void *, int);int Game_Shutdown(void *, int);int Game_Init(void *, int);//GLOBAL VARIABLES//////////////////////////////HINSTANCE	hinstance_app = NULL;HWND		main_window_handle = NULL;LPDIRECTDRAW lpdd	= NULL;LPDIRECTDRAW4 lpdd4	= NULL; //directdraw4 objectLPDIRECTDRAWSURFACE4 lpddsprimary = NULL; //surface pointerLPDIRECTDRAWSURFACE4 lpddsback = NULL;LPDIRECTDRAWSURFACE4 lpddsbackground = NULL; //this will hold the background imageDDSURFACEDESC2  ddsd; //surface descriptionLPDIRECTDRAWPALETTE lpddpal = NULL; //palette interfacePALETTEENTRY palette[256]; //palette storageDDPIXELFORMAT ddpixel; //used to hold info on pixelsbool window_closed = 0;LPDIRECTDRAWCLIPPER lpddclipper = NULL;//UCHAR *double_buffer  = new UCHAR[640*480];//DDSCAPS2              ddscaps;               // a direct draw surface capabilities structint gwidth = -1;int gheight = -1;RECT rect_list[3] = {   {10,10,50,50},                        {100,100,200,200},                        {300,300,500,450}};typedef struct BITMAP_FILE_TAG{    BITMAPFILEHEADER bitmapfileheader; //this contains the bitmapfile header    BITMAPINFOHEADER bitmapinfoheader; //this is all the info including the palette    PALETTEENTRY     palette[256];    //we will store the palette here    UCHAR            *buffer;         //this is a pointer to the data} BITMAP_FILE, *BITMAP_FILE_PTR;BITMAP_FILE bitmap;//this will hold the alientypedef struct ALIEN_OBJ_TYP{    LPDIRECTDRAWSURFACE4 frames[3]; //3 frames of animation for complete walk cycle    int x,y; //position of alien    int velocity; //x-velocity    int current_frame; //current frame of animation    int counter;    //used to time animation} ALIEN_OBJ, *ALIEN_OBJ_PTR;ALIEN_OBJ   aliens[3];      //3 aliens, one on each level//CALLBACK FUNCTION (handles events)//////////////LRESULT CALLBACK WindowProc(HWND hwnd,							UINT msg,							WPARAM wparam,							LPARAM lparam){    //PAINTSTRUCT ps;    //HDC hdc;	switch(msg)	{	case WM_CREATE:		{			return(0);		}break;        case WM_DESTROY:		{			PostQuitMessage(0);			return(0);		}break;	default:break;	}	return (DefWindowProc(hwnd, msg, wparam, lparam));}//main() function (entrypoint) for windows//WINMAIN ///////////////////////////////////////////int WINAPI WinMain(HINSTANCE hinstance,				   HINSTANCE hPrevInstance,				   LPSTR lpCmdLine,				   int nShowCmd){	WNDCLASSEX	winclass;	//holds the structure for the class we create	HWND		hwnd;		//window handle	MSG			msg;		//message to be sent to queue//	HDC			hdc;		//graphics context	//fill the winclass structure with data	winclass.cbSize			=	sizeof(WNDCLASSEX);	winclass.style			=	CS_DBLCLKS	|	CS_OWNDC |								CS_HREDRAW	|	CS_VREDRAW;	winclass.lpfnWndProc	=	WindowProc;	winclass.cbClsExtra		=	0;	winclass.cbWndExtra		=	0;	winclass.hInstance		=	hinstance;	winclass.hIcon			=	LoadIcon(NULL, IDI_APPLICATION);	winclass.hCursor		=	LoadCursor(NULL,IDC_ARROW);	winclass.hbrBackground	=	(HBRUSH)GetStockObject(BLACK_BRUSH);	//winclass.hbrBackground	=	NULL; //loading BMP problem should be fixed    winclass.lpszMenuName	=	NULL;	winclass.lpszClassName	=	WINDOW_CLASS_NAME;	winclass.hIconSm		=	LoadIcon(NULL, IDI_APPLICATION);	//global copy of application instance	hinstance_app = hinstance;	//register the window	if(!RegisterClassEx(&winclass))		return(0);	//create the window	if(!(hwnd = CreateWindowEx( NULL,								WINDOW_CLASS_NAME,								"DirectDraw Demo, version 1.0",								WS_POPUP | WS_VISIBLE,								0,0,								SCREEN_WIDTH, SCREEN_HEIGHT,								NULL, //handle to parent								NULL, //handle to menu								hinstance,								NULL)))	return(0);	main_window_handle = hwnd;	//INITIALIZE THE GAME HERE///////////////////////////////////	Game_Init(NULL,0);    	//MAIN EVENT LOOP///////////////////////////////////////////	while(TRUE)	{		if(PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))		{			if(msg.message == WM_QUIT)				break;			TranslateMessage(&msg);			DispatchMessage(&msg);					}		//MAIN GAME PROCESSING GOES HERE////////////////////////		Game_Main(NULL,0);	}	//SHUTDOWN GAME HERE///////////////////////////////////////	Game_Shutdown(NULL,0);	return(msg.wParam);}int Flip_Bitmap(UCHAR *image, int bytes_per_line, int height){    //this function is used to flip bottom-up .BMP images    UCHAR *buffer; //used to perform the image processing    int index;     //looping index    //allocate the temporary buffer    if(!(buffer = (UCHAR *)malloc(bytes_per_line*height)))    {        //error        return(0);    }    //copy image to work area    memcpy(buffer, image, bytes_per_line*height);    //flip vertically    for(index = 0; index < height; index++)    {        memcpy(ℑ[( (height-1) - index)*bytes_per_line],            &buffer[index*bytes_per_line], bytes_per_line);    }    //release the memory    free(buffer);    return(1);}LPDIRECTDRAWCLIPPER DDraw_Attach_Clipper(LPDIRECTDRAWSURFACE4 lpdds,                                         int num_rects,                                         LPRECT clip_list){    //this function creates a clipper from the sent clip list and attaches     //it to the sent surface    int index;    LPDIRECTDRAWCLIPPER lpddclipper; //pointer to the newly created dd clipper    LPRGNDATA region_data;          // pointer to the region data that contains                                    //the header and clip list    //first create the direct draw clipper    if(FAILED(lpdd4->CreateClipper(0,&lpddclipper, NULL)))    {        //error        return(NULL);    }    //now create the clip list from the sent data    //first allocate memory for region data    region_data = (LPRGNDATA) malloc (sizeof(RGNDATAHEADER)+num_rects*sizeof(RECT));    //now copy the rects into region data    memcpy(region_data->Buffer, clip_list, sizeof(RECT)*num_rects);    //set up fields of header    region_data->rdh.dwSize         =   sizeof(RGNDATAHEADER);    region_data->rdh.iType          =   RDH_RECTANGLES;    region_data->rdh.nCount         =   num_rects;    region_data->rdh.nRgnSize       =   num_rects*sizeof(RECT);    region_data->rdh.rcBound.left   =   64000;    region_data->rdh.rcBound.top    =   64000;    region_data->rdh.rcBound.right  =   -64000;    region_data->rdh.rcBound.bottom =   -64000;    //find bounds of all clipping regions    for(index=0; index<num_rects;index++)    {        //test if the next rectangle unioned with        //the current bound is larger        if(clip_list[index].left < region_data->rdh.rcBound.left)            region_data->rdh.rcBound.left = clip_list[index].left;        if(clip_list[index].right > region_data->rdh.rcBound.right)            region_data->rdh.rcBound.right = clip_list[index].right;        if(clip_list[index].top < region_data->rdh.rcBound.top)            region_data->rdh.rcBound.top = clip_list[index].top;        if(clip_list[index].bottom > region_data->rdh.rcBound.bottom)            region_data->rdh.rcBound.bottom = clip_list[index].bottom;    }    //now we have compute the bounding rectangle region and set up the data     //now let's set the clipping list    if(FAILED(lpddclipper->SetClipList(region_data, 0)))    {        //release memory and return error        free(region_data);        return(NULL);    }    //now attach the clipper to the surface    if(FAILED(lpdds->SetClipper(lpddclipper)))    {        //release memory and return error        free(region_data);        return(NULL);    }    //all is well, so release memory and    //send back the pointer to the new clipper    free(region_data);    return(lpddclipper);}//end of DDraw_Attach_Clipperint DDraw_Fill_Surface(LPDIRECTDRAWSURFACE4 lpdds, int color){    DDBLTFX ddbltfx; //this contains the ddbltfx structure    //clear out the structure and set the size field    DDRAW_INIT_STRUCT(ddbltfx);    //set the dwfillcolor field to the desired color    ddbltfx.dwFillColor = color;    lpdds->Blt(NULL,               NULL,               NULL,               DDBLT_COLORFILL | DDBLT_WAIT,               &ddbltfx);    return(1);} //end of DDraw_Fill_SurfaceLPDIRECTDRAWSURFACE4 DDraw_Create_Surface(int width, int height,                                           int mem_flags, int color_key = 0){    DDSURFACEDESC2 ddsd;    //surface    LPDIRECTDRAWSURFACE4 lpdds; //temporary surface    //initialize structure    DDRAW_INIT_STRUCT(ddsd);    //set to access caps, width, and height    ddsd.dwFlags = DDSD_CAPS | DDSD_WIDTH | DDSD_HEIGHT;    //set dimensions of the new bitmap surface    ddsd.dwWidth = width;    ddsd.dwHeight = height;    //set surface to offscreen plane    ddsd.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN | mem_flags;    //create the surface    if(FAILED(lpdd4->CreateSurface(&ddsd, &lpdds, NULL)))    {        //error        return(NULL);    }    if(color_key >= 0)    {    //set color key     DDCOLORKEY color_key; //used to set color key    color_key.dwColorSpaceLowValue = 0;    color_key.dwColorSpaceHighValue = 0;    //now set the color key for source blitting    lpdds->SetColorKey(DDCKEY_SRCBLT, &color_key);    }    //return surface    return(lpdds);}//end of DDraw_Create_Surfaceint Load_Bitmap_File(BITMAP_FILE_PTR bitmap, char *filename){    //this function opens a bitmap file and loads the data into bitmap    int file_handle,    //the file handle        index;          //looping index    UCHAR *temp_buffer = NULL;  //used to convert 24 bit images to 16 bit    OFSTRUCT    file_data;      //the file data information    //open the file if it exists    if( (file_handle = OpenFile(filename, &file_data, OF_READ))== -1)    {        //error        return(0);    }    //now load the bitmap file header    _lread(file_handle, &bitmap->bitmapfileheader, sizeof(BITMAPFILEHEADER));    //rest if this is a bitmap file    if(bitmap->bitmapfileheader.bfType != BITMAP_ID)    {        //close the file        _lclose(file_handle);        //return error        return(0);    }    //now we know this is a bitmap, so read in all the sections    //first the bitmap infoheader    //now load the bitmap file header    _lread(file_handle, &bitmap->bitmapinfoheader, sizeof(BITMAPINFOHEADER));    //now load the color palette if there is one    if(bitmap->bitmapinfoheader.biBitCount == 8)    {        _lread(file_handle, &bitmap->palette,            MAX_COLORS_PALETTE*sizeof(PALETTEENTRY));        //now set all the flags in the palette correctly        //and fix the reversed        //BGR RGBQUAD data format        for(index=0; index < MAX_COLORS_PALETTE; index++)        {            //reverse the red and green fields            int temp_color      = bitmap->palette[index].peRed;            bitmap->palette[index].peRed = bitmap->palette[index].peBlue;            bitmap->palette[index].peBlue = temp_color;            //always set the flags word to this            bitmap->palette[index].peFlags = PC_NOCOLLAPSE;        }//end index    }//end if    //finally the image data itself    _lseek(file_handle, -(int)(bitmap->bitmapinfoheader.biSizeImage), SEEK_END);    //now read in the image    if(bitmap->bitmapinfoheader.biBitCount==8 ||       bitmap->bitmapinfoheader.biBitCount==16 ||       bitmap->bitmapinfoheader.biBitCount==24)    {        //delete the last image if there was one        if(bitmap->buffer)        {            free(bitmap->buffer);        }        //allocate the memory for the image        if(!(bitmap->buffer = (UCHAR *)malloc(bitmap->bitmapinfoheader.biSizeImage)))        {            //close the file            _lclose(file_handle);            //return error            return(0);        }        //now read it in        _lread(file_handle, bitmap->buffer, bitmap->bitmapinfoheader.biSizeImage);    }//end if    else    {        //serious problem        return(0);    }    //close the file    _lclose(file_handle);    //flip the bitmap    Flip_Bitmap(bitmap->buffer,                bitmap->bitmapinfoheader.biWidth*                (bitmap->bitmapinfoheader.biBitCount/8),                bitmap->bitmapinfoheader.biHeight);    //return success    return(1);}//end of Load_Bitmap_Fileint Unload_Bitmap_File(BITMAP_FILE_PTR bitmap){    //this function releases all memory associated with the bitmap    if(bitmap->buffer)    {        //release memory        free(bitmap->buffer);        //reset pointer        bitmap->buffer = NULL;    }    //return success    return(1);}int Scan_Image_Bitmap(BITMAP_FILE_PTR bitmap,                      LPDIRECTDRAWSURFACE4 lpdds, //surface to hold data                      int cx, int cy)             //cell to scan image from{    //this function extracts a bitmap out of a bitmap file    UCHAR *source_ptr, //working pointers        *dest_ptr;    DDSURFACEDESC2 ddsd; //direct draw surface description    //get the address to destination surface memory        //set size of the structure    ddsd.dwSize = sizeof(ddsd);    //lock the display surface    lpdds->Lock(NULL,        &ddsd,        DDLOCK_WAIT | DDLOCK_SURFACEMEMORYPTR,        NULL);    //compute position to start scanning bits from    cx = cx*(ddsd.dwWidth + 1)  + 1;    cy = cy*(ddsd.dwHeight + 1) + 1;    gwidth = ddsd.dwWidth;    gheight = ddsd.dwHeight;    //extract bitmap data    source_ptr = bitmap->buffer + cy*bitmap->bitmapinfoheader.biWidth+cx;    //assign a pointer to the memory surface for manipulation    dest_ptr = (UCHAR *)ddsd.lpSurface;    for(unsigned int index_y=0; index_y < ddsd.dwHeight; index_y++)    {        //copy next line of data to destination        memcpy(dest_ptr, source_ptr, ddsd.lPitch);        //advance pointers        dest_ptr += (ddsd.lPitch);        source_ptr += bitmap->bitmapinfoheader.biWidth;    }    lpdds->Unlock(NULL);    return(1);} //end of Scan_Image_Bitmapint DDraw_Draw_Surface(LPDIRECTDRAWSURFACE4 source,                       int x, int y,                       int width, int height,                       LPDIRECTDRAWSURFACE4 dest,                       int transparent = 1){    RECT dest_rect,        source_rect;    //file in destination rect    dest_rect.left = x;    dest_rect.top = y;    dest_rect.right = x + width - 1;    dest_rect.bottom = y + height -1;    //fill in the source rect    source_rect.left = 0;    source_rect.top = 0;    source_rect.right = width -1 ;    source_rect.bottom = height -1;    //test transperency    if(transparent)    {        //enable color key blit        //blt to destination surface        if(FAILED(dest->Blt(&dest_rect, source,                            &source_rect, (DDBLT_WAIT | DDBLT_KEYSRC),                            NULL)))        {            //error            return(0);        }    }    else    {            //perform the blit without color key            //blt to destination surface            if(FAILED(dest->Blt(&dest_rect, source,                &source_rect,(DDBLT_WAIT),                NULL)))            {                //error                return(0);            }     }    return(0);} //end of DDraw_Draw_Surfaceint Game_Main(void *parms = NULL, int num_parms=0){    //this is the main loop of the game, do all the processing    //here   static int animation_seq[4] = {0,1,0,2};       int index;    if(window_closed)        return(0);    	if(KEYDOWN(VK_ESCAPE))    {		PostMessage(main_window_handle, WM_CLOSE, 0,0);        window_closed = 1;    }   DDraw_Draw_Surface(lpddsbackground,0,0,SCREEN_WIDTH, SCREEN_HEIGHT, lpddsback, 0);        //move objects around    for(index=0; index < 3; index++)    {        //move each object to the right at its given velocity        aliens[index].x++; //aliens[index].velocity        //test if off screen edge, and wrap around        if(aliens[index].x > SCREEN_WIDTH)        {            aliens[index].x = -80;        }        //animate bot        if(++aliens[index].counter >= (8 - aliens[index].velocity))        {            //reset counter            aliens[index].counter=0;            //advance to next frame            if(++aliens[index].current_frame > 3)            {                aliens[index].current_frame = 0;            }        }    }    for(index=0; index < 3; index++)    {        //draw objects        DDraw_Draw_Surface(aliens[index].frames[animation_seq[aliens[index].current_frame]],                            aliens[index].x, aliens[index].y, 72,80, lpddsback);    }    while(FAILED(lpddsprimary->Flip(NULL, DDFLIP_WAIT)))    {        //error        return(0);    }    Sleep(75);        return(0);} //end game mainint Game_Init(void *parms = NULL, int num_parms=0){	//this is called once after the initial window is created	//and before the main event loop is entered.	//Initialization goes here	//create base IDirectDraw interface	if(FAILED(DirectDrawCreate(NULL, &lpdd, NULL)))	{		//error		return FALSE;	}	//query for IDirectDraw4	if(FAILED(lpdd->QueryInterface(IID_IDirectDraw4,									(LPVOID *)&lpdd4)))	{		//error		return FALSE;	}	lpdd->Release();	lpdd = NULL;	//set cooperation to normal since this will be a windowed app	//lpdd4->SetCooperativeLevel(main_window_handle, DDSCL_NORMAL);        if(FAILED(lpdd4->SetCooperativeLevel(main_window_handle,                                         DDSCL_FULLSCREEN | DDSCL_ALLOWMODEX |                                         DDSCL_EXCLUSIVE | DDSCL_ALLOWREBOOT)))    {        //error        return FALSE;    }    //set display mode to 640x480x8    if(FAILED(lpdd4->SetDisplayMode(SCREEN_WIDTH,                                    SCREEN_HEIGHT,SCREEN_BPP,0,0)))    {        //error        return FALSE;    }        //clear ddsd and set size    DDRAW_INIT_STRUCT(ddsd);     //enable valid fields    //ddsd.dwFlags = DDSD_CAPS; //double buffering    ddsd.dwFlags = DDSD_CAPS | DDSD_BACKBUFFERCOUNT;    ddsd.dwBackBufferCount = 1; //1 back buffer    //request primary surface    //ddsd.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE; //double buffering    ddsd.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE |                             DDSCAPS_COMPLEX | DDSCAPS_FLIP;    //create primary surface    if(FAILED(lpdd4->CreateSurface(&ddsd, &lpddsprimary, NULL)))    {        //error        return FALSE;    }    ddsd.ddsCaps.dwCaps = DDSCAPS_BACKBUFFER;    //get the attached back buffer surface    if(FAILED(lpddsprimary->GetAttachedSurface(&ddsd.ddsCaps, &lpddsback)))    {        //error        return(0);    }        //build the pallete data array    for(int color=1; color < 255; color++)    {        palette[color].peRed = rand()%256;        palette[color].peGreen = rand()%256;        palette[color].peBlue   = rand()%256;        palette[color].peFlags = PC_NOCOLLAPSE;    }        palette[0].peRed = 0;    palette[0].peGreen = 0;    palette[0].peBlue = 0;    palette[0].peFlags = PC_NOCOLLAPSE;    palette[255].peRed = 255;    palette[255].peGreen = 255;    palette[255].peBlue = 255;    palette[255].peFlags = PC_NOCOLLAPSE;        if(FAILED(lpdd4->CreatePalette(DDPCAPS_8BIT | DDPCAPS_ALLOW256 |                                    DDPCAPS_INITIALIZE, palette,                                     &lpddpal, NULL)))    {        //error        return FALSE;    }    if(FAILED(lpddsprimary->SetPalette(lpddpal)))    {        //error        return FALSE;    }        //set clipper up on back buffer since that's where we will clip    RECT screen_rect = {0,0,SCREEN_WIDTH-1, SCREEN_HEIGHT-1};    lpddclipper = DDraw_Attach_Clipper(lpddsback, 1, &screen_rect);    //load an 8 bit bitmap    if(!(Load_Bitmap_File(&bitmap, "alley8.bmp")))    {        //error        return(0);    }        //load its palette into directdraw    if(FAILED(lpddpal->SetEntries(0,0,MAX_COLORS_PALETTE, bitmap.palette)))    {        //error        return(0);    }          //clean the surfaces    DDraw_Fill_Surface(lpddsprimary, 0);    DDraw_Fill_Surface(lpddsback, 0);    //create buffer to hold the background    lpddsbackground = DDraw_Create_Surface(SCREEN_WIDTH, SCREEN_HEIGHT, 0, -1);    //copy the background bitmap image to the background surface    //lock the surface    if(FAILED(lpddsbackground->Lock(NULL, &ddsd, DDLOCK_SURFACEMEMORYPTR | DDLOCK_WAIT, NULL)))    {        //error        return(0);    }        //get video buffer to primary surface    UCHAR *image_buffer = (UCHAR *)ddsd.lpSurface;    //test if memory is linear    if(ddsd.lPitch == SCREEN_WIDTH)    {        //copy memory from double buffer to primary buffer        memcpy((void *)image_buffer, (void *)bitmap.buffer, SCREEN_WIDTH*SCREEN_HEIGHT);    }    else    {        //must be non-linear        //make copy of source and destination addresses        UCHAR *dest_ptr = image_buffer;        UCHAR *src_ptr = bitmap.buffer;        //memory is non-linear, copy line by line        for(int y =0; y < SCREEN_HEIGHT; y++)        {            //copy line            memcpy((void *)dest_ptr, (void *)src_ptr, SCREEN_WIDTH);            //advance pointers to next line            dest_ptr+= ddsd.lPitch;            src_ptr += SCREEN_WIDTH;        }          }    if(FAILED(lpddsbackground->Unlock(NULL)))    {        //error        return(0);    }    Unload_Bitmap_File(&bitmap);    //initialize all the aliens    srand(GetTickCount());    //alien on level 1 of complex        aliens[0].x = rand()%SCREEN_WIDTH;    aliens[0].y = 116 - 72;    aliens[0].velocity = 2 + rand()%4;    aliens[0].current_frame = 0;    aliens[0].counter = 0;    //alien on level 2 of complex    aliens[1].x = rand()%SCREEN_WIDTH;    aliens[1].y =  246 - 72;    aliens[1].velocity = 2 + rand()%4;    aliens[1].current_frame = 0;    aliens[1].counter = 0;    //alien on level 3 of complex    aliens[2].x    =    rand()%SCREEN_WIDTH;    aliens[2].y    =    382 - 72;    aliens[2].velocity = 2 + rand()%4;    aliens[2].current_frame = 0;    aliens[2].counter = 0;    //now load the bitmap containing the alien    //images then scan the images out into the surfaces    //of alien[0] and copy then into the other two, be    //careful of reference counts!    //load the 8-bit image    if(!(Load_Bitmap_File(&bitmap, "dedsp0.bmp")))    {        //error        return(0);    }    //create each surface and load bits    for(int index = 0; index < 3; index++)    {        //create surface to hold image        aliens[0].frames[index] = DDraw_Create_Surface(72,80,0);        //now load bits...        Scan_Image_Bitmap(&bitmap,                          aliens[0].frames[index],                          index, 0);    }    Unload_Bitmap_File(&bitmap);    //now for the tricky part. There is no need to create more    //surfaces with the same data, so I'm going to copy the surface pointers    //member for member to each alien. However, be careful, since the reference    //counts to NOT go up, you still only need to release() each surface once!    for(index = 0; index < 3; index++)    {        aliens[1].frames[index] = aliens[2].frames[index] = aliens[0].frames[index];    }    return(0);} //end game initint Game_Shutdown(void *parms = NULL, int num_parms=0){	//this is called after the game has exited and the main event	//while loop is exited, do all cleanup and shutdown here	    //first the palette    if(lpddpal)    {        lpddpal->Release();        lpddpal = NULL;    }        if(lpddsback)    {        lpddsprimary->Release();        lpddsprimary = NULL;    }        if(lpddsprimary)    {        lpddsprimary->Release();        lpddsprimary = NULL;    }	if(lpdd4)	{		lpdd4->Release();		lpdd4 = NULL;	}	return(0);} //end game shutdown      


[edited by - phoey on June 5, 2002 10:40:01 AM]

[edited by - phoey on June 5, 2002 10:42:42 AM]
---------------------------IGDA Member-Boston Chapter"Science is everything we understand well enough to explain to a computer. Art is everything else."- David Knuth In “Computers”
I believe that the reason he draws a bitmap directly to the primary surface is to illustrate the very basics of directdraw. He doesn't go into using a back buffer until later. There is nothing wrong with writing to the primary buffer. It will just cause massive flickering that is avoided by first drawing everything to the backbuffer.

It took me forever to modify his 565 RGB macro to work with my video card. Of course, that was a year or two ago, but I, too, remember having trouble with his bitmap loader.

[edited by - doctorsixstring on June 5, 2002 10:43:44 AM]
Advertisement
quote:
I believe that the reason he draws a bitmap directly to the primary surface is to illustrate the very basics of directdraw. He doesn''t go into using a back buffer until later. There is nothing wrong with writing to the primary buffer.


The problem I ran into with drawing to the primary
surface was that you get a blank screen. It turns out
that windows sends a WM_PAINT message that clears
the primary surface. It was a pain to figure out
why the image was not showing up, and I thought
there was something wrong with his loader. But
after fishing around I changed the:
winclass.hbrBackground	=	(HBRUSH)GetStockObject(BLACK_BRUSH); 


to

winclass.hbrBackground	=	NULL; //loading BMP problem should be fixed 


so that the primary surface would not be overwritten by
the callback WM_PAINT.

IMHO, he already explained backbuffers by this point, and there should have been consistency by showing the program using the back buffer, instead of the subtle problem by loading it onto the primary surface.

---------------------------IGDA Member-Boston Chapter"Science is everything we understand well enough to explain to a computer. Art is everything else."- David Knuth In “Computers”
I remember having a lot of trouble with his code, it won''t work on a bitmap which width or height isn''t a multiple of 4. I spent a looooong time figuring that out and fixing it.

--
So Long To Red Dye #2
-- So Long To Red Dye #2
phoey: Thanks for posting that. I''ve been going through Lamothe''s book also and being a person with no prior win32 or Directx programming experience, it was insanely frustrating when the samples didn''t work correctly. Almost made me want to put the book away and not pick it back up. Almost...

In the end I just decided that I''d go through the rest of the book and maybe by the end I''d know enough to try to figure out what was wrong with his example. But now I don''t have to. I just started the AI chapter the other night and I think I''m hooked. I can''t wait to make some enemies! Thanks again.
oh hai
quote:
Zul

phoey: Thanks for posting that. I've been going through Lamothe's book also and being a person with no prior win32 or Directx programming experience, it was insanely frustrating when the samples didn't work correctly. Almost made me want to put the book away and not pick it back up. Almost...


Glad I could help!

At one point I thought the bugs in the code were intentional or that the editor fooled around with the code because the errors were so blatently obvious. But I really enjoy Lamothe's TOTWGPG and it is a great way to learn DirectX and basic Windows programming. It will feel like a real accomplishment when I get through this book, and after which I will feel more comfortable developing a game in Directx and Windows.


Edit: Added Sig

---------------------------
IGDA Member-Boston Chapter

"Science is everything we understand well enough to explain to a computer. Art is everything else."
- David Knuth In “Computers”






[edited by - phoey on June 5, 2002 12:40:45 PM]
---------------------------IGDA Member-Boston Chapter"Science is everything we understand well enough to explain to a computer. Art is everything else."- David Knuth In “Computers”

This topic is closed to new replies.

Advertisement