Archived

This topic is now archived and is closed to further replies.

What's wrong with LaMothe's bitmap loader?

This topic is 5673 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

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.

Share this post


Link to post
Share on other sites
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.

Share this post


Link to post
Share on other sites
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.

Share this post


Link to post
Share on other sites
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

Share this post


Link to post
Share on other sites
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


//types

typedef 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 object

LPDIRECTDRAWSURFACE4 lpddsprimary = NULL; //surface pointer

LPDIRECTDRAWSURFACE4 lpddsback = NULL;
LPDIRECTDRAWSURFACE4 lpddsbackground = NULL; //this will hold the background image

DDSURFACEDESC2 ddsd; //surface description

LPDIRECTDRAWPALETTE lpddpal = NULL; //palette interface

PALETTEENTRY palette[256]; //palette storage

DDPIXELFORMAT ddpixel; //used to hold info on pixels

bool window_closed = 0;
LPDIRECTDRAWCLIPPER lpddclipper = NULL;
//UCHAR *double_buffer = new UCHAR[640*480];

//DDSCAPS2 ddscaps; // a direct draw surface capabilities struct

int 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 alien

typedef 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(&image[( (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_Clipper


int 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_Surface


LPDIRECTDRAWSURFACE4 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_Surface



int 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_File



int 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_Bitmap


int 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_Surface



int 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 main


int 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 init



int 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]

Share this post


Link to post
Share on other sites
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]

Share this post


Link to post
Share on other sites
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.

Share this post


Link to post
Share on other sites
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

Share this post


Link to post
Share on other sites
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.

Share this post


Link to post
Share on other sites
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]

Share this post


Link to post
Share on other sites
quote:

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.



I feel the same way. I've learned a ton already just by going through his code. I'm enthralled by demo 12.3. Consequently though, something has become fubar with my sound card as it won't play any sounds now. It's fine in the device manager and I tried disabling/enabling it to no avail. I hope I didn't damage it too badly. But yeah, I'm actually really excited to write my own version of Tetris. Some people seem to want to jump right to Quake III, but to me Tetris and then maybe Galaxian would be awesome.

[edited by - Zul on June 5, 2002 12:14:43 PM]

Share this post


Link to post
Share on other sites


Guys,..screw Lamothe,..havent you heard of DDutil ?
Its faster and easier.And theres a tut for it here on gamedev


[url]http://www.gamedev.net/reference/articles/article1078.asp[/url]

Lamothe cant help you with everything,..sometimes you have to find other ways to do stuff.Bye.

Share this post


Link to post
Share on other sites
quote:
Original post by Access


Guys,..screw Lamothe,..havent you heard of DDutil ?
Its faster and easier.And theres a tut for it here on gamedev


[url]http://www.gamedev.net/reference/articles/article1078.asp[/url]

Lamothe cant help you with everything,..sometimes you have to find other ways to do stuff.Bye.


That''s great, but that alone isn''t going to help me get some ideas on how to program an entire game. Lamothe''s book has though. The fact that a couple of his examples didn''t work frustrated me a great deal, but the concepts I''ve learned from his book have helped me considerably.

"I''ve never seen that. I''ve never seen anybody drive their garbage down to the side of the street and bang the hell out of it with a stick. I''ve never seen that."

Share this post


Link to post
Share on other sites