Those days , I am reading the book 《Tricks of the Windows Game Programming》 . But I always get in trouble .
Today , I code the sample which I should use the Blt function . But I do not know , why the Blt function always goes wrong .
The following is my code which is wrong at the runtime ,
#define WIN32_LEAN_AND_MEAN // just say no to MFC
#define INITGUID // make sure directX guids are included
#include <windows.h> // include important windows stuff
#include <windowsx.h>
#include <mmsystem.h>
#include <iostream> // include important C/C++ stuff
#include <conio.h>
#include <stdlib.h>
#include <malloc.h>
#include <memory.h>
#include <string.h>
#include <stdarg.h>
#include <stdio.h>
#include <math.h>
#include <io.h>
#include <fcntl.h>
#include <ddraw.h> // include directdraw
#pragma comment(lib,"ddraw.lib")
#define WINDOW_CLASS_NAME L"WINCLASS1"
#define SCREEN_WIDTH 1366 // size of screen
#define SCREEN_HEIGHT 768
#define SCREEN_BPP 32 // bits per pixel
typedef unsigned short USHORT;
typedef unsigned short WORD;
typedef unsigned char UCHAR;
typedef unsigned char BYTE;
#define KEYDOWN(vk_code) ((GetAsyncKeyState(vk_code) & 0x8000) ? 1 : 0)
#define KEYUP(vk_code) ((GetAsyncKeyState(vk_code) & 0x8000) ? 0 : 1)
#define DD_INIT_STRUCT(ddstruct) { memset(&ddstruct,0,sizeof(ddstruct)); ddstruct.dwSize=sizeof(ddstruct); }
#define _RGB16BIT565(r,g,b) ((b & 31) + ((g & 63) << 5) + ((r & 31) << 11))
#define _RGB32BIT(a,r,g,b) ((b) + ((g) << 8) + ((r) << 16) + ((a) << 24))
HWND main_window_handle = NULL; HINSTANCE hinstance_app = NULL;
LPDIRECTDRAW7 lpdd = NULL; LPDIRECTDRAWSURFACE7 lpddsprimary = NULL; LPDIRECTDRAWSURFACE7 lpddsback = NULL; LPDIRECTDRAWPALETTE lpddpal = NULL; LPDIRECTDRAWCLIPPER lpddclipper = NULL; PALETTEENTRY palette[256]; PALETTEENTRY save_palette[256]; DDSURFACEDESC2 ddsd; DDBLTFX ddbltfx; DDSCAPS2 ddscaps; HRESULT ddrval; DWORD start_clock_count = 0; LPDIRECTDRAWSURFACE7 lpddsOffScreen[8] ; int windows_closed = 0 ;
int index = 0 ; RECT window_rect ;
int min_clip_x = 0, max_clip_x = SCREEN_WIDTH-1,
min_clip_y = 0,
max_clip_y = SCREEN_HEIGHT-1;
int screen_width = SCREEN_WIDTH, screen_height = SCREEN_HEIGHT, screen_bpp = SCREEN_BPP;
char buffer[80];
typedef struct BITMAP_FILE_TAG
{
BITMAPFILEHEADER bitmapfileheader ;
BITMAPINFOHEADER bitmapinfoheader ;
PALETTEENTRY palette[256] ;
UCHAR * buffer ;
} BITMAP_FILE ,*BITMAP_FILE_PTR ;
BITMAP_FILE bitmap[8] ;
int Load_Bitmap_File(BITMAP_FILE_PTR pBitmap,WCHAR * pFileName);
int Flip_Bitmap_Data(UCHAR* pBitmap,int width , int height );
int UnLoad_Bitmap_File(BITMAP_FILE_PTR pBitmap);
void Blt_Clipper(int x , int y,
int width , int height ,
UINT* bitmap_data,
UINT* video_data,
int mempitch);
void Transform24To32(UCHAR* pcBitmap ,int dwSizeImage ,UINT * pnBitmap );
LPDIRECTDRAWSURFACE7 DDraw_Create_Surface(int width , int height , int mem_flags) ;
LRESULT CALLBACK WindowProc(HWND hwnd,
UINT msg,
WPARAM wparam,
LPARAM lparam)
{
PAINTSTRUCT ps; HDC hdc; char buffer[80];
switch(msg)
{
case WM_CREATE:
{
return(0);
} break;
case WM_PAINT:
{
hdc = BeginPaint(hwnd,&ps);
EndPaint(hwnd,&ps);
return(0);
} break;
case WM_DESTROY:
{
PostQuitMessage(0);
return(0);
} break;
default:break;
}
return (DefWindowProc(hwnd, msg, wparam, lparam));
}
int Game_Main(void *parms = NULL, int num_parms = 0)
{
if(windows_closed)
return 0 ;
if (KEYDOWN(VK_ESCAPE))
{
PostMessage(main_window_handle,WM_CLOSE,0,0);
windows_closed = 1 ;
}
GetWindowRect(main_window_handle,&window_rect);
RECT dest_rect ;
RECT src_rect ;
memset(&dest_rect,0,sizeof(RECT));
memset(&src_rect,0,sizeof(RECT));
dest_rect.left = 100 + window_rect.left;
dest_rect.top = 100 + window_rect.top;
dest_rect.right = dest_rect.left + bitmap[index].bitmapinfoheader.biWidth - 1 ;
dest_rect.bottom = dest_rect.top + bitmap[index].bitmapinfoheader.biHeight - 1 ;
src_rect.left = 0 ;
src_rect.top = 0 ;
src_rect.right = bitmap[index].bitmapinfoheader.biWidth - 1 ;
src_rect.bottom = bitmap[index].bitmapinfoheader.biHeight - 1 ;
if(FAILED(lpddsprimary->Blt(&dest_rect,lpddsOffScreen[index],&src_rect, DDBLT_KEYSRC|DDBLT_WAIT,NULL)))
{
OutputDebugString(L"lpddsprimary->Blt error\n");
return 0 ;
}
index = (index+1)%8 ;
Sleep(300);
return(1);
}
int Game_Init(void *parms = NULL, int num_parms = 0)
{
if (FAILED(DirectDrawCreateEx(NULL, (void **)&lpdd, IID_IDirectDraw7, NULL)))
return(0);
if(FAILED(lpdd->SetCooperativeLevel(main_window_handle,DDSCL_NORMAL)))
{
MessageBox(NULL,L"SetCooperativeLevel error",L"error",MB_OK);
return 0 ;
}
memset(&ddsd,0,sizeof(ddsd));
ddsd.dwSize = sizeof(ddsd);
ddsd.dwFlags = DDSD_CAPS ;
ddsd.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE ;
if(FAILED(lpdd->CreateSurface(&ddsd,&lpddsprimary,NULL)))
{
MessageBox(NULL,L"CreateSurface error",L"error",MB_OK);
return 0 ;
}
for(int i = 0 ; i < 6 ; i ++)
{
lpddsOffScreen[i]=DDraw_Create_Surface(23,23,DDSCAPS_VIDEOMEMORY);
}
for(int i = 1 ; i <= 6 ; i ++)
{
WCHAR * wcFileName = new WCHAR[256] ;
swprintf_s(wcFileName,256,L"grossini_dance_0%d.bmp",i);
Load_Bitmap_File(&bitmap[i-1],wcFileName);
delete wcFileName ;
}
for(int i = 0 ; i < 6 ; i ++)
{
DD_INIT_STRUCT(ddsd);
if(FAILED(lpddsOffScreen[i]->Lock(NULL,&ddsd,DDLOCK_WAIT|DDLOCK_SURFACEMEMORYPTR,NULL)))
{
OutputDebugString(L"Lock error");
return 0 ;
}
int mempitch = ddsd.lPitch>>2 ;
UINT *video_buffer = (UINT*)ddsd.lpSurface ;
UINT * bitmap_buffer = new UINT[bitmap[i].bitmapinfoheader.biSizeImage/3];
Transform24To32(bitmap[i].buffer,bitmap[i].bitmapinfoheader.biSizeImage,bitmap_buffer);
Blt_Clipper(0,0,bitmap[i].bitmapinfoheader.biWidth,bitmap[i].bitmapinfoheader.biHeight,
bitmap_buffer,video_buffer,mempitch);
if(FAILED(lpddsOffScreen[i]->Unlock(NULL)))
{
OutputDebugString(L"Unock error");
return 0 ;
}
}
return(1);
}
int Game_Shutdown(void *parms = NULL, int num_parms = 0)
{
for(int i = 0 ; i < 8 ; i ++)
{
UnLoad_Bitmap_File(&bitmap[i]);
}
for(int i = 0 ; i < 8 ; i ++)
{
if(lpddsOffScreen[i] != NULL)
lpddsOffScreen[i]->Release();
lpddsOffScreen[i] = NULL ;
}
if(lpddsprimary)
{
lpddsprimary->Release();
lpddsprimary = NULL ;
}
if (lpdd)
{
lpdd->Release();
lpdd = NULL;
}
return(1);
}
int WINAPI WinMain( HINSTANCE hinstance,
HINSTANCE hprevinstance,
LPSTR lpcmdline,
int ncmdshow)
{
WNDCLASSEX winclass; HWND hwnd; MSG msg; HDC hdc;
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.lpszMenuName = NULL;
winclass.lpszClassName = WINDOW_CLASS_NAME;
winclass.hIconSm = LoadIcon(NULL, IDI_APPLICATION);
hinstance_app = hinstance;
if (!RegisterClassEx(&winclass))
return(0);
if (!(hwnd = CreateWindowEx(NULL, WINDOW_CLASS_NAME, L"DirectDraw Initialization Demo", WS_OVERLAPPED | WS_VISIBLE,
0,0, SCREEN_WIDTH*0.8,0.8*SCREEN_HEIGHT, NULL, NULL, hinstance, NULL))) return(0);
main_window_handle = hwnd;
Game_Init();
while(TRUE)
{
if (PeekMessage(&msg,NULL,0,0,PM_REMOVE))
{
if (msg.message == WM_QUIT)
break;
TranslateMessage(&msg);
DispatchMessage(&msg);
}
Game_Main();
}
Game_Shutdown();
return(msg.wParam);
}
int Load_Bitmap_File(BITMAP_FILE_PTR pBitmap , WCHAR * pFileName)
{
memset(pBitmap,0,sizeof(pBitmap));
HANDLE hFile = CreateFile(pFileName,GENERIC_READ,FILE_SHARE_READ,
NULL,OPEN_EXISTING,FILE_ATTRIBUTE_READONLY,NULL);
if(hFile == NULL)
{
OutputDebugString(L"CreateFile error");
return 1 ;
}
SetFilePointer(hFile,0,NULL,FILE_BEGIN);
DWORD readByte = 0 ;
if(!ReadFile(hFile,(LPVOID)&pBitmap->bitmapfileheader,sizeof(BITMAPFILEHEADER),&readByte,NULL))
{
OutputDebugString(L"ReadFile for bitmapfileheader error");
CloseHandle(hFile);
return 1 ;
}
if(pBitmap->bitmapfileheader.bfType != 0x4D42)
{
OutputDebugString(L"file is not the bitmap");
CloseHandle(hFile);
return 1 ;
}
SetFilePointer(hFile,sizeof(BITMAPFILEHEADER),NULL,FILE_BEGIN);
if(!ReadFile(hFile,(LPVOID)&pBitmap->bitmapinfoheader,sizeof(BITMAPINFOHEADER),&readByte,NULL))
{
OutputDebugString(L"ReadFile for bitmapinfoheader error");
CloseHandle(hFile);
return 1 ;
}
if(pBitmap->bitmapinfoheader.biBitCount == 8)
{
SetFilePointer(hFile,sizeof(BITMAPINFOHEADER)+sizeof(BITMAPFILEHEADER),NULL,FILE_BEGIN);
if(!ReadFile(hFile,(LPVOID)&pBitmap->palette,sizeof(PALETTEENTRY)*256,&readByte,NULL))
{
OutputDebugString(L"ReadFile for palette is error");
CloseHandle(hFile);
return 1 ;
}
for(int i = 0 ; i < 256 ; i ++)
{
int tempColor = pBitmap->palette[i].peRed ;
pBitmap->palette[i].peRed = pBitmap->palette[i].peBlue ;
pBitmap->palette[i].peBlue = tempColor ;
pBitmap->palette[i].peFlags = PC_NOCOLLAPSE ;
}
}
if(pBitmap->bitmapinfoheader.biBitCount == 8 ||
pBitmap->bitmapinfoheader.biBitCount == 16 ||
pBitmap->bitmapinfoheader.biBitCount == 24 ||
pBitmap->bitmapinfoheader.biBitCount == 32)
{
int length = 0 - pBitmap->bitmapinfoheader.biSizeImage ;
SetFilePointer(hFile,length,NULL,FILE_END);
pBitmap->buffer = new UCHAR[pBitmap->bitmapinfoheader.biSizeImage];
if(pBitmap->buffer == NULL)
{
OutputDebugString(L"new memory error");
CloseHandle(hFile);
return 1 ;
}
if(!ReadFile(hFile,(LPVOID)pBitmap->buffer,pBitmap->bitmapinfoheader.biSizeImage,&readByte,NULL))
{
OutputDebugString(L"ReadFile for buffer is error");
CloseHandle(hFile);
return 1 ;
}
} else
{
OutputDebugString(L"the file is broken");
CloseHandle(hFile);
return 1 ;
}
CloseHandle(hFile);
if(pBitmap->bitmapinfoheader.biHeight > 0)
{
Flip_Bitmap_Data(pBitmap->buffer,pBitmap->bitmapinfoheader.biWidth*pBitmap->bitmapinfoheader.biBitCount/8,
pBitmap->bitmapinfoheader.biHeight);
}
return 0 ;
}
int Flip_Bitmap_Data(UCHAR * pBitmap,int bytes_per_line , int height)
{
UCHAR *buffer; int index;
if (!(buffer = (UCHAR *)malloc(bytes_per_line*height)))
return(0);
memcpy(buffer,pBitmap,bytes_per_line*height);
for (index=0; index < height; index++)
memcpy(&pBitmap[((height-1) - index)*bytes_per_line],
&buffer[index*bytes_per_line], bytes_per_line);
free(buffer);
return(1);
}
int UnLoad_Bitmap_File(BITMAP_FILE_PTR pBitmap)
{
if(pBitmap->buffer != NULL)
{
delete pBitmap->buffer ;
pBitmap->buffer = NULL ;
}
return 0 ;
}
void Blt_Clipper(int x , int y,
int width , int height ,
UINT* bitmap_data,
UINT* video_data,
int mempitch)
{
if(x+width<0 || x>SCREEN_WIDTH
||y>SCREEN_HEIGHT ||y+height<0)
return ;
int x1 = x ;
int y1 = y ;
int x2 = x + width - 1;
int y2 = y + height - 1;
if(x1<0)
x1 = 0;
if(y1<0)
y1 = 0 ;
if(x2>SCREEN_WIDTH)
x2 = SCREEN_WIDTH - 1 ; if(y2>SCREEN_HEIGHT)
y2 = SCREEN_HEIGHT - 1 ;
int xoff = x1- x ;
int yoff = y1 -y ;
int dx = x2 - x1 + 1; int dy = y2 - y1 + 1;
video_data += y1*mempitch+x1 ;
bitmap_data+=yoff*width+xoff ;
UINT piexl = 0 ;
for(int y = 0 ; y < dy ; y ++)
{
for(int x = 0 ; x < dx ; x ++)
{
if(_RGB32BIT(0,255,255,255)!=(piexl=bitmap_data[x]))
video_data[x] = piexl ;
}
bitmap_data += width ;
video_data += mempitch ;
}
}
void Transform24To32(UCHAR* pcBitmap ,int dwSizeImage ,UINT * pnBitmap )
{
for(int i = 0 ,j = 0 ; i < dwSizeImage ; i += 3,j++)
{
UCHAR blue = pcBitmap[i+0] ,
green = pcBitmap[i+1],
red = pcBitmap[i+2];
pnBitmap[j] = _RGB32BIT(0,red,green,blue);
}
}
LPDIRECTDRAWSURFACE7 DDraw_Create_Surface(int width , int height , int mem_flags)
{
DDSURFACEDESC2 ddsd ;
LPDIRECTDRAWSURFACE7 lpdds ;
DD_INIT_STRUCT(ddsd);
ddsd.dwFlags = DDSD_CAPS | DDSD_WIDTH | DDSD_HEIGHT ;
ddsd.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN | mem_flags ;
ddsd.dwWidth = width ;
ddsd.dwHeight = height ;
if(FAILED(lpdd->CreateSurface(&ddsd,&lpdds,NULL)))
{
OutputDebugString(L"CreateSurface for offscreen is error");
return NULL ;
}
DDCOLORKEY color_key ;
color_key.dwColorSpaceHighValue = _RGB32BIT(0,255,255,255);
color_key.dwColorSpaceLowValue = _RGB32BIT(0,255,255,255);
lpdds->SetColorKey(DDCKEY_SRCBLT,&color_key);
return lpdds ;
}
The code above is just make an animation , but it does not work at all .
By the way , I am a Chinese , and I am useing the DirectX 9.0 to do this .
Is there anyone who can tell me the reason ? Thank you very much .
Or is there some function like GetLastError in WIN32 API that can tell me what 's wrong with the Blt ?
Please , help me . I really want to solve this problem .
When I debug this , and I get the result of the Blt function is E_INVALIDARG . But when I delete the DDBLT_KEYSRC , the function is successful . I do not understand it .