수안이의 컴퓨터 연구실

  • Mainpage
  • About Me
  • Tags
  • Metapage
  • Notice
  • Location
  • Keywords
  • Guestbook
  • Admin
  • Write an Article
  • Total | 1694905
  • Today | 650
  • Yesterday | 606

Programming/OpenGL / DirectX2007/04/05 09:37

Direct X (Direct Draw2)

원본 : http://www.sarangnamu.net/basic/basic_v ··· ory%3D33

게임 루프 코딩

기본 프로그램에 「게임 루프」를 추가합니다.
게임은 기본적으로 「반영구인 루프(?)」로 그 처리를 실행하는 것이 보편화 되어 있습니다.
위와 같이 여러 가지 처리를 루프 안에서 실시합니다.
DirectX 프로그램의 경우는 그것을 동작시키는 기기마다 성능이 다른 PC로 동작하므로
어떤 PC나 같은 스피드로 루프 하도록 해야 합니다.

PC에 따라서 캐릭터가 빨리 움직이고 적의 움직임도 빨라져 게임을 할 수 없게
되는 현상이 나타납니다.
반대로 늦은 PC라면···늦은 게임이 됩니다.
그러한 기종간의 차이를 가능한 한 억제하는 것은 당연히 필요합니다.

60분의 1 루프
「60분의 1」이라고 하는 루프가 게임에서는 자주 사용되고 있으므로 여기에서도 그 스피드로 루프 하도록 합니다.
「60분의 1」이란 60분의 1초···1초는 「1000 밀리 세컨드」이므로 「16.66666 밀리 세컨드」라고 하는 극단의 간격으로 루프 한다는 의미입니다.
(1초간에 60회 루프 하는 60회의 화면이 묘화 된다는 의미)
컴퓨터는 굉장히 고속으로 계산하므로 다음 루프 처리까지 시간 「16.66666 밀리 세컨드」의 사이에 여러 가지 일들을 처리할 수 있습니다.


프로그램

그럼 그 루프는 어떻게 프로그램 하는 것일까?
이것에는 「정밀도가 높은 내부 시계」를 사용합니다.
내부 시계의 시간을 취득할 수 있는 함수가 있으므로 간단한 처리입니다.

void     loop(void)
{
   if(timeGetTime() <prev_time) prev_time = timeGetTime();
   double t = fabs(timeGetTime() - prev_time);
   if(t >= MSPF)
   {
       do
       {
           t-=MSPF;
           prev_time+=MSPF;
           //처리를 기입한다.
       }
       while(t>=MSPF);
   }
}

비고
-prev_time
-MSPF 매크로입니다.「16.66666」의 값이 설정되어 있습니다.
우선 처리의 시작에서 「timeGetTime 함수」를 사용합니다.
이것은 PC 기동부터 경과시간을 상당히 정밀도로 취득할 수 있는 함수입니다(밀리 세컨드 단위)

if(timeGetTime() < prev_time)prev_time = timeGetTime();

「timeGetTime 함수」로 기동부터의 경과시간을 취득해 「prev_time 변수」와 비교합니다.
(prev_time에는 전회의 루프 시작 시간이 보관됩니다.)
위의 처리는 초기화입니다.
기본적으로 「prev_time 변수」의 값이 「timeGetTime 함수」로 취득하는 경과시간보다 빠를 수는 없으므로. . .
「prev_time 변수」값의 격납 한계가 되면 자리수 넘침이 발생해 값이 예기치 않은 형태가 되어 끝내므로.
그렇게 되었을 경우에 「prev_time」의 값을 수정합니다.

double t = fabs(timeGetTime() - prev_time);

변수 t에 「현재 시각(기동부터 경과시간)」과「전회의 루프 시간」을 뺄셈을 합니다.
이것으로 현재···전의 루프부터 얼마나 시간이 경과했는지 알 수 있습니다.

fabs 함수는 소수점 값의 절대 값을 요구하는 함수
위에서 경과시간을 알 수 있었으므로 다음의 if문으로 분기합니다.

if(t>=MSPF)
{

}

MSPF에는 1회의 루프로 주어지는 최저의 처리 시간이 매크로에 설정되어 있습니다.
그것과 경과시간을 비교함으로 게임의 처리를 실행하는지를 판단합니다.

「t」가 「MSPF」보다 작은 경우는 처리 시간이 「남아 있다」 것으로 처리를 벗어 납니다.
「MSPF」보다 「t」가 위라면 처리 시간을 지나고 있으므로 게임 처리인
{}의 처리를 실행합니다.


속도가 느린 머신의 처리

느린 머신에서도 가능한 한 같은 처리를 실시하기 위해서 「do while」를 사용한 처리를 합니다.
여기서 느린 머신은 반복 처리를 합니다.

빠른 머신으로 실행했을 경우····캐릭터는 1도트씩 움직이겠지만
늦은 머신의 경우, 여기의 처리로 1도트이상씩 움직입니다.
(그러나 이동에 걸리는 시간은 거의 같게 됩니다.)

do
{
   t-=MSPF;
   prev_time+=MSPF;
   //묘화 처리외(충돌 판정등)의 처리를 기술
}
while(t>=MSPF);

위의 루프의 회수는 「t」의 값에 의해 결정됩니다.
늦은 머신의 경우는 「t」의 값이 커지므로 그 만큼, 보다 많이 여기서 처리해야 합니다.
(빠른 머신의 경우는 여기서 여러번 처리할 필요는 없어진다)

이 처리를 실행하는 위치

while(GetMessage(&msg, (HWND) NULL, 0,0))
{
   TranslateMessage(&msg);
   DispatchMessage(&msg);
}

현재 위와 같이 되어 있는 메세지 함수를 부르는 WHILE문을 이하와 같이 합니다.
while(TRUE)
{
   if(PeekMessage(&msg, 0,0,0, PM_REMOVE))
   {
       if(msg.message==WM_QUIT) break;
       TranslateMessage(&msg);
       DispatchMessage(&msg);
   }
   else
       loop();
}

「PeekMessage」는 아이돌 루프를 가능하게 하는 함수입니다
(헬프에는 상세하게 나와 있지 않지만, 사용예는 실려 있습니다)

첨가
timeGetTime 함수를 사용하는데 「winmm.lib」를 링크해야 합니다.
「ddraw.lib」를 링크했을 때와 같이 설정의 링크에 이것을 추가합니다.
또, fabs 함수를 사용하기 위해서는 「math.h」를 처음에 인클루드 해야 합니다.

//////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////

이미지의 묘화

게임에서는 이미지의 표시가 필수입니다.
이번은 기본적인 이미지의 묘화를 합니다.
「프라이머리서페이스」 「백 버퍼」를 생성 되어 있어야만 합니다.

이미지를 묘화 하려면 우선 이미지와 같은 사이즈의 서페이스를 새로 만들어
그 서페이스를 「백 버퍼」로 전송 하는 것으로 시작됩니다.

위와 같은 흐름으로 묘화를 합니다.
그림중의 「FLIP(플립)」은 백 버퍼와 프라이머리 서페이스와 교체함으로
화면에 백 버퍼의 내용이 표시되고 묘화가 반영됩니다.
플립에 의해 프라이머리 서페이스는 백 버퍼가 됩니다.
백 버퍼는 프라이머리 서페이스가 됩니다.

이미지와 같은 사이즈의 서페이스를 생성한다

서페이스의 생성입니다.
우선 이미지 로드용(이하:스프라이트) 서페이스의 포인터를 정의해야 합니다.
백 버퍼나 프라이머리 서페이스등 모두 같도록 합니다.

LPDIRECTDRAWSURFACE sprite=NULL;

「LPDIRECTDRAWSURFACE」로 포인터를 정의합니다.
샘플에서는 「global.h」에서 정의하고 있습니다.

서페이스를 만드는 함수
샘플에서는 이 처리를 「loadbmp 함수」에서 하고 있습니다.
이 함수는 인수로 서페이스를 만들고 싶은 BMP 이미지의 파일명을 건네주면
그 서페이스를 생성합니다.
이미지는 워크 스페이스가 있는 폴더에 넣어 주세요

처리의 흐름
1.서페이스를 만들고 싶은 이미지의 핸들을 취득한다
2.이미지 정보를 취득(이미지의 사이즈등을 취득)
3.이미지 정보에 따라 빈 서페이스를 생성
4.윈도우와 호환의 디바이스 콘텍스트를 취득
5.디바이스 콘텍스트에 이미지 핸들을 연결한다.
6.서페이스에 디바이스 콘텍스트의 정보(이미지)를 전송
7.핸들등의 해방 처리
8.투과 칼라 키의 설정

위의 흐름으로 이미지의 서페이스 생성은 처리됩니다.

1.이미지의 핸들 취득
WINDOWS 프로그램에서 클라이언트 영역에 이미지를 표시할 때에 핸들을 취득했습니다.
그 때와 같이 이미지의 핸들을 취득합니다.

「LoadImage 함수」로 핸들을 취득하는 것이 가능합니다

2.이미지 정보를 얻는다
여기서 필요한 이미지의 정보는 이미지의 가로, 세로의 크기입니다.
이 정보를 얻을 수가 있으면 어떠한 방법도 OK입니다.
여기서는 「GetObject 함수」를 사용 이미지의 정보를 취득합니다.
샘플에서는 「BITMAP 구조체 bm」에 이미지의 정보가 격납됩니다.

3.이미지 사이즈의 서페이스를 메모리에 만든다
샘플에서는 「create_surface 함수」를 불러 서페이스를 생성하고 있습니다.
(create_surface는 사용자 함수입니다)
create_surface 함수의 처리는 init_surface 함수에서 실행하는 「프라이머리 서페이스」의 생성과 거의 같습니다.

LPDIRECTDRAWSURFACE7    surface;
DDSURFACEDESC2            ddsd; //0으로 초기화

ZeroMemory(&ddsd, sizeof(ddsd));         //구조체의 사이즈를 설정
ddsd.dwSize=sizeof(ddsd) ;

//ddsCaps, dwWIdth, dwHeight를 유효하게 한다
ddsd.dwFlags=DDSD_CAPS|DDSD_HEIGHT|DDSD_WIDTH;     //오프스크린서페이스
ddsd.ddsCaps.dwCaps=caps;     //서페이스의 사이즈 설정
ddsd.dwWidth=width;
ddsd.dwHeight=height;
if(dd->CreateSurface(&ddsd, &surface, NULL)!=DD_OK)
   return NULL;

프라이머리서페이스 생성의 처리와 다른 점은 진한 문자의 부분입니다.
「ddsd 구조체(어떤 서페이스로 할까의 설정하는 구조체)」에 서페이스의 성질
를 나타내는 플래그를 건네주는 멤버

「ddsd.dwFlags」에는 「DDSD_CAPS | DDSD_HEIGHT | DDSD_WIDTH」의 3개의 플래그를 건네받고 있습니다.
「DDSD_HEIGHT」 「DDSD_WIDTH」의 플래그를 건네주면 서페이스의 사이즈 지정이 가능하게 됩니다.
ddsd.dwWidth 멤버와 ddsd.dwHeight 멤버가 사용 가능하게 됩니다
ddsd.dwWidth=width;
ddsd.dwHeight=height;
인수로 건네받은 이미지의 사이즈를「ddsd 구조체」에 건네줍니다.
이것으로 서페이스의 설정을 완료했으므로 「CreateSurface」를 사용해서 서페이스를 생성합니다.

메모리에는 위와 같이 이미지(스프라이트)의 서페이스가 생성되고 이것으로 이미지 묘화의 준비되었습니다.

4.디바이스 콘텍스트를 취득

이제 메모리에 이미지와 같은 사이즈의 서페이스는 생성되었지만 그 안에는 아직 이미지 데이터가 격납되어 있지 않습니다.
아직 비어있는 서페이스입니다.
거기에 이미지 데이터를 격납하는 처리를 합니다.

//현재의 화면 모드와 호환성이 있는 메모리디바이스콘텍스트를 작성.

HDC hdcbmp;

if(!(hdcbmp = CreateCompatibleDC(NULL)))
{
   surface->Release();
   return NULL;
}

위에서 디바이스 콘텍스트를 취득하는 작업을 하고 있습니다.
디바이스 콘텍스트란 묘화 관련 설정하도록 하는 것입니다.
「CreateCompatibleDC(NULL)」로 지정한 디바이스(윈도우, 이미지)같은 성질의
디바이스 콘텍스트를 작성할 수 있습니다.

작성할 수 없는 경우는 프로그램 종료
작성한 「디바이스 콘텍스트」와「서페이스에 묘화하고 싶은 이미지」를 연관 시킵니다.
SelectObject(hdcbmp, hbm);

6.서페이스에 디바이스 콘텍스트의 정보(이미지)를 전송
여기서 서페이스에 이미지 데이터를 전송 해서 「표면=이미지」라고 하는 상태로 합니다.

HDC     hdc;
if(surface->GetDC(&hdc) ==DD_OK)
{
   BitBlt(hdc, 0,0, bm.bmWidth, bm.bmHeight, hdcbmp, 0,0, SRCCOPY);
       surface->ReleaseDC(hdc);
}

위의 처리를 보면 서페이스의 디바이스 콘텍스트를 취득해서 「BitBlt 함수」를 사용해서 이미지 데이터를 서페이스로 전송 하고 있습니다.
전송을 종료하면 「디바이스 콘텍스트」를 해방하고 있습니다.
서페이스의 디바이스 콘텍스트는 「surface 오브젝트」의 「ReleaseDC」를 사용해서 해방해야 합니다.

이것으로 서페이스에는 이미지의 정보가 격납되었습니다.
소스에서는 다음으로 투과 키(스프라이트로서 묘화 할 때의 투과색설정)의 처리를
가고 있습니다.(마스크컬러 설정)

보충

서페이스가 증가하면 프로그램을 종료할 때 해방해야 하는 서페이스가
증가하겠지요.
해방 처리를 하고 있는 함수에 추가한 서페이스의 해방처리를 추가합시다.

스프라이트용의 서페이스는 메모리가 충족되는 한 얼마든지 생성할 수 있습니다.
필요한 수만큼 서페이스를 만들어도 괜찮을 것입니다.

(서페이스는 여러 개를 만들어서 따로 Road하는 것보다 하나에서 Road하는편이
속도가 더 빠릅니다)

DirectX DRAW 플립
전 회에서 서페이스를 만들고 이미지를 묘화 할 준비는 됐지만 아직 서페이스를 묘화하고 있지는 않습니다.
이제 서페이스의 내용을 화면에 표시합니다.
지금까지 프로그램은 위의 그림과 같이 메모리상에 서페이스는 존재하고 있었습니다.
하지만, 화면에는 표시되고 있지 않았습니다.
화면에 표시되고 있던 것은 비어있는 윈도우 클라이언트 영역입니다.

플립(Flip)
서페이스를 「플립」에 의해 화면에 묘화 합니다.
이 「플립」은 게임이 동작하는 동안 반복실행 됩니다.

묘화의 흐름
첫번째의「플립」을 하면「화면(디스플레이)」= 「프론트서페이스(프라이머리서페이스)」의 상태입니다.
화면에는 「프론트 서페이스」의 정보(이미지)가 표시됩니다.
묘화 순서는 「스프라이트 서페이스」에서 「백서페이스」로 묘화(전송) 합니다.
이것에 의해 「백서페이스」를 「플립」합니다.

「플립」을 하면 「프론트 서페이스」와「백서페이스」가 교체됩니다.
그러면 지금까지 화면에 반영되어 있지 않았던 「백서페이스」의 정보(이미지)가 표시됩니다.
프로그래머는 항상 「백서페이스」에 이미지를 넣어 「플립」하면 됩니다.

현재의 상태로 화면에는 서페이스의 정보가 표시되고 있으므로 이것으로 되었다고 할 수 있습니다.

「플립」을 실행하고 있는 부분····

loop 함수

void loop(void)
{
   if(timeGetTime()=MSPF)
   {
       do
       {
           t-=MSPF;
           prev_time+=MSPF;
           // 처리 기술
       }
       while(t>=MSPF);
       //flip 함수로 플립을 실행하고 있습니다.
       flip();
   }
}

loop 함수로 「플립」을 하고 있습니다(플립 함수를 호출하고 있습니다)
loop 함수는 60 FPS를 처리하고 있는 곳에서 「flip()」함수가 있는 위치는
1초에 (약)60회 실행되는 곳입니다.

MainSurface->Flip(NULL, DDFLIP_WAIT);

하지만 「flip 함수」로 처리되고 있는 내용은
이 1행만으로 서페이스를 화면에 표시되는 서페이스로 바꿔 넣기를 할 수 있습니다.

「프론트서페이스(화면에 보이는 서페이스)」를 타겟으로 「Flip 함수」로 실행할 수 있습니다.

//////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////

DirectX DRAW 이미지 묘화

스프라이트의 서페이스도 만들고 플립도 했습니다.
완전하게 이미지의 묘화가 가능한 상태가 되었으므로 이미지 묘화를 합니다.

묘화는 「백서페이스」에의 「전송」···그리고 실시합니다.
「백서페이스」에의 전송은 「플립」을 하기 전에 실시합니다.

void loop(void)
{
   if(timeGetTime()=MSPF)
   {
       do
       {
           t-=MSPF;
           prev_time+=MSPF;
           //계산 처리
       }
       while(t>=MSPF);

       //묘화 처리
       //flip 함수로 플립을 실행하고 있습니다.
       flip();
   }
}

그럼 추가된 것을 살펴 보도록 합시다.

void loop(void)
{
   if(timeGetTime()=MSPF)
   {
       do
       {
           t-=MSPF;
           prev_time+=MSPF;
           //계산 처리
       }
       while(t>=MSPF);
       //묘화 처리

       imagerender();

       //flip 함수로 플립을 실행하고 있습니다.
       flip();
   }
}

추가 된 것은 이「loop 함수」입니다.
진한 문자로 되어 있는 부분이 추가된 부분입니다.

「imagerender()」는 이미지를 묘화 하는 처리를 모은 함수로 임의로 제작 된 것입니다.
(함수의 내역은 밑에서 기술되고 있습니다.)

void imagerender(void)
{
   BackSurface->BltFast(150,150, sprite, NULL, DDBLTFAST_SRCCOLORKEY|DDBLTFAST_WAIT);
}

묘화를 실시하고 있는 부분입니다.
함수의 의미를 소개하면
여기서 사용되고 있는 「BltFast 함수」는 「이미지를 전송」하는 함수입니다.
전송이란 스프라이트 이미지를 백서페이스로 묘화하는 것입니다.

「BitBlt 함수」는 「확대 축소」가 가능하지만 「BltFast 함수」와 비교하면 스피드에서
조금 떨어지므로 보통 전송하는 경우는 「BltFast 함수」를 사용합니다.

(BitBlt 함수는 도큐멘트 참조)

HRESULT BltFast(
   DWORD dwX,            //묘화 하는 X좌표
   DWORD dwY,            //묘화 하는 Y좌표
   LPDIRECTDRAWSURFACE3 lpDDSrcSurface,//불러올 이미지가 들어 있는 서페이스
   LPRECT lpSrcRect,    //불러올 서페이스의 일부 전송을 실시할 때에 사용
   DWORD dwTrans        //전송 타입
);

(VC++헬프에서)
우선 첫째 제2 파라미터는 코멘트대로입니다.
전송할 이미지가 많은 경우는 스프라이트서페이스에서 백 버퍼로 전송 합니다.
백 버퍼의 어느 위치(좌표)를 묘화 할까?
그 값을 파라미터 1, 2로 지정합니다.
제3 파라미터는 호출할 서페이스의 포인터를 지정합니다.

샘플의 경우는 준비한 이미지(스프라이트)의 서페이스를 건네주고 있습니다.
이것에 의해 스프라이트 서페이스의 내용을 보낼 서페이스로 전송하는 처리를
합니다.

이 제3 파라미터를「백서페이스」에서도 할 수 있다고 생각합니다.

제4 파라미터는 필요에 따라서 사용합니다.
(여기를 NULL로 하면, 서페이스 전부를 전송이 한다!)

서페이스에는 게임에서 사용하는 이미지를 한꺼번에 모아서 생성할 것이 많습니다.
일반적으로 생성하는 서페이스에는 많은 이미지를 모아서 격납합니다.

(캐릭터라면 캐릭터등으로)

하나의 이미지에 1개씩 서페이스를 생성하는 것도 괜찮지만
메모리 공간이 낭비입니다.(적은 용량이지만. . )
가능한 한 효율적으로 프로그래밍을 하는 것이 역시 베스트라고 할 수 있습니다.

예로 많은 이미지를 준비해 둔 경우

제4 파라미터를 NULL로 해 두면 서페이스 전체가 전송 된다····
즉 지금 필요하지 않은 이미지까지도 묘화됩니다.

거기서 이 제4 파라미터에는 서페이스의 어느 부분을 전송하는 값을 건네줍니다.
여기서 건네주는 값은 「RECT 구조체」가 아니면 안됩니다.

RECT 구조체는 4개의 멤버

「좌측 X」 「좌측 Y」 「우측 X」 「우측 Y」라고 하는 느낌의 멤버를 가지고 있습니다.
이 멤버 각각 값을 건네주어 둡니다.
「BltFast 함수」를 실행하기 전에 RECT 구조체를 생성해 각 멤버에 값을 넣어 두면 OK 입니다.

제5 파라미터는 어떠한 전송을 할까?를 결정하는 플래그입니다.
플래그는 이하로부터 선택해 사용합니다.(헬프참조)

DDBLTFAST_DESTCOLORKEY

전송할 곳의 칼라 키를 사용하는 투과형 블록 전송을 지정한다.

이것을 건네주면 지정된 색을 투명하게 해서 묘화 한다
(전송할 곳에서 투명처리)

DDBLTFAST_NOCOLORKEY

투명이 아닌 보통의 복사 블록 전송을 지정한다.

투명하게 하지 않고 묘화

DDBLTFAST_SRCCOLORKEY

이것을 건네주면 지정된 색을 투명하게 해서 묘화 한다
(전송할 곳에서 투명처리로)

DDBLTFAST_WAIT

블록 전송이 바쁜 경우, DDERR_WASSTILLDRAWING에 반영되는 값을 바로 돌려주지 않고 기다린다.
그리고 블록 전송의 준비를 하던지 혹은 다른 에러가 발생하는 대로 즉시 돌아온다.

이것을 건네 두지 않으면 묘화 되지 않을 때가 있지만 묘화를 할 수 있을 때까지 멈춘다.
때문에 처리가 지연되는 경우도 있다
보충

BackSurface->BltFast

···는 왜 이렇게 되고 있는지?
위의 경우는 「백서페이스」로 전송이 됩니다.
여기를 스프라이트 서페이스로 하면 스프라이트 서페이스로 묘화하게 됩니다.
이것을 사용해 이미지 편집도 가능합니다.

//////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////

서페이스의 초기화


전면 painting에 해당하는 「render 함수」를 만들었습니다.
이 함수는 이전 「flip 함수」를 호출했던 부분에서 이것을 호출하고 있습니다.


void loop(void)
{
   if(timeGetTime()=MSPF)
   {
       do
       {
           t-=MSPF;
           prev_time+=MSPF;
           // 계산 처리
       }
       while(t>=MSPF);

       //묘화 처리
       render();
   }
}

호출하고 있는 것은 짙은 문자의 부분입니다.
그럼 「render 함수」의 처리는. . .

void render(void)
{
   DDBLTFX ddbltfx;
   ddbltfx.dwSize = sizeof(ddbltfx);
   ddbltfx.dwFillColor = 0;

   BackSurface->Blt(NULL, NULL, NULL,
   DDBLT_COLORFILL | DDBLT_WAIT, &ddbltfx);

   imagerender();    // 이미지의 전송

   flip();            // 플립

}

적색 문자의 부분은 전회의 프로그램으로 만든 묘화 처리와 플립입니다.
그럼 위로부터 설명···

   DDBLTFX ddbltfx;

   ddbltfx.dwSize        = sizeof(ddbltfx);
   ddbltfx.dwFillColor    = 0;

「DDBLTFX 구조체」를 정의합니다.

이것은 화면 효과 등을 표현할 때에 잘 사용하는 구조체입니다.
이 구조체에 실시하고 싶은 화면 효과의 값(플래그)을 리턴해서 「Blt 함수」를 실행하면 여러 가지 화면 효과를 만들 수 있습니다.

화면 효과에서 제일 간단한 것이 화면의 초기화입니다.
위에서는 「DDBLTFX 구조체」를 정의해 「dwSize」 「dwFillColor」라고 하는
멤버에 값을 건네줍니다.

「dwSize」는 구조체 사이즈를 입력합니다.
「dwFillColor」만이 포인트!
「dwFillColor」는 페인팅하는 색을 지정합니다.
샘플에서는 「0」을 건네주고 있지만 RBG값으로 건네줄 수도 있습니다.

흐름은 위의 그림과 같습니다.
결국 페인팅도 묘화 명령에 의해 실행됩니다(Blt 명령으로)
BackSurface->Blt(NULL, NULL, NULL, DDBLT_COLORFILL | DDBLT_WAIT, &ddbltfx);
위의 부분이 페인팅의 하나의 예입니다.

Blt 함수의 사양
제1 파라미터- 전송할 곳의 직사각형(RECT 구조체로)
제2 파라미터-전송해 올 곳의 서페이스
제3 파라미터-전송해 올 곳의 직사각형(RECT 구조체로)
제4 파라미터-플래그
제5 파라미터-DDBLTFX 구조체의 포인터
중요한 것은 플래그입니다. 그 외에는 모두 페인팅을 할 경우는 「NULL」로 설정합니다.

「DDBLT_COLORFILL」 플래그는 반드시 건네줍니다.
이것은 위에서 전부 페인팅 하는 색을 결정한 「DDBLTFX 구조체」를 사용하도록 됩니다.
「DDBLT_WAIT」는 그것이 끝날 때까지 처리를 멈춘다는 의미입니다.

여기까지의 처리로 백서페이스는 모두 black으로 painting됩니다.

////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////

서페이스의 일부 전송

이번은 스프라이트 서페이스의 일부를 백서페이스에 전송하는
작업을 실시합시다.

위의 그림과 같이 서페이스의 일부를 전송합니다.
이것을 할 때는 당연히 그 범위를 나타내는 변수를 사용합니다.
이 방법으로 캐릭터의 애니메이션을 표현하는 것이 용이하게 됩니다.

추가 된 부분으로

실제로 묘화를 실시하고 있는 「BltFast 함수」를 실행하고 있던 부분입니다.
전번의 프로그램에서는···묘화를 실시하고 있는 처리는 이하와 같이 되어있었습니다

//---------------------------------------
//imagerender 함수:백서페이스에 묘화

void imagerender(void)
{
   BackSurface->BltFast(150,150, sprite, NULL, DDBLTFAST_SRCCOLORKEY|DDBLTFAST_WAIT);
}
이 부분을 변경합니다.

「BltFast 함수」의 제4 파라미터가 전번에는 「NULL」이었습니다.
이 파라미터가 서페이스의 어느 부분을 전송 할지?

그 위치와 사이즈를 값(value)으로 해서 건네주는 파라미터로 여기에 「RECT 구조체」의 포인터로 파라미터에 건네줍니다.
그러면 미리 「RECT 구조체」에 값을 넣어 두어야 합니다.

우선은 「RECT 구조체」를 정의합니다.

void imagerender(void)
{
   RECT rect;
   BackSurface->BltFast(150,150, sprite,&rect, DDBLTFAST_SRCCOLORKEY|DDBLTFAST_WAIT);
}

RECT 구조체는 사각형의 시작 위치 좌표와 그 사이즈를 보관하는데 적합한 구조체입니다.
(헬프참조)
그런데, RECT 구조체를 정의한 후는, 4개의 멤버에 값을 셋팅해야 합니다.

샘플에서의 이미지는 「64×32」사이즈의 이미지입니다.
RECT 구조체를 사용해 이미지 모두를 전송 할 때는····

left  에는 「0」
top  에는 「0」
right 에는 「63」
under 에는 「31」

위의 같이 값을 입력합니다.

이미지 사이즈보다 1낮은 이유는 0부터 첵크하기 때문입니다.
(서페이스의 사이즈보다 큰 값으로 범위 지정하면 이미지가 표시되지 않기 때문에 주의)

위와 같이 표시할 때는···

left  에는 「0」
top  에는 「0」
right 에는 「31」
under 에는 「31」

「BltFast 함수」를 사용하기 전에 「RECT 구조체」를 위의 값으로 초기화하면,
RECT rect={0,0,63,31};

/////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////

스프라이트 이동

이미지 묘화가 되면 스프라이트의 이동도 간단합니다.
묘화 함수인 「BltFast」등의 파라미터를 프로그램에서 증가 또는 감소 시키면 스프라이트는 이동합니다.

묘화 될 때 좌표 값을 변경하면 스프라이트는 움직이고 있는 것처럼 보입니다.
샘플은 우측 방향으로 캐릭터를 이동시키는 프로그램입니다.

void imagerender(void)
{
   RECT rect={0,0,63,31};
   BackSurface->BltFast(xpos, ypos,sprite, &rect,
   DDBLTFAST_SRCCOLORKEY | DDBLTFAST_WAIT);
   xpos++;//캐릭터의 X좌표 값에 1 플러스
}

캐릭터를 묘화 하던 「imagerender 함수」가 변경되어 있습니다.
우선은 「BltFast」의 제1, 2 파라미터가 지금까지는 직접 값을 건네주었으나
여기를 변수로 해서 캐릭터의 좌표를 변경할 수 있도록 합니다.

「xpos」 「ypos」각각 글로벌로 정의되어 있습니다.(global.h에)
xpos++;//캐릭터의 X좌표 값에 1 플러스

이 처리는 캐릭터의 표시 좌표의 X 값인 「xpos」에 1을 플러스하고 있습니다.
그로 인해 다음에 묘화 될 때는 「X+1」된 위치에 묘화됩니다.

포인트
샘플에 대해

샘플에서는 캐릭터가 화면 끝에 도달하면 갑자기 사라집니다.
이것은 서페이스의 표시 영역을 넘어가 버렸기 때문입니다.

캐릭터의 1 도트가 서페이스사이즈를 초과했다

갑자기 사라지는 것을 막으려면 처리가 필요합니다.
DirectX에서는 이것을 간단하게 설정할 수 있습니다.

기울기 이동

만약 「오른쪽 위」의 기울기 이동을 실시하고 싶을 때는 「X값에 플러스」 「Y값에 마이너스」합니다.
그러면 오른쪽 위로 비스듬하게 진행됩니다.

기울기 이동이 종횡의 이동보다 약간 고속입니다.
이것은 1 도트(움직이는 요소)가 정방형으로 종횡의 길이는 동일한데 비교
기울기의 길이가 가로세로보다 약간 길기 때문에 그렇게 됩니다.

스스로 정방형을 그려 기울기 선과 가로세로의 길이를 비교해 보자
만약 기울기의 이동도 종횡과 같은 스피드로 이동시키고 싶을 때는 그것을 고려한 계산이
필요하게 됩니다.

/////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////

Animation

애니메이션이란?
캐릭터가 움직이고 있는 것처럼 보이게 하는 것입니다.

하나의 캐릭터에 여러 개의 이미지를 준비해서 그것을 차례로 묘화 함으로 움직이고 있는
것처럼 보이는 방법입니다.

RPG라면 캐릭터를 걷게 하는 애니메이션이 필요합니다.

위와 같이 캐릭터가 걷고 있는 이미지를 준비하고
A가 묘화 되면, 다음은 B를 묘화···그 다음으로 C를 묘화
차례차례 이미지를 교체해서 애니메이션 합니다.
샘플에서는 캐릭터가 걷는 애니메이션을 같은 위치에서 반복합니다.

캐릭터는 위의 이미지를 사용해서 묘화합니다.
위의 같은 흐름으로 진행됩니다.
플래그는 다음에 표시하는 이미지의 번호를 나타내게 됩니다.


void imagerender(void)
{
   static int flg=1;//캐릭터의 묘화 플래그입니다
   RECT rect={0,0,31,31};
   if(flg==1){         //flg=1일때
       flg=2;
       rect.left=0;
       rect.right=31;
   }
   else{
       if(flg==2){         //flg=2일때
           flg=3;
           rect.left=32;
           rect.right=63;
       }
       else{                 //flg=3일때
           flg=1;
           rect.left=64;
           rect.right=95;
       }
   }
   BackSurface->BltFast(xpos, ypos, sprite, &rect, DDBLTFAST_SRCCOLORKEY|DDBLTFAST_WAIT);
   //xpos++;//캐릭터의 X좌표값에 1 플러스
}

현재는 단순히 동작 됩니다.
샘플에서 변경된 것은 위의 「imagerender 함수」 뿐입니다.
여기서 이미지는 어떤 것을 표시할까? 를 판단해서 캐릭터를 묘화하고 있습니다.
(늦은 기종은 loop 함수로 작성하는 것이 좋다)

본래는 애니메이션은 사람이 인식할 수 있을 정도의 스피드와 끊어지는 느낌이 없도록
묘화되어야 합니다.

////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////

키이벤트의 발생

많은 게임은 플레이어로부터의 키이벤트에 따라 조작됩니다.

「↑키」를 누르면 캐릭터가 이동한다····같은 것
「↑키」를 눌렸을 때 캐릭터의 좌표를 변경시키면 플레이어의 뜻
에 따라 캐릭터가 움직이게 됩니다.

샘플에는 플레이어가 「↑」 「↓」 「←」 「→」키를 누르면
캐릭터가 이동하도록 되어 있습니다.

플레이어로부터의 키 입력····키보드 상태를 취득하는 함수는 몇 개 있습니다만
여기에는 「GetKeyState 함수」로 셋팅되어 있습니다.

이 함수는 파라미터로 지정된「가상 키코드」의 상태가 어떻게 되고 있는지를 리턴합니다.
「가상 키코드」란 키보드의 키에 할당된 인식 코드 같은 것입니다.
(「windows.h」에서 매크로 정의되어 있다)
A~Z까지의 키코드는 매크로되어 있지 않기 때문에 스스로 정의한다

ENTER 키의 경우는
GetKeyState(VK_RETURN)

위와 같이 하면 「ENTER 키(리턴 키)」가 눌려졌을 때에 함수의
리턴 값으로서 「제일 위 비트에 1」을 리턴합니다.
눌려지지 않았을 때는 「제일밑 비트에 1」이 리턴됩니다.

리턴 값은 「4바이트(16비트)」입니다.

「 제일위가 1」이라고 하는 것은 「10000000000000000」<키가 눌리고 있을 때
16 진수로 「8000」입니다.
이 값과「비트 단위의 AND 처리」를 합니다.
>

if(GetKeyState(VK_WNTER) &0x8000)

「비트 단위의 AND 처리」입니다.
「&연산자」라고 사용하는 것으로 간단하게 할 수 있습니다.

만약 플레이어가 ENTER 키를 누르고 있으면 「GetKeyState」에는
「10000000000000000(16진이라면 8000)」가 리턴됩니다.
그것과 「10000000000000000(16진이라면 8000)」는 AND로 「1」이라면
그 키가 눌리고 있다는 의미가 되는 것입니다.

덧붙여서 16진의 「8000」의 전에 있는 「0 x」는 뒤의 값이 16진임을 알려주는 연산자입니다

void KeyIvent(void)
{
   if( (GetKeyState(VK_UP) & 0x8000))        ypos-=4;//↑
   if( (GetKeyState(VK_DOWN) & 0x8000))    ypos+=4;//↓
   if( (GetKeyState(VK_RIGHT) & 0x8000))    xpos+=4;//→
   if( (GetKeyState(VK_LEFT) & 0x8000))    xpos-=4;//←
}

이 「KeyIvent 함수」는 새롭게 추가된 캐릭터 이동을 하는 함수입니다.
이 함수는 「loop 함수」의 계산 처리를 하고 있는 중에 호출되고 있습니다

처리의 내용은 지극히 단순해 눌린 방향으로 나아가게 하기 위해 캐릭터 좌표의 값
의 변화에 따른 처리입니다.

////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////

클립핑

여태까지 샘플에서 이미지가 화면 끝을 벗어나면 캐릭터가 화면에서
사라져 버립니다.
이것은「클립 영역」을 설정하면 사라지지 않게 할수 있습니다.

흐름은 거의 위의 그림과 같습니다.
우선 「DirectDrawCliper 오브젝트」를 생성해야 합니다.
이 오브젝트의 인터페이스의 포인터가 필요로 하는 포인터를 별도로 준비합니다.

「DirectDrawCliper 오브젝트」의 포인터는
「LPDIRECTDRAWCLIPPER」로 정의할 수 있습니다.
LPDIRECTDRAWCLIPPER LpClip;//클립 오브젝트 포인터

샘플에서는 「global.h」에서 정의하고 있습니다.
포인터를 준비했으면, 「DirectDrawCliper 오브젝트」를 생성합니다.
이 오브젝트는 「DRAW 오브젝트」의 「CreateClipper 메소드」로 생성할 수 있습니다.

샘플에서는 「BOOL CreateDraw(HWND hwnd)」에서 그 처리를 하고 있습니다.
「Draw 오브젝트」를 사용하므로 「Draw 오브젝트」가 생성된 후에 처리할
필요가 있습니다.

dd->CreateClipper(0, &LpClip, NULL);

제일 파라미터:사용하지 않으므로 항상 「0」을 건네줍니다.
제2 파라미터:인터페이스의 주소를 보관, 유지하는 포인터
제3 파라미터:확장 파라미터로 DirectX5에서는 「NULL」이외라면 에러가 발생됩니다

파라미터는 「제2 파라미터」만이 중요합니다.
여기에는 방금 전 정의한 오브젝트의 포인터를 건네줍니다.
이것으로 「DirectDrawCliper 오브젝트」가 생성됐습니다.

그럼 클립 오브젝트가 생성되었으므로 영역을 설정해 서페이스에 건네주는 작업을 합시다.
이 클립 기능을 사용하면 서페이스상에 복수의 클립 영역을 설정할 수 있으나,
여기에서는 640×480(묘화 영역전체)을 클립 영역으로 합시다.

만약 묘화 영역전체이외를 클립 영역으로서 설정하고 싶은 경우는 스스로 하시길 바랍니다.
이 클립 기능의 처리는 무거우므로 클립 오브젝트에 맡기는 것보다 스스로 클립 영역을 스스로 프로그램(지정)하는 것이 고속이기 때문입니다.

여기서 하나의 클립 오브젝트의 소개를 했으나 어디까지나 하나의 예일 뿐입니다.

if(LpClip->SetHWnd( 0, hwnd )!= DD_OK)
   return FALSE;

클립 오브젝트가 생성되면 바로 오브젝트의 「SetHWnd 메소드」를 사용합니다.
이 메소드를 사용하면 그 윈도우 핸들(hwnd)의 영역을 클립 영역으로
오브젝트에 등록해 줍니다.

제1 파라미터:항상 0입니다
제2 파라미터:윈도우 핸들을 건네줍니다.

만약 클립 영역을 임의의 위치로 하고 싶은 경우는 「setClipList 메소드」
에 영역의 사이즈를 건네줍니다.

그리고 마지막에·····

if(BackSurface->SetClipper(LpClip) !=DD_OK)
   return FALSE;//서페이스에 클립 셋팅

「SetClipper 메소드」를 사용 서페이스에 클립 영역을 설정합니다.
파라미터는 「클리퍼 오브젝트 인터페이스」의 포인터입니다.

백서페이스에 클립 영역을 세트 합니다
대상이 「백서페이스」라고 하는 것에 주의하십시오.

묘화 함수 「Blt 메소드」로 묘화를 실시하는 서페이스는 「백서페이스」이므로
「프라이머리 서페이스」에 클립 영역을 설정해도 의미가 없습니다.

보충
클립 기능은 「Blt 메소드」로 밖에 효과를 발휘하지 않기 때문에 캐릭터의 묘화를 하는「BltFast」에서 「Blt」로 변경되어 있습니다.

/////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////

확대, 축소 묘화

전송 메소드인 「Blt」를 사용하면 확대·축소 묘화가 간단합니다.
이것은 「Blt」의 파라미터만으로 할 수 있으므로 간단합니다.

HRESULT Blt(
   LPRECT lpDestRect,
   LPDIRECTDRAWSURFACE3 lpDDSrcSurface,
   LPRECT lpSrcRect,
   DWORD dwFlags,
   LPDDBLTFX lpDDBltFx
);

「Blt 메소드」의 파라미터는 위에 있는 대로 입니다.
확대 축소를 실시하는 파라미터는 제1 파라미터이므로 이 파라미터를 바꾸는 것으로 확대 축소가 가능하게 됩니다.

32×32 도트의 이미지의 경우

보통 묘화(크기대로)

제1 파라미터의 RECT 구조체의 값을····

RECT.LEFT=0;
RECT.TOP=0;
RECT.RIGHT=31;
RECT.BOTTOM=31;

32 도트는 0~31까지로 32 도트입니다

확대 묘화

제1 파라미터의 RECT 구조체의 값을····
RECT.LEFT=0;
RECT.TOP=0;
RECT.RIGHT=31보다 위의 값;
RECT.BOTTOM=31보다 위의 값;

축소 묘화

제1 파라미터의 RECT 구조체의 값을····

RECT.LEFT=0;
RECT.TOP=0;
RECT.RIGHT=31보다 아래의 값;
RECT.BOTTOM=31보다 아래의 값;

참고로 제1 파라미터를 「null」로 하면 화면 전체에 확대 묘화 됩니다.
제1 파라미터를 동적으로 변환시키면 조금씩 확대나 축소하는 것도 가능하게 됩니다.

///////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////

화면 효과

이번은 화면을 지정한 색으로 전부 페인트하는 처리를 실시합시다.
어드벤쳐 게임등에서 사용되는 「페이드아웃」입니다.

위의 같은 화면 효과를 보신적이 있을 것입니다.
검은 부분(전부 칠해진 부분)이 서서히 퍼져가 화면이 어둡게 되는
화면 효과입니다.
이 효과는「All Paint」를 셋팅하면 간단하게 가능합니다.

우선은 키 코드의 정의를 모두 합니다.

#define VK_A 0x41     //a키
#define VK_B 0x42     //b키
#define VK_C 0x43     //c키
#define VK_D 0x44     //d키
#define VK_E 0x45     //e키
#define VK_F 0x46     //f키
#define VK_G 0x47     //g키
#define VK_H 0x48     //h키
#define VK_I 0x49     //i키
#define VK_J 0x4A     //j키
#define VK_K 0x4B     //k키
#define VK_L 0x4C     //l키
#define VK_M 0x4D //m키
#define VK_N 0x4E     //n키
#define VK_O 0x4F     //o키
#define VK_P 0x50     //p키
#define VK_Q 0x51     //q키
#define VK_R 0x52     //r키
#define VK_S 0x53     //s키
#define VK_T 0x54     //t키
#define VK_U 0x55     //u키
#define VK_V 0x56     //v키
#define VK_W 0x57 //w키
#define VK_X 0x58     //x키
#define VK_Y 0x59     //y키
#define VK_Z 0x5A     //z키


ALL PAINTING 방법

「Blt 메소드」를 사용합니다.
「Blt 메소드」는 이미지 전송도 하지만, 구형을 전부 페인트하는 기능도 있습니다.

HRESULT Blt(

   LPRECT lpDestRect,
   //전송할 곳의 서페이스의 묘화 위치(RECT 구조체)

   LPDIRECTDRAWSURFACE3 lpDDSrcSurface,
   //전송해 올 곳의 서페이스

   LPRECT lpSrcRect,
   //전송해 올 곳의 서페이스의 전송 영역(RECT 구조체)

   DWORD dwFlags,        
   //전송 플래그

   LPDDBLTFX lpDDBltFx
   //플래그에 의해 이 파라미터를 사용한다

);

Blt 메소드의 파라미터는 위에 있는 대로 입니다.

(헬프참조)

ALL PAINT에서 중요한 것은 제4 파라미터와 제5 파라미터입니다.
플래그안에 「DDBLT_COLORFILL」라고 하는 플래그가 있습니다.
이것은 제5 파라미터로 건네주는 「DDBLTFX 구조체」에 격납된 「컬러」
를 사용해 전송할 곳의 서페이스를 All Paint 하는 플래그입니다.

이 플래그를 제4 파라미터로 설정함으로 「Blt 메소드」는 ALL PAINT 기능이 됩니다.
BackSurface->Blt(NULL, NULL, NULL, DDBLT_COLORFILL | DDBLT_WAIT, &ddbltfx);

위는 화면 전체를 ALL PAINTING할 때의 「Blt 메소드」사용 예입니다.

DDBLTFX 구조체

Paint의 컬러를 격납만을 하는 구조체가 아니고 여러 가지 용도에 사용되는 구조체입니다.
(헬프참조)

여기서 중요한 멤버는 「dwFillColor」입니다.
이 멤버에 ALL PAINTING하는 칼라값을 격납해 Blt 메소드에 건네줍니다.

사용예

DDBLTFX         ddbltfx;
ddbltfx.dwSize=sizeof(ddbltfx);
ddbltfx.dwFillColor=0;
BackSurface->Blt(NULL, NULL, NULL, DDBLT_COLORFILL | DDBLT_WAIT, &ddbltfx);

위는 화면 전체에 All Painting할 때의 구체적인 예입니다.
이 처리는 지난 번에서는 서페이스 초기화로 사용되고 있었습니다.

(render 함수로 서페이스를 BLACK으로 All Painting해서 쓰레기이미지가 표시되지 않게 하는 처리입니다)

그런 다음 서페이스의 어느 부분을 All Painting할까?그 값을 RECT 구조체에 격납해
Blt 로 페인트합니다.

/////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////

문자 묘화
여기서는 화면에 캐릭터 라인을 묘화를 합니다.

위와 같이 캐릭터 라인의 묘화가 가능합니다.
하나는 문자의 배경이 투과 하고 있지 않는 캐릭터 라인····

또 하나는 투과 해 묘화 할 수 있는 캐릭터 라인입니다.
투과 할 수 있는 캐릭터 라인이 게임에서 보다 많이 사용되고 있습니다.

그러나 투과되는 쪽의 처리가 조금 복잡합니다.

추가된 부분은 「void render(void)」부분입니다.
투과 하지 않는 묘화

HDC     hdc;
BackSurface->GetDC(&hdc);
//백 버퍼의 디바이스 콘텍스트 취득
SetBkColor(hdc, 0);
//디바이스 콘텍스트로 지정색을 셋팅
SetTextColor(hdc, RGB(255,255,255));
//문자의 색을 셋팅
TextOut(hdc, 300,280," 테스트~", 8);
//캐릭터 라인 표시
BackSurface->ReleaseDC(hdc);
//디바이스 콘텍스트 해방
처리는 위와 같이 됩니다.

HDC     hdc;
디바이스 콘텍스트(이하:DC)가 필요하게 되므로 여기서 정의합니다.

BackSurface->GetDC(&hdc);
묘화 대상인 서페이스····백 버퍼의 DC를 얻으려면, 백 버퍼의 「GetDC 메소드」를 사용합니다.

파라미터는 DC에의 주소입니다.
SetBkColor(hdc, 0);
이 함수는 지정한 DC의 배경을 All Paint합니다.

제1 파라미터가 배경에 All Paint하고 싶은 DC.
제2 파라미터가 All Paint하는 컬러입니다.

SetTextColor(hdc, RGB(255,255,255));
지정한 DC의 텍스트 컬러를 변경합니다.
파라미터는 「SetBkColor」와 같습니다.

TextOut(hdc, 300,280," 테스트~", 8);
DC가 가리키는 메모리 영역에 묘화를 실시합니다.

제1 파라미터:디바이스 콘텍스트
제2 파라미터:묘화할 곳 X좌표
제3 파라미터:묘화할 곳 Y좌표
제4 파라미터:묘화할 캐릭터 라인의 포인터
제5 파라미터:묘화할 문자수

BackSurface->ReleaseDC(hdc);
여기서 DC는 불필요하게 되므로 해방 처리를 합니다.
해방도 서페이스의 메소드를 사용합니다.
「ReleaseDC」가 해방의 메소드입니다.
파라미터는 DC입니다

이것으로 문자를 묘화 할 수 있었습니다.
그러나 이것은 「투과 하지 않는다」 것으로 용도가 꽤 한정되어 있습니다.
다음으로 투과 되는 캐릭터 라인 묘화를 실시합니다(스프라이트).

투과 하는 묘화(스프라이트 묘화)
무엇인가 어려울 것 같은 투과되는 캐릭터 라인의 묘화입니다만 API 함수로 가능합니다.
게다가 투과 하지 않는 캐릭터 라인 묘화와 그다지 다른점은 없습니다.

HDC     Fhdc;
char str[]={"스프라이트효과 테스트!!"};
BackSurface->GetDC(&Fhdc);
//백 버퍼의 디바이스 콘텍스트 취득
SetBkMode(Fhdc, TRANSPARENT);
//디바이스 콘텍스트로 지정색을 셋팅
SetTextColor(Fhdc, RGB(250,250,250));
//문자의 색을 셋팅
TextOut(Fhdc, 120,120, str, strlen(str));
//캐릭터 라인 표시
BackSurface->ReleaseDC(Fhdc);
//디바이스 콘텍스트 해방

중요한 추가점은 진한 문자로 되어있는 부분입니다.
투과 하지 않는 문자 묘화의 경우는 「SetBkColor 함수」였습니다.
이 함수는 배경색을 설정하는 함수입니다만,
이번 사용하는 「SetBkMode」는 파라미터에 배경을 투과하는 파라미터가 있습니다.

제2 파라미터의 「TRANSPARENT」가 그것입니다.
이것을 건네주고 묘화 할 때, 묘화할 곳의 배경을 남기면서 문자를 묘화하게 됩니다.
그 외의 변경은 그다지 주의하지 않으셔도 괜찮습니다.
캐릭터 라인을 변수로부터 읽고 있는 것과 문자수를 함수로 요구하고 있는 등···대수롭지 않은 것입니다.

어땠습니까?
캐릭터 라인의 묘화는 이해할 수 있었는지요?

그렇지만, Windows의 시스템 폰트는 게임에 맞지 않는다든가 안 어울린다고
생각하지 않습니까?

가능하다면 폰트를 스스로 만들도록 합시다. 이미지로서 폰트를 준비해 묘화 하면
휠씬 보기 좋을 것이라 생각합니다.

//////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////

칼라 키

칼라 키는 이미지에 있는 칼라를 무효로 해서 「스프라이트」를 가능하게 합니다.
(선택한 칼라가 투명처리 된다 = 스프라이트)

이 처리는 샘플에서 「loadbmp 함수」로 설정되어 있습니다.
여기서 그「칼라 키」에 대해 설명합니다.

칼라 키셋팅

칼라 키는 서페이스에 대해서 설정이 가능합니다.
샘플의 「loadbmp 함수」는 지정한 BMP 파일과 같은 사이즈의 서페이스를
생성해서····그 서페이스에 칼라 키를 셋팅하는 함수입니다.

DDSURFACEDESC2         ddsd;
memset(&ddsd, 0, sizeof(ddsd));
ddsd.dwSize = sizeof(ddsd);

//서페이스를 잠급니다

surface->Lock(NULL, &ddsd, DDLOCK_WAIT |
DDLOCK_SURFACEMEMORYPTR, NULL);

char     *p=(char *) ddsd.lpSurface;        
//좌상각의 칼라를 투과칼라로 합니다

DWORD transparent=*(DWORD *) p;

//서페이스의 록을 해제합니다
surface->Unlock(NULL);             // 투과칼라의 설정
DDCOLORKEY    ddck;
ddck.dwColorSpaceLowValue=transparent;
ddck.dwColorSpaceHighValue=transparent;
surface->SetColorKey(DDCKEY_SRCBLT, &ddck);

위는 「loadbmp 함수」의 칼라 키셋 처리의 행입니다.
「서페이스 직접 억세스」 방법으로 이미지의 좌상 1도트의 칼라를
칼라 키로서 셋팅하는 방법입니다.

「서페이스 직접 억세스」는 아직 설명하지 않았기 때문에 모르는 것이
대부분이겠지만 「서페이스」의 좌상 1 도트의 칼라정보를 취득하는 작업을 실시해서
(직접 억세스는 여러가지 일이 생긴다)
취득한 칼라정보를 「DDCOLORKEY 구조체」에 건네주어 서페이스에서
「SetColorKey 메소드」를 셋팅합니다.

이번은 「서페이스에 직접 억세스」에 의한 칼라 데이터 취득을 실시하지 않고
「DDCOLORKEY 구조체」에 직접, 투과 시키고 싶은 칼라를 지정하는 방법을 실시합니다.

「DDCOLORKEY 구조체」

이 구조체는 「dwColorSpaceLowValue」 「dwColorSpaceHighValue」의
2개의 멤버를 가지고 있습니다.
투과 하는 칼라의 범위를 이 멤버에 건네줍니다.

「256이하의 모드의 경우」는 투과 하고 싶은 범위의 「팔레트 넘버」를
멤버에 건네줍니다.

「그 이상의 모드의 경우」는 팔레트 넘버가 아니고 칼라의 범위를 건네줍니다.

이 경우 건네주는 칼라의 값은 이미지의 픽셀 포맷과 같은 형식이 아니면 안돼기 때문에
그것을 조사하려면 「서페이스의 직접 억세스」를 실시해야 합니다.

「DDCOLORKEY 구조체」에 뽑아 내고 싶은 칼라의 범위를 설정하고 칼라 키를 설정하고 싶은 서페이스의 「SetColorKey 메소드」에 다른 파라미터와 함께 건네줍니다.

HRESULT SetColorKey(
   DWORD dwFlags,
   LPDDCOLORKEY lpDDColorKey
);

메소드는 위에 있는 대로 입니다.
제1 파라미터는 칼라 키를 셋팅 할 때 플래그(어떻게 셋팅 할까)
제2 파라미터는 「DDCOLORKEY 구조체」의 주소입니다.

제1 파라미터에 건네주는 플래그
DDCKEY_COLORSPACE

구조체가 칼라 스페이스를 포함하고 있는 경우 셋팅 한다.
구조체가 단일의 칼라 키를 포함하고 있을 때는 셋팅해서는 안 된다.

DDCKEY_DESTBLT

블록 전송의 전송할 곳의 칼라 키로서 사용되는 칼라 키 혹은
전송할 곳의 칼라 스페이스에 구조체가 지정되어 있는 경우 셋팅 한다.

DDCKEY_DESTOVERLAY

오버레이 처리의 전송할 곳의 칼라 키로서 사용되는 칼라 키 혹은
전송할 곳의 칼라 스페이스에 구조체가 지정되어 있는 경우 셋팅 한다.

DDCKEY_SRCBLT

블록 전송의 전송해올 곳의 칼라 키로서 사용되는 칼라 키 혹은
전송할 곳의 칼라 스페이스에 구조체가 지정되어 있는 경우 셋팅 한다.

DDCKEY_SRCOVERLAY

오버레이 처리의 전송해올 곳의 칼라 키로서 사용되는 칼라 키 혹은
전송할 곳의 칼라 스페이스에 구조체가 지정되어 있는 경우 셋팅 한다.

플래그는 위의 종류등이 있습니다. 상황에 따라 선택하시길 바랍니다.
칼라 키를 유효하게 한다

서페이스에 셋팅한 칼라 키를 유효하게 하려면, 전송 함수
「Blt」나 「BltFasr」등의 전송 플래그를 변경해서 유효하게 합니다.

예를 들면 「Blt 메소드」····제5 파라미터는 플래그입니다.
칼라 키에 관한 플래그는...

DDBLT_ALPHAEDGEBLEND

칼라 키의 칼라를 집어내는 이미지의 edge의 알파 채널로서 DDBLTFX 구조체의
dwAlphaEdgeBlend 멤버를 사용한다.

DDBLT_KEYDEST

전송할 곳의 표면(서페이스)과 관련되는 칼라 키를 사용한다.

DDBLT_KEYSRC

전송해올 곳의 표면과 관련되는 칼라 키를 사용한다.

DDBLT_KEYDESTOVERRIDE

전송할 곳의 표면의 칼라 키로서 DDBLTFX 구조체의 dckDestColorkey 멤버를 사용한다.
지금까지의 프로그램들은 「이미지」의 서페이스에 칼라 키를 설정해 두고 있었으므로
백서페이스에 전송 할 때에 건네주는 플래그는 「DDBLT_KEYSRC」가 됩니다.

이것은 전송해올 곳인 「이미지 서페이스」의 칼라 키를 사용해 투과 처리를
실시하는 플래그입니다.

이것과 비슷한 플래그로 「DDBLT_KEYDEST」의 경우는 전송할 곳의 서페이스의 칼라 키
를 사용해서 투과 처리를 실시하는 것이 됩니다.

/////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////

감마 컨트롤

256칼라이상의 모드에서 「팔레트」의 개념이 없기 때문에
팔레트 데이터의 수정에 의한 화면 효과를 실시할 수가 없습니다.
그래서 256칼라이상의 모드에서는 「감마 컨트롤」이라 하는 것을 실시합니다.

「감마」란 칼라의「휘도」로 DirectDraw는 이 감마값을 R·G·B의 세가지요소를 하나 하나의 설정이 가능합니다.
R의 감마값을 올리면 적칼라가 강조됩니다.
감마값을 평균적으로 하면 흑백의 효과도 가능합니다.

또 감마 컨트롤을 사용하기 위해 「dxguid.lib」이 라이브러리를 링크해야 합니다.

샘플은 32비트 칼라로 동작합니다.
Z키를 누르면 적칼라 감마값을 내립니다. A키로 올립니다.
X키를 누르면 녹칼라 감마값을 내립니다. S키로 올립니다.
C키를 누르면 청칼라 감마값을 내립니다. D키로 올립니다.

GammaControl 오브젝트의 생성

감마값을 조정하려면 「IDirectDrawGammaControl 오브젝트」를 생성해야 합니다.
이 오브젝트는 「서페이스」의 「QueryInterface 메소드」로 생성할 수 있습니다.
참고서에는 대부분 오브젝트를 「프라이머리 서페이스」에서 생성하도록 하고 있습니다

IDirectDrawGammaControl 오브젝트 인터페이스의 포인터

이 포인터는 「LPDIRECTDRAWGAMMACONTROL」로 정의할 수 있습니다.
소스프로그램에서는 「grobal.h」에 이 포인터를 정의했습니다.

LPDIRECTDRAWGAMMACONTROL lpGamma;
//감마 컨트롤 오브젝트 포인터

인터페이스의 포인터를 정의하면 「프라이머리서페이스」의 「QuertInterface 메소드」
를 사용해서 오브젝트를 생성합니다.

오브젝트의 생성은 「CreateDraw 함수」안에서 처리하고 있습니다.
프라이머리 서페이스가 생성되어 있으므로 한번만 실행되는 장소라면 어디라도 괜찮습니다.

HRESULT QueryInterface(
   REFIID riid,
   LPVOID* obp
);

이 메소드는 「감마 컨트롤 오브젝트」를 생성하는 기능은 아니고
파라미터로 지정하는 오브젝트가「COM」을 서포트하고 있을까?를 첵크해 생성합니다.

「COM」가 무엇인가 신경이 쓰이겠지만
여기에서는 신경쓰지 않고 진행합니다.

「감마 컨트롤 오브젝트」를 생성하려면, 제1파라미터에「IID_DirectDrawGammaControl」
을 건네줍니다.

제2 파라미터에는 「오브젝트 인터페이스」의 주소를 보관하는 포인터를 건네줍니다.

QueryInterface 메소드

감마 컨트롤 오브젝트를 생성하기 위해 사용하는 이 메소드를 사용하지만,
감마 컨트롤 오브젝트를 생성만 하는 메소드는 아닙니다.

헬프에는 이렇게 적혀 있습니다.

DirectX 구축의 기본으로 되는 컴퍼넌트 오브젝트 모델 (COM)은 후방 호환성에 영향을 주는 일 없이
새로운 인터페이스로 새로운 기능을 추가할 수 있는 것으로 하고 있다.
이것으로 IDirectDraw 인터페이스는 IDirectDraw2 인터페이스에 의해 옮겨놓을 수 있다.
이 새로운 인터페이스를 얻으려면 다음의 C++ 의 예에 나타나듯이 IDirectDraw::QueryInterface메소드를 사용한다.
「감마컨트롤 인터페이스」도 위의 헬프에 적혀 있는데로 하위 호환을 유지하기 위해
「QueryInterface 메소드」를 사용해서 지정된 오브젝트가 새로운 것이라면
낡은 오브젝트보다도 우선시해서 사용하도록 한다·····하는 뜻입니다.

감마값의 변경

오브젝트도 생성했으므로 다음으로 감마값을 변경하면
화면의 칼라를 변화시킬 수가 있습니다.

감마값은 「DDGAMMARAMP 구조체」의 「red」 「green」 「blue」의 멤버에 감마값을
넣고 「IDirectDrawGammaControl 오브젝트」 「SetGammaRamp 메소드」에 파라미터
로 건네주기만 하면 됩니다.

감마값
감마값은 「0~65535의 65536」입니다.
칼라 정보는 「0~255의 256」으로 표현되고 있습니다.
칼라 정보 값이 「(RED) 46」이었던 경우의 감마값은 「(RED) 11776」이 됩니다.

감마값 = 칼라값×256

위의 식으로 감마값이 구해 집니다.
감마값이 「0」이 되면 「짙은black」····「65535」가 되면 「짙은white」가 됩니다.

Color의 변화
소스의 「빨강 강조 처리」의 흐름을 여기서 설명합니다.

「IDirectDrawGammaControl 오브젝트」에는 「SetGammaRamp 메소드」와
「GetGammaRamp 메소드」 두 개가 있습니다.

뒤의 「GetGammaRamp 메소드」는 현재의 감마값을 취득할 수 있는 메소드입니다.
이 메소드를 사용해 우선은 현재의 감마값을 취득합니다.

HRESULT GetGammaRamp(
   DWORD dwFlags,
   LPGAMMARAMP lpRampData
);

제1 파라미터:항상 0 입니다.(헬프참조)
제2 파라미터:DDGAMMARAMP 구조체의 포인터
제2 파라미터로 건네주는 「DDGAMMARAMP 구조체」의 멤버에 현재의 감마값이 격납됩니다.

typedef struct _DDGAMMARAMP {
   WORD red[256];
   WORD green[256];
   WORD blue[256];
} DDGAMMARAMP, FAR * LPDDGAMMARAMP;

위가 「DDGAMMARAMP 구조체」입니다.
이 「red」 「green」 「blue」의 3 멤버로 변경하고 싶은 감마값을 넣습니다.
각 칼라의 요소마다 「256개 배열」이 있으므로 우선 루프로 모든 배열 요소를
고쳐 써 보세요.

GetGammaRamp 메소드로 현재의 감마값을 취득하고 나서

적색을 강조한다
적색을 강조하는 경우는 「red 감마 배열」안의 값을 증가시킴으로 가능합니다.

DDGAMMARAMP Gamma;
lpGamma->GetGammaRamp(0, &Gamma);

for(int i=0;i<=255;i++){
   Gamma.red[i] = Gamma.red[i]+100;
}

「lpGamma」는 「IDirectDrawGammaControl 인터페이스」의 포인터

위의 식으로 RED의 감마값만을 100 강조할 수 있습니다.
변경을 했으므로 변경한 감마값을 다시 셋팅합니다.
이것에는 「SetGammaRamp 메소드」를 사용합니다.

HRESULT SetGammaRamp(
   DWORD dwFlags,
   LPGAMMARAMP lpRampData
);

제1 파라미터:플래그입니다.

dwFlags
Flag indicating if gamma calibration is desired.
Set this parameter DDSGR_CALIBRATE to request that the calibrator adjust the
gamma ramp according to the physical properties of the display, making the result
identical on all systems. If calibration is not needed, set this parameter to 0.

「DDSGR_CALIBRATE」든지 「0」을 건네줄 것이라고 생각됩니다.
「calibration」가 필요한 때는 「DDSGR_CALIBRATE」를 셋팅하고
필요 없을 때에 「0」을 건네준다 ·· 라고 보입니다.

「SetGammaRamp 메소드」가 실행되면 곧 바로 화면의 칼라는 변경됩니다.

참고

감마 컨트롤은 비디오 카드의 기능에 따라서 동작하기때문에
만약 비디오 카드가 감마 컨트롤에 대응하고 있지 않는 경우는 제대로 동작 하지 않습니다.

/////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////

"OpenGL / DirectX" 카테고리의 다른 글
  • Introduction to Direct 3D (0)2007/04/29
  • Direct X (Direct Draw3) (0)2007/04/05
  • Direct X (Direct Draw2) (0)2007/04/05
  • Direct X (Direct Draw) (0)2007/04/05
  • 얼굴인식의 구현과 유사도 판단-5 (0)2005/09/14
2007/04/05 09:37 2007/04/05 09:37
Posted by webdizen
No Trackback No Comment

Trackback URL : http://www.webdizen.net/blog/trackback/2785

Leave your greetings.

[로그인][오픈아이디란?]

«Prev  1 ... 464 465 466 467 468 469 470 471 472 ... 3009  Next»

RSS HanRSS
Blog Image
webdizen
이곳은 컴퓨터에 대해 연구하고, 공유하고, 소통하기 위한 연구실입니다. 개인적으로는 OLAP, Data Mining, Semantic Web, Data Modeling에 대해서 연구하고 있습니다.

Categories

전체 (3009)
Webdizen (141)
Life (6)
Diary (16)
Blog (9)
IDEA (2)
Travel (10)
Book (16)
Photo (7)
Movie (8)
Music (14)
Leisure Sports (10)
Funny (6)
Hardware (121)
Software (120)
Windows (5)
Unix & Linux (120)
Installation (5)
Kernel (10)
System (34)
Develop (22)
X-Window (0)
Applicaton (31)
Security (4)
Framework (2)
Hadoop (2)
Programming (804)
Algorithm & Data Structure (1)
Assembly (38)
UNIX/Linux C (95)
C++ (128)
STL (4)
Java (38)
Win32 API (92)
ATL/COM (44)
MFC (151)
.NET (26)
WCF/WPF (4)
C# (28)
Network Programming (17)
Database Programming (12)
OpenGL / DirectX (13)
Multimedia Programming (0)
Game Programming (21)
Parallel Distributed Progra... (0)
Reverse Engineering (0)
Debugging (9)
Python (1)
Ruby (1)
Ruby on Rails (1)
QT (4)
GTK (0)
JSP (0)
PHP (6)
ASP.NET (6)
ASP (2)
Development (28)
Useful Library (2)
Data Modeling (0)
Database (105)
Oracle (4)
MSSQL (41)
MySQL (2)
Data Warehouse (2)
Data Mining (4)
Network (66)
Web (79)
DHTML (4)
XHTML (1)
Javascript (1)
CSS (1)
AJAX (9)
XML (11)
Flex (1)
Silverlight (3)
Security (91)
DoS (1)
Kernel (10)
Scanning (3)
Sniffing (0)
Spoofing (4)
Overflow (28)
Web (11)
Shell (10)
Format String (14)
Window (2)
Embedded (70)
Multimedia (27)
Mobile (14)
Graphic (24)
Management (633)
Knowledge (581)
Hadoop (0)

Notice

  • 메타 블로그 사이트에 등록
  • 새해 맞이 블로그의 변화
  • 블로그 명칭 변경
  • 도메인(www.webdizen.net) 구...
  • TEXTCUBE 1.6.1로 업그레이드...

Tags

  • JsUnit
  • 보안 솔루션
  • 데이터
  • 첨단정보기술연구센터
  • 해킹
  • 동적 SQL
  • 의과대학
  • OLAP
  • SOA
  • XMLParser
  • SQL
  • 석재복합연구소
  • 창의력
  • 디스크 포멧
  • 빠에야
  • Powershell
  • 동기화 클래스
  • 웹 개발자
  • Windows Workflow Foundation
  • 스탠포드

Recent Articles

  • 트위터(Twitter)의 시작!.
  • 청년 리더의 조건.
  • 애플의 타블렛 PC - 아이패드....
  • 미래의 인터페이스 - 육감 기....
  • 기초발성법 동영상 강좌.

Recent Comments

  • 경청... 너무나 중요한데.......
    webdizen 14:59
  • 학교 과제물중 쓰레드에 대하....
    장진혁 03/17
  • 관리자만 볼 수 있는 댓글입....
    비밀방문자 03/12
  • 상대방의 이야기를 열심히 경....
    DoNuts 03/03
  • 좋은글 잘 보고 갑니다..
    Und_hacker 01/08

Recent Trackbacks

  • printf,scanf를 이용한 형식....
    yundream의 프로그래밍 이야기 03/10
  • 파일 열기/저장하기 CFileDialog.
    은마군의 나태블록 2009
  • World IT Show 2008.
    상우 :: Oranzie's BLOG 2008
  • cvs서버 설치하기.
    3인3색 2008
  • 속속 공개되는 Google Chart....
    PHP와 Web 2.0 2007

Archive

  • 2010/02 (1)
  • 2010/01 (6)
  • 2009/12 (5)
  • 2009/09 (3)
  • 2009/08 (1)

Calendar

«   2010/03   »
일 월 화 수 목 금 토
  1 2 3 4 5 6
7 8 9 10 11 12 13
14 15 16 17 18 19 20
21 22 23 24 25 26 27
28 29 30 31      

Bookmarks

    • Administration
      • IIS.NET
      • NTFAQ
      • OS의 모든 것
      • 리눅스포털
    • Database
      • SQL Server Central
      • SQL Team
    • Development
      • .NET Heaven
      • ASP Alliance
      • ASP.NET 2.0
      • Bullog.net
      • C# Corner
      • C++ (C PlusPlus.com)
      • C++ Reference
      • CodeGuru
      • CodePlex
      • DebugLab
      • Dev Articles
      • Devpia
      • DotNet Junkies
      • DotNet Zone
      • Driver Online
      • GOSU.NET
      • HOONS 닷넷
      • Joinc 팀블로그
      • KOSR
      • MSDN Home Page
      • OSR Online
      • Sky.ph - 개발자 커뮤니...
      • TAEYO.NET
      • The Code Project
      • WindowsClient.net
      • 김상욱의 개발자 Side
      • 조인시 위키
    • Human Networks
      • belief21c's e-space
      • I think I can
      • Invisible Rover's Blog :D
      • Polarux - Linuxing
      • Rodman®
      • 까만 나비
      • 나를 가꾸는 시간.
      • 단녕
      • 상우 :: Oranzie's BLOG
    • Information Technology
      • Microsoft TechNet
      • 지디넷코리아 - 글로벌...
    • Security
      • FoundStone
      • milw0rm
      • NewOrder
      • OpenRCE
      • Phrack.org
      • Reverse Engineering b1...
      • Reverse Engineering Team
      • RootKit
      • SecurityFocus
      • SecurityXploded by Nag...
      • Wow Hacker
      • Zone-H
Textcube
Louice Studio Inc.
Powered by Textcube. Original designed by Tistory.