What's wrong with LaMothe's bitmap loader?
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.
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.
------------------------------BASIC programmers don't die, they just GOSUB and don't return.
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
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:
[edited by - phoey on June 5, 2002 10:40:01 AM]
[edited by - phoey on June 5, 2002 10:42:42 AM]
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]
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]
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
-- 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.
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
Popular Topics
Advertisement
Recommended Tutorials
Advertisement