410 likes | 703 Views
Chapter 10 DirectDraw 활용 : 애니메이션과 비트맵. In this Chapter…. - 하드웨어 가속을 위한 DirectDraw 사용하기 - 애니메이션 - 비트맵 불러오기 - 블리터 (blitter) 사용하기. 부드러운 애니메이션 테크닉. 페이지 전환 ( 플리핑 ;flipping) 더블 버퍼링 (double buffering) . Double Buffering.
E N D
In this Chapter… • - 하드웨어 가속을 위한 DirectDraw 사용하기 • - 애니메이션 • - 비트맵 불러오기 • - 블리터(blitter) 사용하기
부드러운 애니메이션 테크닉 • 페이지 전환(플리핑;flipping) • 더블 버퍼링(double buffering)
Double Buffering • 충분한 비디오 메모리가 없다면 DirectX가 대신 페이지 전환을 시뮬레이트하여 double buffering을 사용 • 우리들은 그 차이를 알지 못한다.
DEMO: PROG10_1 • Double buffering을 프로그래머가 해 준 경우. • Lpitch = screenwidth 인 경우와 아닌 경우를 달리 처리하였음.
페이지 전환(flipping) - 1 • DDSCAPS_PRIMARYSURFACE | DDSCAPS_FLIP | DDSCAPS_COMPLEX 사용 • 후면버퍼 카운트를 1로 DDSURFACEDESC2 ddsd; DDSCAPS2 ddscaps; LPDIRECTDRAWSURFACE7 lpddsprimary, // primary surface lpddssecondary; // secondary backbuffer surface memset(ddsd,0,sizeof(ddsd)); ddsd.dwSize = sizeof(ddsd); ddsd.dwFlags = DDSD_CAPS | DDSD_BACKBUFFERCOUNT; ddsd.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE | DDSCAPS_FLIP | DDSCAPS_COMPLEX; ddsd.dwBackBufferCount = 1; lpdd->CreateSurface(&ddsd,&lpddsprimary,NULL);
페이지 전환(flipping) - 2 // query for the backbuffer or secondary surface // notice the use of ddscaps to indicate what you’re requesting ddscaps.dwCaps = DDSCAPS_BACKBUFFER; // get the surface lpddsprimary->GetAttachedSurface(&ddscaps,&lpddsback); …. // flip the primary and secondary surfaces while(lpddsprimary->Flip(NULL, DDFLIP_WAIT)!=DD_OK);
DEMO PROG10_2 • PROG10_1 의 double buffering 에 비해 한결 간단하다.
블리터(Blitter) • 이미지를 한 곳에서 다른 곳으로 (보통 주표면) 비트맵 이미지를 복사하기 위해 비트 블리터(bit blitter) 하드웨어를 사용. • 비트맵이 스케일 되고 회전되거나, 혹은 다른 효과들을 처리하도록 요청할 수 있다. • 메모리의 일부분을 특정한 값으로 간단하게 채울 수 있다.
Blitter 함수 • Blt(): 화면의 모서리에 클리핑되는 것을 고려하지 않을 때 • BltFast(): 화면의 모서리에 클리핑되는 것을 고려할 때
Blt() HRESULT Blt( LPRECT lpDestRect, // the destination rectangle LPDIRECTDRAWSURFACE7 lpDDSrcSurf, // the source surface LPRECT lpSrcRect, // the source rectangle DWORD dwFlags, // control flags LPDDBLTFX lpDDBltFx); // the special fx structure
DDBLTFX Structure (1) typedef struct _DDBLTFX{ DWORD dwSize; // the size of this structure in bytes DWORD dwDDFX; // type of blitter fx DWORD dwROP; // Win32 raster ops that are supported DWORD dwDDROP; // DirectDraw raster ops that are supported DWORD dwRotationAngle; // angle for rotations DWORD dwZBufferOpCode; // z-buffer fields used for 3D DWORD dwZBufferLow; // advanced parameter DWORD dwZBufferHigh; // advanced parameter DWORD dwZBufferBaseDest; // advanced DWORD dwZDestConstBitDepth; // advanced union { DWORD dwZDestConst; // advanced... LPDIRECTDRAWSURFACE lpDDSZBufferDest; // advanced... }; DWORD dwZSrcConstBitDepth; // advanced...
DDBLTFX Structure (2) union { DWORD dwZSrcConst; // advanced... LPDIRECTDRAWSURFACE lpDDSZBufferSrc; // advanced... }; DWORD dwAlphaEdgeBlendBitDepth; // alpha stuff (advanced) DWORD dwAlphaEdgeBlend; // advanced... DWORD dwReserved; // advanced... DWORD dwAlphaDestConstBitDepth; // advanced... union { DWORD dwAlphaDestConst; // advanced... LPDIRECTDRAWSURFACE lpDDSAlphaDest; // advanced... }; DWORD dwAlphaSrcConstBitDepth; // advanced...
DDBLTFX Structure (3) union { DWORD dwAlphaSrcConst; // advanced... LPDIRECTDRAWSURFACE lpDDSAlphaSrc; // advanced... }; union // the following are very important { DWORD dwFillColor; // color word used for fill DWORD dwFillDepth; // z filling (advanced) DWORD dwFillPixel; // color fill word for RGB(alpha) fills LPDIRECTDRAWSURFACE lpDDSPattern; }; // the following are very important DDCOLORKEY ddckDestColorkey; // destination color key DDCOLORKEY ddckSrcColorkey; // source color key } DDBLTFX,FAR* LPDDBLTFX;
한가지 color로 칠하기 • DDBLT_COLORFILL • DDBLT_WAIT • 블리터가 요청을 수행하지 못하면 계속 하도록 지시하는 일반적인 예방책을 둔다.
Example DDBLTFX ddbltfx; // this contains the DDBLTFX structure RECT fill_area; // this contains the destination rectangle memset(&ddbltfx,0,sizeof(DDBLTFX)); ddbltfx.dwSize = sizeof(DDBLTFX); ddbltfx.dwFillColor = color; // your data 8,16,24 bit // fill in the destination-rectangle data (your data) fill_area.top = top; fill_area.left = left; fill_area.bottom = bottom; fill_area.right = right; // ready to blit to surface; in this case, blit to primary lpddsprimary->Blt(&fill_area, // pointer to dest rectangle NULL, // pointer to source surface, NA NULL, // pointer to source rectangle, NA DDBLT_COLORFILL | DDBLT_WAIT, // fill and wait &ddbltfx); // pointer to DDBLTFX structure
DEMO: PROG10_3 • 640x480 16비트 모드 윈도우를 생성하고 주표면을 랜덤한 크기의 색깔 있는 사각형을 블리트로 채운다
벡터 디스플레이 • 70년대 후반과 80년대 초반에는 테일거너(Tail Gunner)같은 많은 게임들은 디스플레이가 선으로 이루어지는 벡터 그래픽 디스플레이를 사용
Bitmap • 하나의 이미지를 나타내는 색깔 있는 픽셀의 2D 행렬(matrix)
Bitmap Animation • 해골 애니메이션의 56x72 크기 비트맵들
Bitmap Operations • 보조표면이나 주표면의 어디에든 비트맵을 불러와서 표시 • 비트맵을 애니메이션 • 움직이고 • 충돌 검사 • …
Bitmap Creation • 페인트 프로그램을 사용 • Template 사용
Bitmap 생성시 주의할 점 • 색상: 비트맵이 얼마나 많은 색상을 사용할 것인지 결정해야 하며, 그리고 모두 같은 색상 공간에서 그려야 한다. • 크기: 모든 비트맵을 2의 거듭제곱 크기로 그리도록 한다. 즉, 2x2, 4x4, 8x8, 16x16, 32,x32와 같이 이다. 이렇게 하면, 블리터와 게임에서 수행하는 여러 최적화에 유리하다. 정사각형이 되어야 하는 것은 아니다. 그러나 각 축은 2의 거듭제곱이 되도록 한다. 8x16은 좋지만 7x5는 좋지 않다. • 하나의 이미지 페이지에 여러 비트맵 크기를 섞지 않도록 한다. • Bitmap color space 바꾸기! How?
BITMAPFILEHEADER structure typedef struct tagBITMAPFILEHEADER { // bmfh WORD bfType; // type of bitmap; 0x4D42 means .BMP DWORD bfSize; // the total size of the file, in bytes WORD bfReserved1; // always 0 WORD bfReserved2; // always 0 DWORD bfOffBits; // number of bytes from this structure to access the // BITMAPINFO; basically an offset } BITMAPFILEHEADER;
BITMAPINFO structure • 팔레트가 파일에 있다면, bmiColors[] 배열은 팔레트를 포함하다. 그렇지 않으면 bmiColors[] 배열은 비어있다. typedef struct tagBITMAPINFO { BITMAPINFOHEADER bmiHeader; // contains all the data field definitions of the // .BMP file RGBQUAD bmiColors[1]; // the color palette } BITMAPINFO;
BITMAPINFOHEADER structure typedef struct tagBITMAPINFOHEADER{ DWORD biSize; // number of bytes in this structure LONG biWidth; // width of bitmap LONG biHeight; // height of bitmap WORD biPlanes; // number of color planes (always 1) WORD biBitCount // bits per pixel (1,4,8,16,24, or 32) DWORD biCompression; // type of compression; always BI_RGB for // noncompressed bitmaps DWORD biSizeImage; // size of image in bytes LONG biXPelsPerMeter; // x res of target display LONG biYPelsPerMeter; // y res of target display DWORD biClrUsed; // how many colors are used DWORD biClrImportant; // number of important colors; only for Windows apps } BITMAPINFOHEADER;
Bitmap File Structure typedef struct BITMAP_FILE_TAG { BITMAPFILEHEADER bitmapfileheader; BITMAPINFOHEADER bitmapinfoheader; PALETTEENTRY palette[256]; // the 256-color palette UCHAR *buffer; // pointer to data } BITMAP_FILE, *BITMAP_FILE_PTR;
비트맵을 불러오기 두 개의 함수 int Load_Bitmap_File(BITMAP_FILE_PTR bitmap, char *filename) int Unload_Bitmap_File(BITMAP_FILE_PTR bitmap)
DEMO: PROG10_4 • Bitmap file loading • 비트맵은 8비트. 16비트, 또는 24비트 형식이 될 수 있다. 그리고 그 함수는 24비트 이미지를 16비트 RGB 이미지로 변환한다.
DEMO: PROG10_5 • 16bit file 읽어와서 뿌리기 데모
블리터로 비트 채우기 (1) // create the primary surface memset(&ddsd,0,sizeof(ddsd)); ddsd.dwSize = sizeof(ddsd); ddsd.dwFlags = DDSD_CAPS | DDSD_BACKBUFFERCOUNT; // you need to tell DirectDraw that you want a complex // flippable surface structure; set flags for that ddsd.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE | DDSCAPS_FLIP | DDSCAPS_COMPLEX; // set the backbuffer count to 1 ddsd.dwBackBufferCount = 1; // create the primary surface lpdd->CreateSurface(&ddsd,&lpddsprimary,NULL); // query for the backbuffer; that is, the secondary surface ddscaps.dwCaps = DDSCAPS_BACKBUFFER; lpddsprimary->GetAttachedSurface(&ddscaps,&lpddsback);
블리터로 비트 채우기 (2) // load the bitmap Load_Bitmap_File(&bitmap16bit, “ANDRE16.BMP”); // lock the secondary surface memset(&ddsd,0,sizeof(ddsd)); ddsd.dwSize = sizeof(ddsd); lpddsback->Lock(NULL,&ddsd, DDLOCK_SURFACEMEMORYPTR | DDLOCK_WAIT,NULL); // get video pointer secondary_buffer = (UCHAR *)ddsd.lpSurface; // copy the bitmap data into secondary surface; this time, assume linear memory memcpy(secondary_buffer, bitmap16bit.buffer, 640*480); // unlock the secondary backbuffer lpddsback->Unlock(NULL);
블리터로 비트 채우기 (3) // select source position to grab bitmap from int source_x = rand()%640; int source_y = rand()%480; // select destination position to blit to int dest_x = rand()%640; int dest_y = rand()%480; // select width and height of rectangle int width = rand()%640; int height = rand()%480; // set up rectangles RECT source_rect, dest_rect; source_rect.left = source_x; source_rect.top = source_y; source_rect.right = source_x + width; source_rect.bottom = source_y + height; dest_rect.left = dest_x; dest_rect.top = dest_y; dest_rect.right = dest_x + width; dest_rect.bottom = dest_y + height;
블리터로 비트 채우기 (4) // set up the color key so that color index 0 is transparent. If you’re using a // 16/24 bit mode then you would build the actual RGB values for the transparent // color and place the SAME value in both the low and high color key DDCOLORKEY col_key; col_key.dwColorSpaceLowValue = 0; // RGB16BIT565(0,0,0) for 16 bit col_key.dwColorSpaceHighValue = 0; // RGB16BIT565(0,0,0) for 16 bit // set the key lpddsback->SetColorKey(DDCKEY_SRCBLT, &col_key); // perform the blit lpddsprimary->Blt(&dest_rect, lpddsback, &source_rect, DDBLT_KEYSRC | DDBLT_WAIT, NULL);