1 / 62

Chapter 11 DirectDraw 의 깊은 곳 : 보다 발전된 기능들

Chapter 11 DirectDraw 의 깊은 곳 : 보다 발전된 기능들. 이 장에서는. - 비트맵 그래픽으로 고급 작업 수행하기 - 오프스크린 표면 사용하기 - 색상 애니메이션 기법 알아보기 - DirectDraw 와 GDI 결합하기 - 윈도우 모드에서 DirectDraw 사용하기 - DirectDraw 에서 정보 얻어오기. 투명도. Black-transparent 8-bit version. // 32 x 32 bitmap 을 화면 (x,y) 에 뿌리는 예제

nessa
Download Presentation

Chapter 11 DirectDraw 의 깊은 곳 : 보다 발전된 기능들

An Image/Link below is provided (as is) to download presentation Download Policy: Content on the Website is provided to you AS IS for your information and personal use and may not be sold / licensed / shared on other websites without getting consent from its author. Content is provided to you AS IS for your information and personal use only. Download presentation by click this link. While downloading, if for some reason you are not able to download a presentation, the publisher may have deleted the file from their server. During download, if you can't get a presentation, the file might be deleted by the publisher.

E N D

Presentation Transcript


  1. Chapter 11DirectDraw의 깊은 곳: 보다 발전된 기능들

  2. 이 장에서는 • - 비트맵 그래픽으로 고급 작업 수행하기 • - 오프스크린 표면 사용하기 • - 색상 애니메이션 기법 알아보기 • - DirectDraw와 GDI 결합하기 • - 윈도우 모드에서 DirectDraw 사용하기 • - DirectDraw에서 정보 얻어오기

  3. 투명도

  4. Black-transparent 8-bit version // 32 x 32 bitmap을 화면 (x,y) 에 뿌리는 예제 // (x, y) 는 bitmap의 왼쪽 위 꼭지점이 된다. // (index_x, index_y) 는 32x32 bitmap을 따라간다. for (int index_y=0; index_y<32; index_y++) { for (int index_x=0; index_x<32; index_x++) { UCHAR pixel = image[index_x+index_y*32]; if (pixel!=0) primary_buffer[x+index_x+(y+index_y)*ddsd.lPitch] = pixel; } // end for index_x } // end for index_y

  5. Black-transparent 16-bit version // these two loops blit a 32 x 32 bitmap for (int index_y=0; index_y<32; index_y++) { // copy next row of pixels for (int index_x=0; index_x<32; index_x++) { // get the next pixel USHORT pixel = image[index_x+index_y*32]; // test if pixel is transparent if (pixel!=_RGB16BIT565(0,0,0)) primary_buffer[x+index_x+(y+index_y)*(ddsd.lPitch/2)] = pixel; // else do nothing } // end for index_x } // end for index_y

  6. Black-transparent 8-bit (without multiply) UCHAR *src_ptr = image; UCHAR *dest_ptr = primary_buffer + x + y * ddsd.lPitch; for (int index_y=0; index_y<32; index_y++) { for (int index_x=0; index_x<32; index_x++) { UCHAR pixel = *src_ptr; if (pixel!=0) *dest_ptr = pixel; src_ptr++; dest_ptr++; } // end for index_x // move destination pointer to start of next line dest_ptr+=(ddsd.lPitch - 32); } // end for index_y

  7. Black-transparent 16-bit (without multiply) • Try it !

  8. Multiplication/Division by shift • player_x*64 = player_x <<6 • player_x*96 = player_x*64 + player_x*32 = (player_x << 6) + (player_x << 5)

  9. 색상키(color keying) • 원본키(source key) • 투명한 색상의 범위를 설정하고, 블리터에게 이 범위를 복사하지 말도록 지시 HRESULT SetColorKey(DWORD dwFlags, // what kind of key LPDDCOLORKEY lpDDColorKey); // range of key typedef struct _DDCOLORKEY { DWORD dwColorSpaceLowValue; // starting color (inclusive) DWORD dwColorSpaceHighValue;// ending color (inclusive) } DDCOLORKEY,FAR* LPDDCOLORKEY;

  10. Source Key Example DDCOLORKEY key; // color key // set transparent color range to 0 key.dwColorSpaceLowValue = 0; key.dwColorSpaceHighValue = 0; // set color key now on the source surface, which is usually the backbuffer lpddsback->SetColorKey(DDCKEY_SRCBLT, &key); // perform the blit from backbuffer to primary buffer lppddsprimary->Blt(...);

  11. Source Key의 예 Y Source Key = R R + G B Blitting Source Destination Y G B Result

  12. 목적키(destination key) • 그려질 목적 표면에 색상키 범위를 설정 • Dest key 와 같은 색이 먼저 깔려 있으면 그 곳에는 blitting 되지 않는다. DDCOLORKEY key; // color key // set writable values from 0 to 249 key.dwColorSpaceLowValue = 0; key.dwColorSpaceHighValue = 249; // set color key now on the destination surface lpddsprimary->SetColorKey(DDCKEY_DESTCBLT, &key); // perform the blit from backbuffer to primary buffer // or whatever is the source surface... lppddsprimary->Blt(...);

  13. B Destination Key의 예 Y Dest Key = B R + G B Blitting Source Destination Y R G Result

  14. 템플릿으로부터 비트맵 추출

  15. BOB(Bitmapped Object Bitmap) 사용 1. DirectDraw를 설정한다. 2. 10장에서처럼 8비트 또는 16비트 색상의 비트맵 이미지에 객체들을 불러온다. 3. Create_BOB() 또는 Create_BOB16()으로 BOB를 생성한다. 4. Load_BOB() 또는 Load_BOB16()으로 이미지를 BOB에 불러온다. 5. Draw_BOB() 또는 Draw_BOB16()으로 BOB를 그린다. 6. 완료하면, Destroy_BOB() 또는 Destroy_BOB16()으로 BOB을 제거한다.

  16. BOB Structure typedef struct BITMAP_OBJ_TYP { int state; // the state of the object (general) int attr; // attributes pertaining to the object (general) int x,y; // position bitmap will be displayed at int xv,yv; // velocity of object int width, height; // the width and height of the bitmap LPDIRECTDRAWSURFACE7 image; // the bitmap surface itself } BITMAP_OBJ, *BITMAP_OBJ_PTR; #define BOB_STATE_DEAD 0 // this is a dead BOB #define BOB_STATE_ALIVE 1 // this is a live BOB #define BOB_STATE_LOADED 2 // the BOB has been loaded

  17. 죽은(dead) BOB와 살아있는(live) BOB • 살아있다는 것은 BOB가 게임 로직에 의해 처리되고 있음을 뜻한다. • BOB가 죽었다는 것은 게임 로직에 의해 처리되지 않는다는 것을 의미한다.

  18. BOB 생성 (1) int Create_BOB(BITMAP_OBJ_PTR bob, // the BOB to create int width, int height, // size of BOB int attr, // attrs int flags = 0) // memory flag { // create the BOB object; note that all BOBs are created as off-screen // surfaces in VRAM as the default; if you want to use system memory, // set flags equal to DDSCAPS_SYSTEMMEMORY DDSURFACEDESC2 ddsd; // used to create surface // set state and attributes of BOB bob->state = BOB_STATE_ALIVE; bob->attr = attr; bob->image = NULL; // set position and velocity to 0 bob->x = bob->y = bob->xv = bob->yv = 0; // set to access caps, width, and height memset(&ddsd,0,sizeof(ddsd)); ddsd.dwSize = sizeof(ddsd); ddsd.dwFlags = DDSD_CAPS | DDSD_WIDTH | DDSD_HEIGHT;

  19. BOB 생성 (2) // set dimensions of the new bitmap surface ddsd.dwWidth = bob->width = width; ddsd.dwHeight = bob->height = height; // set surface to off-screen plain ddsd.ddsCaps.dwCaps = DDSCAPS_OFF_SCREENPLAIN | flags; // create the surface if (lpdd->CreateSurface(&ddsd,&(bob->image),NULL)!=DD_OK) return(0); // set color key to color 0 DDCOLORKEY color_key; // used to set color key color_key.dwColorSpaceLowValue = 0; color_key.dwColorSpaceHighValue = 0; // now set the color key for source blitting (bob->image)->SetColorKey(DDCKEY_SRCBLT, &color_key); // return success return(1); } // end Create_BOB

  20. 비트맵 데이터로 BOB 로딩하기 (1) • 목적 BOB와 읽어올 원본 비트맵 파일을 인수로 받는다. • (cx, cy)와 mode에 의해서 읽어올 위치가 결정된다. • Cell Mode (0): (cx, cy)는 셀 좌표로 해석된다. • Absolute Mode (1): (cx, cy)는 원본 비트맵의 절대 좌표로 해석된다. • 읽을 비트맵의 크기는 BOB와 정확하게 맞으며, 이것은 bob->width와 bob->height에 정의된다.

  21. 비트맵 데이터로 BOB 로딩하기 (2)

  22. 비트맵 데이터로 BOB 로딩하기 (3) int Load_BOB(BITMAP_OBJ_PTR bob, // BOB to load with data BITMAP_FILE_PTR bitmap, // bitmap to scan image data from int cx,int cy, // cell or absolute pos to scan image from int mode) // if 0, then cx,cy is cell position; else // cx,cy are absolute coordinates { // this function extracts a bitmap out of a bitmap file UCHAR *source_ptr, // working pointers *dest_ptr; DDSURFACEDESC2 ddsd; // DirectDraw surface description // test the mode of extraction, cell-based or absolute if (mode==0) { // re-compute x,y cx = cx*(bob->width+1) + 1; cy = cy*(bob->height+1) + 1; } // end if

  23. 비트맵 데이터로 BOB 로딩하기 (4) // extract bitmap data source_ptr = bitmap->buffer + cy*bitmap->bitmapinfoheader.biWidth+cx; // get the addr to destination surface memory // set size of the structure ddsd.dwSize = sizeof(ddsd); // lock the display surface (bob->image)->Lock(NULL, &ddsd, DDLOCK_WAIT | DDLOCK_SURFACEMEMORYPTR, NULL); // assign a pointer to the memory surface for manipulation dest_ptr = (UCHAR *)ddsd.lpSurface;

  24. 비트맵 데이터로 BOB 로딩하기 (5) // iterate through each scanline and copy bitmap for (int index_y=0; index_y<bob->height; index_y++) { // copy next line of data to destination memcpy(dest_ptr, source_ptr,bob->width); // advance pointers dest_ptr += (ddsd.lPitch); source_ptr += bitmap->bitmapinfoheader.biWidth; } // end for index_y // unlock the surface (bob->image)->Unlock(NULL); // set state to loaded bob->state |= BOB_STATE_LOADED; // return success return(1); } // end Load_BOB

  25. BOB 그리기 int Draw_BOB(BITMAP_OBJ_PTR bob, // BOB to draw LPDIRECTDRAWSURFACE7 dest) // surface to draw the BOB on { // draw a BOB at the x,y defined in the BOB // on the destination surface defined in dest RECT dest_rect, // the destination rectangle source_rect; // the source rectangle // fill in the destination rect dest_rect.left = bob->x; dest_rect.top = bob->y; dest_rect.right = bob->x+bob->width; dest_rect.bottom = bob->y+bob->height; // fill in the source rect source_rect.left = 0; source_rect.top = 0; source_rect.right = bob->width; source_rect.bottom = bob->height; // blt to destination surface dest->Blt(&dest_rect, bob->image, &source_rect,(DDBLT_WAIT | DDBLT_KEYSRC), NULL); // return success return(1); } // end Draw_BOB

  26. BOB 소멸하기 int Destroy_BOB(BITMAP_OBJ_PTR bob) { // destroy the BOB; simply release the surface if (bob->image) (bob->image)->Release(); else return(0); // return success return(1); } // end Destroy_BOB

  27. BOB를 움직이게 하는 함수들 (16bit) BITMAP_FILE bitmap; // working bitmap file BITMAP_OBJ car; // the bitmapped object // load the bitmap Load_Bitmap_File(&bitmap,”cars16.bmp”); // create a 32 x 32 VRAM BOB Create_BOB16(&car,32,32,0,0,0); // load the BOB with first cell of bitmap template image Load_BOB16(&car,0,0,0); // unload the bitmap; you’re done with it Unload_Bitmap_File(&bitmap); // set position of BOB car.x = 100; car.y = 200; // draw BOB on primary surface Draw_BOB16(&car, lppdsprimary); // your game code goes here... // delete the BOB Destroy_BOB16(&car);

  28. DEMO: PROG11_1_16

  29. 색상을 이용한 기술들 • 게임 프로그래머는 기교(trick)를 써서 • 그래픽 시스템이 실제보다 더 많은 색상이 있는 것처럼 보이게 하고, • 또한 기존 하드웨어로는 불가능한 것처럼 보이는 광원(lighting) 효과를 적용하기도 했다. • 요즘에는 이런 trick을 쓰지 않아도 된다. • 휴대폰이나 PDA 게임 프로그래밍에 여전히 적용 가능하다.

  30. 팔레트 애니메이션 • 8비트 색상 모드에서만 적용 • 하나 혹은 이상의 팔레트 항목을 실시간에 새로운 데이터로 갱신하는 것이다. • 이 방법으로 이들 색상으로 그려진 픽셀은 시간에 따라 변한다. • 깜빡이는 빛이나, 에너지 펄스, 폭발 등에 이 기법을 사용한다.

  31. DEMO: PROG11_2

  32. 색상 회전(color rotation) • 움직임을 잘 시뮬레이션 한다 • 폭포수나 흐르는 샘물, 또는 컨베이어 벨트

  33. DEMO: PROG11_3

  34. 클리핑(clipping) • 이미지에서 보이지 않는 부분을 그리지 않는 것을 의미

  35. 두가지 클리핑 방법 • 이미지-공간(image-space) 클리핑 • 픽셀 단위로 그리는 것처럼 클리핑하는 방법이다. • 시간이 많이 걸리고, 때로는 하드웨어 가속기능이 있을 때에만 잘 동작한다. • 물체의 각 픽셀을 그릴 때에 그것이 클리핑 영역에 그려지지 않는 것을 확인해야 한다는 것이다. • 오브젝트-공간(object-space) 클리핑 • 매 픽셀마다 클리핑 영역과 비교하는 것이 아니라, 그려질 물체의 형태를 분석하여, 어느 정도의 부분을 그려야 하는지 계산 • 이미지-공간 클리핑보다 조금 더 수학적이다.

  36. Clipping Cases

  37. 오브젝트-공간 클리핑의 간단한 예 // trivial rejections test first // is the rectangle totally off the screen? if (x1 > MAX_X || x2 < MIN_X || y1 > MAX_Y || y2 < MIN_Y) { /* totally clipped, do nothing */ } // check x coords if (x1 < MIN_X) x1 = MIN_X; else if (x2 > MAX_X) x2 = MAX_X; // now y coords if (y1 < MIN_Y) y1 = MIN_Y; else if (y2 > MAX_Y) y2 = MAX_Y; // at this point, (x1,y1) through (x2,y2) contain the clipped rectangle...

  38. DirectDrawClipper의 소개 • DirectDraw는 블리트하고자 하는 어떤 표면에도 추가할 수 있는 DirectDrawClipper를 지원한다. • 클리퍼는 여러 개의 클리핑 영역을 가질 수 있다.

  39. DirectDrawClipper를 생성하는 단계 1. DirectDrawClipper 객체를 생성한다. 2. 클리핑 사각형의 목록을 생성하고 그것을 클리퍼(clipper)에 할당한다. 3. 클리퍼를 표면(surface)에 추가한다.

  40. DirectDrawClipper 생성 // Prototype HRESULT CreateClipper(DWORD dwFlags, // unused; make 0 LPDIRECTDRAWCLIPPER FAR *lplpDDClipper, // ptr to result IUnknown FAR *pUnkOuter); // always NULL // Example LPDIRECTDRAWCLIPPER lpddclipper; // the clipper if ((lpdd->CreateClipper(0,&lpddclipper,NULL))!=DD_OK) return(NULL);

  41. 클리핑 목록 채우기 (1) • RGNDATA typedef struct _RGNDATA { // rgnd RGNDATAHEADER rdh; // the header char Buffer[1]; // a list of RECTs defining clipping } RGNDATA; typedef struct _RGNDATAHEADER { // rgndh DWORD dwSize; // size of this header DWORD iType; // must be RDH_RECTANGLES DWORD nCount; // number of rectangles in buffer DWORD nRgnSize; // size of the buffer RECT rcBound; // a bounding box around all the rects } RGNDATAHEADER;

  42. 클리핑 목록 채우기 (2) HRESULT SetClipList( LPRGNDATA lpClipList, // ptr to RGNDATA DWORD dwFlags); // unused; must be 0 RGNDATA region_data; // holds the RECTs and data header // fill in region_data... // set clipping list if ((lpddclipper->SetClipList(&region_data, 0))!=DD_OK) { /* error */ }

  43. 클리퍼를 표면에 추가하기 if ((lpdds->SetClipper(lpddclipper))!=DD_OK) { /* error */ }

  44. Wrapper Fn: DD_Attach_Clipper (1) LPDIRECTDRAWCLIPPER DD_Attach_Clipper(LPDIRECTDRAWSURFACE7 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; // looping var 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 DirectDraw clipper if ((lpdd->CreateClipper(0,&lpddclipper,NULL))!=DD_OK) 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);

  45. Wrapper Fn: DD_Attach_Clipper (2) // 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 whether 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; ….

  46. Wrapper Fn: DD_Attach_Clipper (3) // set up fields of header // you’ve computed the bounding rectangle region and // set up the data; now set the clipping list if ((lpddclipper->SetClipList(region_data, 0))!=DD_OK) { // release memory and return error free(region_data); return(NULL); } // end if // now attach the clipper to the surface if ((lpdds->SetClipper(lpddclipper))!=DD_OK) { // release memory and return error free(region_data); return(NULL); } // end if // all is well, so release memory and send back the pointer // to the new clipper free(region_data); return(lpddclipper); } // end DD_Attach_Clipper

  47. 클리핑 목록을 설정하는 방법 // create clip list (4) rectangles RECT cliplist[4] = { {0,0,100,100}, {200,200,300,300}, {400,100,500,200}, {500,400,550,450}}; // attach clipper and save in lpddclipper lpddclipper = DD_Attach_Clipper(lpddsprimary,4,cliplist);

  48. DEMO: PROG11_4_16B

  49. GDI와 DirectDraw의 사용 • 윈도우즈와 DirectDraw의 고수준(메시지 상자, 메뉴 등)과 저수준(물체 그리기, 텍스트 그리기) 혼합

  50. DirectDraw에서 GDI를 사용하기 위해 세 가지 선택 • 고수준 컨트롤의 경우 • GDC(Graphics Device Context; 그래픽 장치 컨텍스트)를 이용하지 않고, GDI를 이용하는 가장 간단한 방법이다. 대신, 메시지 상자, 대화상자, 메뉴와 같은 고수준 컨트롤을 사용한다. GDC는 HDC(Handle to Device Context)의 특수한 경우이다. • GDC를 이용하는 경우 • 임의의 표면에 그리기 위해 GDC(비디오 모드, 메모리, 해상도, 색상 공간 등의 기술)를 사용할 수 있다. IDIRECTDRAWSURFACE7의 함수를 이용하여 DirectDraw로부터 GDC를 요청한다. • 윈도우 모드의 경우 • 표준 윈도우 모드를 이용하여 GDI와 함께 DirectDraw를 사용할 수 있다. 이 책에 나오는 대부분의 그래픽을 이용하는 코드는 전체 비디오 표면을 위임받고 그래픽 모드를 변경한다. 그러나 때때로 그렇게 하고 싶지 않을 수도 있고, 표준 윈도우 모드에서 DirectDraw를 이용하여 그릴 수도 있다.

More Related