Upload
dinah-sparks
View
232
Download
0
Embed Size (px)
Citation preview
Chapter 9Chapter 9
DirectDraw DirectDraw 크래용 사용하기 크래용 사용하기
2
이 장에서는이 장에서는 ... ...
• 표면 생성하기• 색상 팔레트 다루기• DirectDraw 로 그리기
3
DirectDraw DirectDraw 표면 표면 (Surface)(Surface)
• 실제로 비디오 카드의 비디오 메모리와 직접 대응 • 표면은 어떤 크기도 될 수 있다 . 주표면은 현재 화면
해상도와 같은 크기여야 한다 . 그러나 , 다른 표면은 어떤 크기라도 될 수 있다 .
• 표면은 비디오 메모리에 (VRAM) 또는 시스템 메모리에 생성할 수 있다 .
• 비트깊이와 색상공간이 같은 한 , 모든 표면은 같은 속성을 갖는다 .
4
DirectDraw SurfaceDirectDraw Surface
5
SurfacesSurfaces
• 주 디스플레이 표면 (primary display surface)– 보여지는 비디오 화면 자체 , 비디오 카드의 비디오 메모리와
직접적으로 대응
• 보조 디스플레이 표면 (secondary display surface)– 후면버퍼 (back buffer) – 주표면과 같은 구조– 내용은 화면에 보여지지 않는다 . – 애니메이션을 위해 다음 프레임을 렌더링
• 오프스크린 표면 (offscreen surface)– 이것은 하드웨어 가속을 이용해서 빠르게 그리고 싶은 비트
맵 , 스프라이트 , 또는 스크린 아이템 ( 예들 들어 캐릭터나 우주선 등 ) 을 저장하는 표면이다 .
6
SurfacesSurfaces
7
주표면주표면 (Primary Surface) (Primary Surface) 사용하기 사용하기
• CreateSurface() 를 호출 HRESULT CreateSurface(
LPDDSURFACEDESC2 lpDDSurfaceDesc,
LPDIRECTDRAWSURFACE7 FAR *lplpDDSurface,
IUnknown FAR *pUnkOuter);
– lpDDSurfaceDesc: DirecDraw 표면을 기술하는 구조체의 포인터 . 원하는 표면을 기술하는 여러 속성들을 이 포인터에 설정한다 .
– lplpDDSurface: 성공하면 함수로부터 반환될 DirectDraw 표면의 인터페이스의 포인터이다 .
– pUnkOuter: 심화된 기능으로 , COM aggregation 에 사용된다 . 항상 NULL 로 놓도록 한다 .
8
DDSURFACEDESC structure (1)DDSURFACEDESC structure (1)
typedef struct _DDSURFACEDESC2 { DWORD dwSize; // the size of this structure in bytes // this field must be set by you DWORD dwFlags; // flags field indicating which fields // of this structure are valid with data DWORD dwHeight; // width of surface DWORD dwWidth; // height of surface union { LONG lPitch; // number of bytes per line DWORD dwLinearSize; // used for compression } DUMMYUNIONNAMEN(1); DWORD dwBackBufferCount; // number of back buffers
9
DDSURFACEDESC structure (2) DDSURFACEDESC structure (2)
union
{
DWORD dwMipMapCount; // number of mip levels
DWORD dwRefreshRate; // refresh rate in hz
} DUMMYUNIONNAMEN(2);
DWORD dwAlphaBitDepth; // number of bits for alpha
DWORD dwReserved;
LPVOID lpSurface; // pointer to surface memory
10
DDSURFACEDESC structure (3)DDSURFACEDESC structure (3)
union { DDCOLORKEY ddckCKDestOverlay; // color key for // destination overlay DWORD dwEmptyFaceColor; // 3d stuff } DUMMYUNIONNAMEN(3); DDCOLORKEY ddckCKDestBlt; // color key for // destination blit DDCOLORKEY ddckCKSrcOverlay; // color key for overlay DDCOLORKEY ddckCKSrcBlt; // color key for source blit DDPIXELFORMAT ddpfPixelFormat; // general pixel format DDSCAPS2 ddsCaps; // capabilities bits DWORD dwTextureStage; // 3d stuff} DDSURFACEDESC2, FAR* LPDDSURFACEDESC2;
11
dwFlagsdwFlags
• DDSD_ALL All input members are valid.• DDSD_ALPHABITDEPTH dwAlphaBitDepth member is valid.• DDSD_BACKBUFFERCOUNT dwBackBufferCount member is valid.• DDSD_CAPS ddsCaps member is valid.• DDSD_CKDESTBLT ddckCKDestBlt member is valid.• DDSD_CKDESTOVERLAY ddckCKDestOverlay member is valid.• DDSD_CKSRCBLT ddckCKSrcBlt member is valid.• DDSD_CKSRCOVERLAY ddckCKSrcOverlay member is valid.• DDSD_HEIGHT dwHeight member is valid.• DDSD_LINEARSIZE Unused.• DDSD_LPSURFACE lpSurface member is valid.• DDSD_MIPMAPCOUNT dwMipMapCount member is valid.• DDSD_PITCH lPitch member is valid.• DDSD_PIXELFORMAT ddpfPixelFormat member is valid.• DDSD_REFRESHRATE dwRefreshRate member is valid.• DDSD_WIDTH dwWidth member is valid.• DDSD_ZBUFFERBITDEPTH dwZBufferBitDepth member is valid.
12
Fields (1)Fields (1)
• dwSize: DDSURFACEDESC 구조체의 크기로 개발자가 꼭 설정해야 한다 .
• dwFlags: 유효한 속성 정보 플래그를 포함한다 . 다른 말로 하면 , 수정하거나 얻어오고 싶은 모든 속성을 논리적인 OR 로 플래그 속성을 설정해야 한다 .
• dwHeight: 픽셀단위의 표면의 높이이다 .• dwWidth: 픽셀단위의 표면의 폭이다 .• lpSurface: 표면이 잠그어질 때 , 표면 VRAM 을
가리키는 포인터이다 . 잠그기 (locking) 는 표면 메모리의 일부분을 수정할 것이라고 DirectDraw 에게 알리는 과정이다 .
13
Fields (2)Fields (2)
• dwBackBufferCount: 오프스크린 버퍼나 페이지의 숫자를 지정한다 . DirectDraw 에서 여러 개의 표면을 생성할 수 있다 . 따라서 한 표면을 표시하는 동안 다른 표면에 그림으로써 부드러운 애니메이션을 만들 수 있다 .
• lPitch: 표면의 메모리 피치 (memory pitch) 로 , 한 줄당 바이트 수를 말한다 .
• ddCaps: 표면의 부가적인 기능 (capability) 들이다 .typedef struct _DDSCAPS2 {
DWORD dwCaps;
DWORD dwCaps2;
DWORD dwCaps3;
DWORD dwCaps4;
} DDSCAPS2, FAR* LPDDSCAPS2;
14
Fields (3)Fields (3)
• dwCaps: 표면에 부여되길 원하는 기능들을 저장한다 . – DDSCAPS_BACKBUFFER
• 표면이 전환 사슬 (flipping chain) 의 후면버퍼가 된다 .
– DDSCAPS_COMPLEX• 표면이 하나의 주표면 이상을 갖는 복잡한 표면의 일부가 된다 .
– DDSCAPS_FLIP• 표면이 플립 가능하다 .
– DDSCAPS_FRONTBUFFER• 표면이 전환 구조에서 첫번째 , 혹은 전면버퍼 (frontbuffer) 가
된다 .
– DDSCAPS_MODEX• 표면이 320x200 이나 320x240 모드 X 표면이다 .
– DDSCAPS_OFFSCREENPLAIN• 표면이 오버레이 , 텍스쳐 , z- 버퍼 , 전면버퍼 , 후면버퍼 , 알파
표면이 아닌 오프스크린 표면이 된다 . 보통 스프라이트나 비트맵에 사용한다 .
15
Fields (4)Fields (4)
– DDSCAPS_OWNDC• 표면이 장시간 윈도우즈 장치 컨텍스트와의 연관을 갖는다 .
– DDSCAPS_PRIMARYSURFACE• 표면이 주표면이다 . 즉 , 보여지고 렌더링된다 .
– DDSCAPS_STANDARDVGAMNODE• 표면이 표준 VGA 모드 표면이며 , 모드 X 표면이 아니다 .
– DDSCAPS_SYSTEMMEMORY• 표면이 시스템 메모리에 할당된다 .
16
주표면 생성하기 주표면 생성하기 - 1 - 1
// pointer to DirectDraw objectLPDIRECTDRAW7 lpdd;// used to hold the DirectDraw surface descriptionDDSURFACEDESC2 ddsd;// where the interface pointer will be placed// when the surface is createdLPDIRECTDRAWSURFACE7 lpddsprimary;// create DirectDraw objectDirectDrawCreateEx(NULL, (void **)&lpdd, IID_IDirectDraw7, NULL);// set cooperation levellpdd->SetCooperativeLevel(hwnd, DDSCL_ALLOWREBOOT | DDSCL_ALLOWMODEX | DDSCL_FULLSCREEN | DDSCL_EXCLUSIVE );// now set the display mode; assume constants definedlpdd->SetDisplayMode(SCREEN_WIDTH,SCREEN_HEIGHT, SCREEN_BPP,0,0);
17
주표면 생성하기 주표면 생성하기 - 2- 2
// create the primary surface
// manually set the size; very important
ddsd.dwSize = sizeof(ddsd);
// the only field you modify, so you must indicate in the flags
// that you want a primary drawing surface; in this case, you don’t have
// to define anything else, because DirectDraw already knows the
// resolution and color of the video mode
ddsd.dwFlags = DDSD_CAPS;
// set the capabilities to what you want, a primary surf
ddsd.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE;
// create the surface and check for an error
if (lpdd->CreateSurface(&ddsd,&lpddsprimary,NULL)!=DD_OK)
{ /* error */ }
18
COM Interface ReleaseCOM Interface Release
// first release the surface, but check for NULL
if (lpddsprimary)
lpddsprimary->Release();
// now release the DirectDraw object itself
if (lpdd)
lpdd->Release();
19
PROG9_1.CPP PROG9_1.CPP
• 800x600x16 모드
20
Linear 640 x 480 x 256-color mode.Linear 640 x 480 x 256-color mode.
21
비디오의 다음 줄을 얻기 위해서 비디오의 다음 줄을 얻기 위해서
• 640 을 더하는 대신에 , 1,024 같은 숫자를 더해야 할 수도 있다 . ( 이 수를 lpitch 라고 하며 video card 마다 다르다 .)
UCHAR *video_buffer;
// point video buffer to primary surface...
// (check out the section “The details of rendering to the primary surface”
// for this code)
// write a single pixel; color is a palette index
video_buffer[x + 1024*y] = color;
22
The memory mapping of the primary The memory mapping of the primary surface surface
23
640 x 480 x 8 mode 640 x 480 x 8 mode
// used to access data
UCHAR *video_buffer;
// point video_buffer to primary surface...
// check out the section “The details of rendering to the primary surface”
// for this code
// write a single pixel; color is a palette index
video_buffer[x + 640*y] = color;
24
640 x 480 x 16-bit color mode 640 x 480 x 16-bit color mode
// this time, use a 16-bit short
USHORT *video_buffer;
// point video buffer to primary surface...
// write a single pixel; color is a palette index
video_buffer[x + 640*y] = color;
• RGB 값 ( 각각 5 비트 ) • 픽셀당 2 바이트 • 각 줄은 1,280 바이트
25
주표면 렌더링 주표면 렌더링
• DirectDraw 는 디자인상 렌더링을 아주 조금 지원한다 . • 대부분의 게임 프로그래머는 자신의 그래픽스 엔진과
라이브러리를 작성한다 . • 따라서 DirectDraw 는 게임 프로그래머에게 기본적인
– 색상 지원 , – 비디오 버퍼 접근 , – 하드웨어를 이용한 고속 채움 (filling) 및 블리팅 (blitting) 을
제공한다 .
26
팔레트 모드팔레트 모드
• 각 픽셀은 한 바이트로 표현 • 각 바이트는 실제 RGB 값을 가지고 있는 색상조사표
(CLUT) 의 인덱스 • 순서
– Lock()– Write or Read– Unlock()
• LockHRESULT Lock(LPRECT lpDestRect, // rectangle to lock; use NULL to lock // the entire surfaceLPDDSURFACEDESC2 lpDDSD, // returns the properties of the su
rface being lockedDWORD dwFlags, // control flagsHANDLE hEvent); // unused; set to NULL
27
Flags for Lock()Flags for Lock()
• Table 9-3 Flags for Lock()• Value Meaning• DDLOCK_READONLY The surface locked is reada
ble only.• DDLOCK_SURFACEMEMORYPTR The surface l
ocked returns a memory pointer to the surface memory in lpSurface. This default action takes place if you don’t send any flags.
• DDLOCK_WAIT If the surface can’t be locked, wait until it can be.
• DDLOCK_WRITEONLY The surface being locked is written to only.
28
UnlockUnlock
• HRESULT Unlock(LPRECT lpRect); // pointer to rectangle to unlock
29
8-bit Example (1)8-bit Example (1)
• 표준 DirectDraw 호출로 (x,y) 픽셀에 col 색상으로 점을 찍는 예제
// pointer to DirectDraw objectLPDIRECTDRAW7 lpdd;// you use this function to access the surface memoryUCHAR video_buffer = NULL;// used to hold the DirectDraw surface descriptionDDSURFACEDESC2 ddsd;// primary surfaceLPDIRECTDRAWSURFACE7 lpddsprimary;// create DirectDraw objectDirectDrawCreateEx(NULL, (void **)&lpdd, IID_IDirectDraw7, NULL);// set cooperation levellpdd->SetCooperativeLevel(hwnd, DDSCL_ALLOWREBOOT | DDSCL_ALLOWMODEX | DDSCL_FULLSCREEN | DDSCL_EXCLUSIVE );
30
8-bit Example (2)8-bit Example (2)
// now set the display mode to 800 x 600 x 256
lpdd->SetDisplayMode(800,600,8,0,0);
// set up data structure to create the primary surface
ddsd.dwSize = sizeof(ddsd);
ddsd.dwFlags = DDSD_CAPS;
ddsd.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE;
// create the primary surface
lpdd->CreateSurface(&ddsd,&lpddsprimary,NULL);
// set up the surface description to lock the surface
// zero out the data structure and set its size
memset(&ddsd,0,sizeof(ddsd));
ddsd.dwSize = sizeof(ddsd);
31
8-bit Example (3)8-bit Example (3)
// lock the primary surface
lpddsprimary->Lock(NULL,&ddsd,
DDLOCK_SURFACEMEMORYPTR | DDLOCK_WAIT,NULL);
// get video pointer
video_buffer = (UCHAR *)ddsd.lpSurface;
//.. use video pointer to write to memory
// notice the use of lPitch (linear pitch)
video_buffer[x + y*ddsd.lPitch] = col;
// unlock the surface
lpddsprimary->Unlock(NULL);
32
PROG9_2.CPPPROG9_2.CPP
33
16bit Mode16bit Mode
• 1.5.5.5 형식– alpha 1 bit– red, green, blue 각각 5 bits
• 5.6.5 형식 – red 5 bits– green 6 bits ( 사람의 눈은 green 에 가장 민감 )– blue 5 bits
• 일반적으로 90% 이상의 video card 들은 5.6.5 형식을 사용한다 .
34
RGB Mode Macro (1)RGB Mode Macro (1)
// 5.5.5 format
#define _RGB16BIT(r,g,b) ((b%32)+((g%32)<<5)+((r%32)<<10))
example)
UCHAR red = 0x08 // 0000 1000
UCHAR green = 0x05 // 0000 0101
UCHAR blue = 0x1b // 0001 1011
Result = _RGB16BIT(red,green,blue)– (blue % 32) = 0001 1011
– (green % 32) << 5 = (0000 0101) << 5 = 1010 0000
– (red % 32) << 10 = (0001 1000) << 10 = 0110 0000 0000 0000
Result = 0110 0000 1011 1011 = 0 (11000) (00101) (11011)
35
RGB Mode Macro (2)RGB Mode Macro (2)
// this builds a 16 bit color value in 1.5.5.5 format (1-bit alpha mode)
#define _RGB16BIT555(r,g,b) ((b & 31) + ((g & 31) << 5) + ((r & 31) << 10))
example)
UCHAR red = 0x08 // 0000 1000
UCHAR green = 0x05 // 0000 0101
UCHAR blue = 0x1b // 0001 1011
Result = _RGB16BIT555(red,green,blue)– (blue & 31) = (0001 1011) & (0001 1111) = 0001 1011
– (green & 31) << 5 = (0000 0101) << 5 = 1010 0000
– (red & 31) << 10 = (0001 1000) << 10 = 0110 0000 0000 0000
Result = 0110 0000 1011 1011 = 0 (11000) (00101) (11011)
36
RGB Mode Macro (3)RGB Mode Macro (3)
// this builds a 16 bit color value in 5.6.5 format (green dominate mode)
#define _RGB16BIT565(r,g,b) ((b & 31) + ((g & 63) << 5) + ((r & 31) << 11))
37
16bit Mode16bit Mode 로 그리기로 그리기• 640x480x16 모드에서 (x, y) 위치에 (r, g, b) 색상으로 그리는 예제
memset(&ddsd,0,sizeof(ddsd));ddsd.dwSize = sizeof(ddsd);// lock the primary surfacelpddsprimary->Lock(NULL,&ddsd, DDLOCK_SURFACEMEMORYPTR | DDLOCK_WAIT,NULL);// get video pointervideo_buffer = (USHORT *)ddsd.lpSurface;// use video pointer to write to memory..// notice the use of lPitch (linear pitch) and the division by 2 (>>1);// this is needed to keep the addressing correct because you’re using USHO
RT// pointers and lPitch is always in bytesvideo_buffer[x + (y*ddsd.lPitch >> 1)]= (USHORT)_RGB16BIT565(r,g,b);// unlock the surfacelpddsprimary->Unlock(NULL);
38
Why lPitch >> 1Why lPitch >> 1
// pointers and lPitch is always in bytes
video_buffer[x + (y*ddsd.lPitch >> 1)]=
(USHORT)_RGB16BIT565(r,g,b);
• USHORT 를 사용할 때 모든 포인터 연산은 16 비트로 이루어지지만 , lPitch 는 항상 바이트로 표현되기 때문이다 .
39
DEMO: PROG9_3.CPPDEMO: PROG9_3.CPP
• PROG9_2_16.cpp 와 다른 점은 무엇인가 ?
40
2424 비트나 비트나 3232 비트 표면 비트 표면
#define _RGB24BIT(a,r,g,b) ((b) + ((g) << 8) + ((r) << 16) )
24bit 는 32bit 중 최상위 8bit 가 사용되지 않을 뿐이다 .
따라서 bpp 를 32 로 하는 것이 좋다 .
41
24, 32bit 24, 32bit 이용 이용 (1)(1)
• In Game_Init()if (lpdd->SetDisplayMode(SCREEN_WIDTH,
SCREEN_HEIGHT,32,0,0)!=DD_OK) return(0);
42
24, 32bit 24, 32bit 이용 이용 (2)(2)
• Game_Main()
UINT *video_buffer = NULL;
…
video_buffer = (UINT *)ddsd.lpSurface;
int words_per_line = (ddsd.lPitch >> 2);
UCHAR red = rand()%256;
UCHAR green = rand()%256;
UCHAR blue = rand()%256;
video_buffer[x + (y*words_per_line)] = _RGB24BIT(red,green,blue);
43
보조표면보조표면 (Secondary Surface) (Secondary Surface)
• 보조 표면 ( 또는 후면버퍼 ) 의 사용– 부드러운 애니메이션
– 1. 주표면을 생성하고 , 주표면으로부터 하나의 보조표면을 생성한다 .
– 2. 주표면이 보여지는 동안 보조표면에 그린다 .– 3. 순간적으로 표면을 바꾸어서 (switch or flip), 보조표면이
주표면이 되게 하여 , ( 그 반대로도 마찬가지 ) 부드러운 애니메이션을 만든다 .
44
Page Flipping Page Flipping
45
보조표면의 생성 보조표면의 생성 (1)(1)
// DirectDraw surface descriptionDDSURFACEDESC2 ddsd;// device capabilities structure, used to query for// secondary backbuffer, among other thingsDDSCAPS2 ddscaps;LPDIRECTDRAWSURFACE7 lpddsprimary, // primary surface lpddssecondary; // secondary backbuffer surface// prepare to create primary surface with one backbuffermemset((void *)&ddsd,0,sizeof(ddsd));ddsd.dwSize = sizeof(ddsd); // DDSURFACEDESC would work, too// set the flags to validate both the capabilities// field and the backbuffer count fieldddsd.dwFlags = DDSD_CAPS | DDSD_BACKBUFFERCOUNT;// you need to let dd know that you want a complex flippable surface
structure;
46
보조표면의 생성 보조표면의 생성 (2)(2)
// 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 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);
47
주표면과 부표면주표면과 부표면
48
Rendering BackbufferRendering Backbuffer
// used to access secondary video buffer
UCHAR *video_buffer;
// lock the secondary surface
lpddsback->Lock(NULL,&ddsd,
DDLOCK_SURFACEMEMORYPTR | DDLOCK_WAIT,NULL);
// draw on the surface: ddsd.lpSurface and
// ddsd.lPitch are valid as before
video_buffer = (UCHAR *)ddsd.lpSurface;
// unlock the surface
lpddsback->Unlock(NULL);
49
FlippingFlipping
HRESULT Flip(
LPDIRECTDRAWSURFACE7 lpDDSurfaceOverride, // always NULL
DWORD dwFlags); // always DDFLIP_WAIT
// flip the primary and secondary surfaces
while(lpddsprimary->Flip(NULL, DDFLIP_WAIT)!=DD_OK);
50
Flipping Flipping 전후전후
51
오프스크린 표면오프스크린 표면 (off-screen surface) (off-screen surface)
• 시스템 메모리나 VRAM 에 모두 존재할 수 있음• 주표면과 같은 색상깊이와 속성을 가지는 비트맵 • 스프라이트
– 간단히 말해서 비디오 게임 화면에서 움직이는 작은 물체를 뜻한다 . 대부분의 경우 , 스프라이트는 비트맵일 뿐
– 애플 II 프로그래머들에 의해 사용된 용어
52
VRAMVRAM 에 오프스크린 표면 생성에 오프스크린 표면 생성
// .. assume DirectDraw has been set up and so onDDSURFACEDESC2 ddsd; // a DirectDraw surface descriptorLPDIRECTDRAWSURFACE7 lpwork; // the working surface// set the size parameter as alwaysmemset(&ddsd,0,sizeof(ddsd));ddsd.dwSize = sizeof(ddsd);// set the flags; very important// remember that you must set the flags of the fields that will be validddsd.dwFlags = DDSD_CAPS | DDSD_WIDTH | DDSD_HEIGHT;// set dimensions of the new surfaceddsd.dwWidth = width;ddsd.dwHeight = height;// what kind of offscreen surface, system memory, or VRAM// default is VRAMddsd.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN;// now create the surface and check for errorif (lpdd->CreateSurface(&ddsd,&lpwork,NULL)!=DD_OK){ /* error */ }
53
시스템 메모리에 시스템 메모리에
// set flags for an offscreen plain system memory surface
ddsd.ddsCaps.dwCaps =
DDSCAPS_OFFSCREENPLAIN | DDSCAPS_SYSTEMMEMORY;
// now create the surface and check for error
if (lpdd->CreateSurface(&ddsd,&lpwork,NULL)!=DD_OK)
{ /* error */ }
54
팔레트…팔레트…
• 생략 .