Surface 사용



1. 텍스쳐 생성

if(FAILED(g_d3d_Device->CreateTexture(w, h, 0, 0,
                       D3DFMT_A8R8G8B8, D3DPOOL_MANAGED, ppTexture, NULL)))
                goto error;

D3DX의 D3DXCreateTextureFromFile()같은 함수를 사용해 텍스쳐를 로드해도 되지만, 여기서는 텍스쳐 표면에
직접 접근하기 위해 디바이스의 CreateTexture()를 사용할 것이다.

첫 번째, 두 번째 인자는 폭과 높이를 나타낸다.

세 번째 인자는 밉레벨을 나타낸다.
0이면 모든 레벨의 밉맵을 만들고, 0이외의 값은 해당하는 레벨의 맵만 만든다.

네 번째 인자는 사용플래그로 0이면 아무런 값도 지정하지 않는다.
D3DUSAGE_DEPTHSTENCIL이면 Z 스텐실, D3DUSAGE_RENDERTARGET은 렌드링 타겟이다.
보통 텍스쳐로 사용된면 0을 넣는다.

다섯 번째 인자는 텍스쳐 포맷으로 명시적으로 지정해야 한다.
디폴트 지정자 D3DFMT_UNKNOWN와 같이 사용하면 안된다.

여섯 번째 인자는 텍스쳐 메모리에 대한 플래그이다.
보통은 D3DPOOL_DEFAULT를 사용하지만, 이 값은 락을 걸 수 없는 옵션이다.
또한 D3DPOOL_SYSTEMMEM도 락을 걸 수 있지만, 다이렉트 X쪽에서 액세스 할 수 없다.
이 텍스쳐는 렌드링시 텍스쳐로 사용할 수 없다.
이 플래그의 사용 목적은 우선 시스템 메모리에 버퍼를 만들고 버퍼에서 텍스쳐를 조작한후 DirectX를
사용해, CopyRects()와 같은 함수를 사용해 비디오 메모리로 카피한다.

일곱 번째 인자는 LPDIRECT3DTEXTURE9로 텍스쳐 객체이다.

여덟 번째 인자는 예약된 인자로 NULL을 넣는다.            

if(FAILED((*ppTexture)->GetSurfaceLevel(0, &surface)))
               goto error;

첫 번째 인자는 밉맵 레벨 0의 surface를 구해 온다. 레벨 0은 원래의 크기이다.

surface->LockRect(&rect, NULL, 0);

첫 번째 인자는 D3DLOCKED_RECT 구조체로 락된 영역의 정보가 들어온다.
두 번째 인자는 락을 걸 RECT 구조체이다. NULL값이면 전체 영역에 락을 건다.
세 번째 인자는 락의 유형이다. 여기서는 0을 넣는다.

D3DLOCKED_RECT 구조체는  Pitch와  pBits 두 개의  필드로 이뤄져 있다.
pBits 잠그진 버퍼의 선두 주소를 나타낸다.pBits는 x값, 즉 한행의 바이트 수를 나타낸다. 한행이 1024픽셀이고 4바이트라면
한 행의 바이트가 1024*4의 결과 값이 나와야 하지만 그래픽 카드에서 캐싱과 같은 여러 가지 이유로 해서 계산값과
일치 하지 않기 때문에 한행을 증가시킬 때 마다 pBits값을 사용해야 한다

        //BMP 데이타를 카피한다(비트맵은 위아래 반대로 저장되기 때문에 아래에서부터 저장한다)
        for(y=(int)bInfo.biHeight-1; y>=0; y--)
        {
                //Y값의 시작 위치로 이동한다.
                data = (LPDWORD)((LPBYTE)rect.pBits + rect.Pitch * y);

                for(x=0; x<bInfo.biWidth; x++, data++)
                {
                        BYTE    r, g, b;
                        fread(&b, sizeof(BYTE), 1, fp);
                        fread(&g, sizeof(BYTE), 1, fp);
                        fread(&r, sizeof(BYTE), 1, fp);

                        //불투명 칼라값을 surface에 넣는다.
                        *data = 0xff000000 | ((DWORD)r << 16) | ((DWORD)g << 8) | ((DWORD)b);
                }
        }

bInfo는 BITMAPINFOHEADER 구조체이다. 여기에 비트맵 사이즈, 픽셀당 칼라 비트수와 같은 정보가 들어가 있다.
비트맵 데이터는 위아래가 반대 방향으로 저장되는 포맷이기 때문에 메모리에 저장할 때 다시 위아래를 뒤집어준다.
Pitch값으로 y값의 시작 위치로 이동한다.
텍스쳐 포맷이 D3DFMT_A8R8G8B8이므로 4바이트 DWORD 크기가 된다.

 *data = 0xff000000 | ((DWORD)r << 16) | ((DWORD)g << 8) | ((DWORD)b);
위의 방식은 아래의 방식과 같다. surface와 비트맵은 blue, green, red의 순서로 저장되어있다.\
surface도 또한 blue, green, red의 순서로 저장된다. 불투명한 값으로 만들기 위해 0xff로 채운다.

            char* p = (char*)data;
            *p = b;
            *(p + 1) = g;
            *(p + 2) = r;
            *(p + 3) = 0xff;

surface->UnlockRect();

표면의 사용이 끝나면 락을 해제한다.

_RELEASE_<LPDIRECT3DSURFACE9>(surface); 

GetSurfaceLevel()함수 내부에서 IDirect3DSurface9 참조 카운터를 증가시키기 때문에 릴리즈 시켜주어야 한다.
안그러면 IUnknown::Release()시에 메모리 leak이 일어 날것이다.

LoadTextureFromBMP() 함수의 전체 소스는 다음과 같다.


비디오 램의 언, 락은 프레임을 떨어뜨린다(락을 걸고 액세스하기 때문이다.) DirectX에서 프레임을 떨어떠리는
첫 번째 요소는 다각형 채우기이다. 그리고 두 번째 요소는 비디오램에 액세스 하는 것이다.
매프레임마다 액세스 해야 한다면 시스템 메모리에 표면을 만든후, CopyRect() 함수로 복사하는게 좋지 않을까하는
생각이 든다.

마지막으로 FillRed()를 추가하였다.
F1 키를 누르면 김태희 사진을 빨간색으로 채운다.

 

[펌]
http://monsho.hp.infoseek.co.jp/dx/dx9.html
Direct9를 이용한 3D GAME 프로그래밍 입문 - 정보문화사