디시인사이드 갤러리

갤러리 이슈박스, 최근방문 갤러리

갤러리 본문 영역

적분시리즈: 2. 파일 메모리 매핑, 스프라이트 읽기와 그리기

∫ 2t dt=t²+c갤로그로 이동합니다. 2009.11.20 18:03:34
조회 868 추천 0 댓글 2


1757E4104B065454048FBD
화면에 그림을 그리기 위해서는 먼저 파일에서 비트맵을 읽어와야한다. 아무리 3D라고 할지라도 그 기본은 변하지 않는다.3D프로그래밍에서는 비트맵 대신에 텍스쳐라는 말을 자주 쓴다. 그러니 앞으로 텍스쳐 얘기가 계속 나오면 그냥 비트맵을말하는건가보다 하고 간단히 넘어가자.
Direct3D에서는 텍스쳐를 관리하는 인터페이스로 IDirect3DTexutre9를 제공한다.
근데 문제가 하나 있다. 비디오카드에서 받을 수 있는 텍스쳐는 가로 세로길이가 (2의 거듭제곱)픽셀이어야 한다. 요즘에는 가로 세로 길이에 제한이 없는 비디오카드도 있지만, 모든 카드에서 그런것이 아니다.
그러므로 우리가 사용할 텍스쳐는 어쩔 수 없이, 가로 세로 길이가 (2의 거듭제곱)픽셀이어야 한다. 그러나 화면에 출력할 그림들의 크기가 늘 (2의 거듭제곱)꼴일수는 없다.
그래서 여기에서 대안을 소개한다.
2의 거듭제곱 꼴의 크기를 갖는 텍스쳐를 불러오기는 하되, 부분부분을 쪼개서 사용하는 것이다. 이 한 조각을 스프라이트(Sprite)라고 하자.

이제, 텍스쳐와 스프라이트를 관리하는 클래스를 하나 만들겠다. 이름은 GSprites라고 하자.

그리고 스프라이트 정보를 담는 구조체를 GSpriteDat이라고 하자.
GSpriteDat은 두 필드로 이뤄져 있다.
DWORD itxt; 텍스쳐의 인덱스
RECT rect; 텍스쳐 중에서 사용할 사각형 영역

class GSprites
{
protected:
    vector<LPDIRECT3DTEXTURE9> m_vptxt;
    vector<GSpriteDat> m_vspr;
public:
    GSprites();
    ~GSprites();
    GRET LoadTexture(DataInMem* file);
    GRET ReleaseTexture();
    GRET AddSprites(DWORD itxt, int left, int top, int right, int bottom);
    GRET DrawSprite(UINT index, int x, int y, D3DCOLOR color=0xffffffff) const;
};

vector가 등장했다. STL에 대해 잘 모르는 사람들은 적이 당황할수 있지만, 그렇게 어려운 놈은 아니므로 안심해도 좋다.vector는 길이가 자유롭게 변하는 배열이라고 생각하면 쉽다. vector 뒤에는 <>를 쓰고 그 안에 데이터타입을 써넣는다. 예를 들어 vector<int>라 하면 길이가 자유롭게 변하는 int 배열이 되는것이다.
vector에서 가장 중요한 함수는 push_back과 pop_back, 그리고 size이다.
push_back은 배열의 꽁지에 원소 하나를 추가하는 일을 하고,
pop_back은 꽁지에 있는 원소 하나를 빼는 일을 한다.
size는 전체 원소의 개수를 알려준다.
일반 배열처럼 []를 사용해서 원소에 접근할 수 있으니, 크기가 변하는 배열이라면 vector를 애용해주자.

이제 m_vptxt가 뭔지 쉽게 알 수 있다. 길이가 자유롭게 변하는 LPDIRECT3DTEXTURE9의 배열이다.

GRET GSprites::LoadTexture(DataInMem* file)
{
    if(!GGame::GetInstance()->GetDevice())return GRET_ERROR_NODEVICE;
    LPDIRECT3DTEXTURE9 ptxt;
    if(FAILED( D3DXCreateTextureFromFileInMemoryEx(GGame::GetInstance()->GetDevice(),
        file->getsrc(), file->getsize(), 0, 0, 0, 0, D3DFMT_UNKNOWN, D3DPOOL_MANAGED,
        D3DX_DEFAULT, D3DX_DEFAULT, 0, NULL, NULL, &ptxt)) )
    {
        return GRET_ERROR_FAIL;
    }
    m_vptxt.push_back(ptxt);
    return GRET_OK;
}
file에서 텍스쳐를 읽어오는 함수이다. DataInMem은 이따가 다시 살펴보도록 하고, 먼저 텍스쳐를 읽어오는 부분을 살펴보자.
D3DXCreateTextureFromFileInMemoryEx 함수를 사용했다. 후 이름 한 번 참 길다.
D3D에서는 텍스쳐를 만드는 함수를 여러가지 제공한다.

D3DXCreateTexture : 텍스쳐를 만든다.
D3DXCreateTextureFromFile : 텍스쳐를 파일로부터 만든다.
D3DXCreateTextureFromFileEx : 텍스쳐를 파일로부터 만드는데, 세부사항을 결정할 수 있다.
D3DXCreateTextureFromFileInMemory : 텍스쳐를 메모리로부터 만든다.
D3DXCreateTextureFromFileInMemoryEx : 텍스쳐를 메모리로부터 만드는데, 세부사항을 결정할 수 있다.

FromFile과 FromFileInMemory와는 파일에서 읽어오느냐, 메모리에서 읽어오느냐의 차이밖에 없고 나머지는 동일하다. 그러니까 하나만 제대로 알고 있으면 나머지도 알고 있는거나 마찬가지다.

HRESULT D3DXCreateTextureFromFileInMemoryEx(  LPDIRECT3DDEVICE9 <i>pDevice</i>,  LPCVOID <i>pSrcData</i>,  UINT <i>SrcDataSize</i>,  UINT <i>Width</i>,  UINT <i>Height</i>,  UINT <i>MipLevels</i>,  DWORD <i>Usage</i>,  D3DFORMAT <i>Format</i>,  D3DPOOL <i>Pool</i>,  DWORD <i>Filter</i>,  DWORD <i>MipFilter</i>,  D3DCOLOR <i>ColorKey</i>,  D3DXIMAGE_INFO * <i>pSrcInfo</i>,  PALETTEENTRY * <i>pPalette</i>,  LPDIRECT3DTEXTURE9 * <i>ppTexture</i>);
pDevice: D3D장치
pSrcData, SrcDataSize: 메모리의 시작 주소와, 그 크기

Width, Height: 만들 텍스쳐의 가로와 세로 길이, 0이나 D3DX_DEFAULT이면 원본 크기를 그대로 사용함.
- 원본크기를 그대로 사용한다지만, 2의 거듭제곱 꼴이 아닐 경우에는, 제일 가까운 2의 거듭제곱꼴로 올려버린다. 그러므로, 2의 거듭제곱 꼴이 아닌 것을 사용하면 그림이 원치 않는 비율로 늘어날 수 있다.

Pool: 텍스쳐가 위치할 메모리의 종류
 D3DPOOL_DEFAULT : 기본
 D3DPOOL_MANAGED : D3D가 처음부터 끝까지 다 관리해줍니다.
 D3DPOOL_SYSTEMMEM : 시스템메모리에 저장된다.
등등

- 흔히 D3DPOOL_DEFAULT를 사용하면 될것 같지만, 그러면 굉장히 성가시게 된다. D3DPOOL_DEFAULT로 만들어진 텍스쳐는 장치를 잃어버렸을 경우, 텍스쳐를 해제했다가, 장치가 복구되면 다시 만들어줘야 한다.
- D3DPOOL_MANAGED는 정말로 D3D가 처음부터 끝까지 다 관리해준다. 해제했다가 다시 만들어주는 일 따위는 신경쓰지 않아도 된다. (하지만 RenderTarget등으로는 쓸 수 없다는 단점이 있다.) 우리는 앞으로 이 방식을 사용할 것이다.
- D3DPOOL_SYSTEMMEM은 지금 몰라도 아무 문제 없으므로 패스.


ColorKey: 투명색으로 사용할 색깔.
- bmp나 jpg같은 이미지 포맷은 알파채널이 없다. 만약 이런 이미지들을 사용할때, 투명색을 지정해 주려면 사용하면 된다. 그러나 우리는 png포맷을 사용할것이므로 신경 쓸 필요가 없다.

ppTexture: 우리가 얻고자하는 LPDIRECT3DTEXTURE9의 주소.

다시 본론으로 돌아가서,
텍스쳐를 성공적으로 만들었다면 m_vptxt.push_back(ptxt) 로 m_vptxt에 꽁지에 넣어놓는다.

GRET GSprites::ReleaseTexture()
{
    for(size_t i=0;i<m_vptxt.size();i++)
    {
        SAFE_RELEASE(m_vptxt.back());
        m_vptxt.pop_back();
    }
    return GRET_OK;
}
텍스쳐를 해제해주는 함수이다. GSprites 소멸자에서 반드시 이 함수를 호출해줘야 한다. 그렇지 않으면 해제되지 않은 텍스쳐 때문에 메모리가 줄줄 새게 될 것이다.
m_vptxt.back()이라는 것은 m_vptxt에 마지막 원소를 내놓으라는 얘기이다. 그것을 SAFE_RELEASE한 뒤에 m_vptxt.pop_back()하여서 배열의 원소에서 빼버리는 것이다.

이제 DataInMem에 대해서 설명하겠다.

파일에서 데이터를 읽어오는 함수를 열심히 짜놓았다고 해보자. 근데 나중에 그 파일이 리소스로 포함되어버렸다. 그래서 이제 메모리상에서 데이터를 읽어와야 한다. 그러면 전에 짜놓았던 함수 말고 또 다른 함수를 다시 짜야한다. 상당히 귀찮은 일이다. 데이터가메모리 상에 있던지 파일에 있던지 상관하지 않고 일률적으로 입출력하기 위해서 DataInMem클래스를 만들었다.

class DataInMem
{
protected:
    char* m_psrc;
    size_t m_size;
    size_t m_pointer;
public:
    DataInMem(void* psrc, size_t size);
    virtual ~DataInMem() {}
    size_t read(void* dest, size_t n);
    virtual size_t write(const void* src, size_t n);
    int seek(int offset, int whence);
    size_t getsize();
    const void* getsrc();
};
DataInMem함수는 일반 파일 입출력과 비슷하게 읽고(read), 쓰고(write), 포인터이동(seek)도 할 수 있다.
하지만, DataInMem함수는 메모리상의 데이터에 대해서만 작동한다. 파일 상의 데이터를 위해서 약간 손을 봐야한다.

class DataInFile : public DataInMem
{
protected:
    HANDLE m_hFileMap;
    DWORD m_access;
public:
    enum{
        readonly=1,
        readwrite=2,
    };
    DataInFile(HANDLE hFile, DWORD access=readonly);
    virtual ~DataInFile();
    size_t write(const void* src, size_t n);
};

DataInFile::DataInFile(HANDLE hFile, DWORD access) : DataInMem(NULL, 0), m_access(access)
{
    m_size=GetFileSize(hFile, NULL);
    m_hFileMap=CreateFileMapping(hFile, NULL,
        m_access==readonly ? PAGE_READONLY : PAGE_READWRITE,
        0, (DWORD)m_size, NULL);
    if(m_hFileMap==NULL) /*CreateFileMapping 실패했을 경우*/
    {
        m_size=0;
        return;
    }
    m_psrc=(char*)MapViewOfFile(m_hFileMap,
        m_access==readonly ? FILE_MAP_READ : FILE_MAP_ALL_ACCESS,
        0, 0, 0);
    if(m_psrc==NULL) /*MapViewOfFile 실패했을 경우*/
    {
        CloseHandle(m_hFileMap);
        m_hFileMap=NULL;
        m_size=0;
        return;
    }
}
DataInMem클래스를 상속받아서 DataInFile 클래스를 만들었다. 이 클래스는 파일을 메모리에 매핑하여 DataInMem클래스로 주소를 넘겨주는 역할을 한다.

-파일을 메모리에 매핑한다?
파일을 메모리 주소에 연결시켜서 그 주소에 읽기/쓰기를 하면, 파일에 읽기/쓰기를 할 수 있는 기법을 말한다.
CreateFileMapping함수를 사용하여서 먼저 FileMapping핸들을 얻고,
MapViewOfFile함수를 사용하여서 메모리 주소를 얻는다.
그리고 다 쓴 후에는 CloseHandle을 이용해서 닫아준다.

그리고 다시 DataInFile을 상속받아서 DataInFileDirect 클래스를 만들었다. DataInFileDirect클래스는 파일 주소를 가지고 파일을 열어서(CreateFile함수) DataInFile에게 그 핸들을 넘겨준다.

GRET GSprites::DrawSprite(UINT index, int x, int y, D3DCOLOR color) const
{
    if(m_vspr.size()<=index)return GRET_ERROR_PARAM;
    D3DXMATRIX mat;
    GGame::GetInstance()->GetSprite()->SetTransform(D3DXMatrixIdentity(&mat));
    if(FAILED( GGame::GetInstance()->GetSprite()
        ->Draw(m_vptxt[m_vspr[index].itxt],
        &m_vspr[index].rect, NULL,
        &D3DXVECTOR3((float)x, (float)y, 0), color) ))
    {
        return GRET_ERROR_FAIL;
    }
    return GRET_OK;
}
다시 GSprites로 돌아와서 화면에 출력하는 함수를 살펴보자.
GGame에서 ID3DXSprite 인터페이스를 얻어와서 Draw해주고 있다.
SetTransform함수는 변환행렬을 설정해주는 부분인데, 단위행렬을 그냥 설정했다. 이 것에 대해서는 다음 강좌에서 자세히 설명하겠다.

HRESULT
Draw(  LPDIRECT3DTEXTURE9 <i>pTexture</i>,  CONST RECT * <i>pSrcRect</i>,  CONST D3DXVECTOR3 * <i>pCenter</i>,  CONST D3DXVECTOR3 * <i>pPosition</i>,  D3DCOLOR <i>Color</i>);
pTexture: 화면에 그릴 텍스쳐.
pSrcRect: 텍스쳐의 어느 부분을 그릴것인가? NULL일 경우 전체 다 그린다.
pCenter: 텍스쳐의 중심을 어디로 잡을까? NULL일 경우 (0, 0)을 중심으로 잡는다.
pPosition: 어느 지점에 그릴것인가? NULL일 경우 (0, 0)에다가 그린다.
Color : 텍스쳐에 곱할 색깔.

void GGame::OnCreate()
{
    m_sprs.LoadTexture(&DataInFileDirect(L"integral.png"));
    m_sprs.AddSprites(0, 0, 0, 128, 128);
    m_sprs.AddSprites(0, 128, 0, 256, 128);
    m_sprs.AddSprites(0, 128, 128, 256, 192);
}
void GGame::OnDraw()
{
    m_sprs.DrawSprite(0, 10, 10);
    m_sprs.DrawSprite(1, 200, 110, D3DCOLOR_ARGB(127, 255, 255, 255)); //투명도 50%
    m_sprs.DrawSprite(2, 390, 220, D3DCOLOR_ARGB(255, 255, 0, 0)); //빨갛게
}
OnCreate에서 텍스쳐를 읽고, 스프라이트를 3개 추가하고,
OnDraw에서 그리고 있다.


추천 비추천

0

고정닉 0

0

원본 첨부파일 1

댓글 영역

전체 댓글 0
본문 보기

하단 갤러리 리스트 영역

왼쪽 컨텐츠 영역

갤러리 리스트 영역

갤러리 리스트
번호 제목 글쓴이 작성일 조회 추천
설문 공개연애가 득보다 실인 것 같은 스타는? 운영자 25/10/06 - -
AD 프로게이머가 될테야!! 운영자 25/10/01 - -
공지 프로그래밍 갤러리 이용 안내 [96] 운영자 20.09.28 47729 65
2894897 복권 당첨되면 뭐할까 한번 생각해봤어. ㅇㅇ(223.38) 16:34 9 0
2894896 연휴인데 질문받습니다. n년차 네카라 백엔드입니다. [2] 프갤러(58.126) 16:20 13 0
2894895 모니터 세로로 쓰는것도 좋지 않음..? 프갤러(221.167) 16:09 11 0
2894893 실리콘밸리 개발자? 걔들 왜 짤리는거임 [1] ㅇㅇ(106.101) 15:40 23 0
2894892 제가 미쳤냐 봅니다. Jump 넥도리아(223.38) 15:22 21 0
2894891 근데 왜 국비웹땔깜들끼리 싸움? [2] ㅇㅇㅇ(125.130) 14:50 35 0
2894890 근데 나만 스택 분기별로 체크하냐? ㅆㅇㅆ(124.216) 14:43 20 0
2894888 내가 만든 GPT가 생성한 수학교재 - 인수분해 멘타리갤로그로 이동합니다. 14:40 24 0
2894884 교환 가능하네 류류(220.147) 14:29 11 0
2894882 C++ 인생 40 년 갈아 넣었습니다. 프갤러(59.16) 14:24 38 0
2894881 카레시켰는데 드럽게 맵네 류류(220.147) 14:24 13 0
2894880 메이드양 나보다 다리 두꺼운데 ㅇㅅㅇ 류류(220.147) 14:06 23 0
2894879 메이드 카페 와봤는데 류류(220.147) 14:04 23 0
2894878 C# 은 명작은 듯 해. 어디 자바 따위가 깝쳐. [1] 프갤러(59.16) 13:57 36 0
2894876 유니티 IK 보는데 루도그담당(58.239) 13:37 15 0
2894875 어제 매향리 - 궁평항 ㅇㅇ(121.168) 13:10 24 0
2894874 생각해보니 영상생성과 llm이랑 비슷하네 ㅇㅇ갤로그로 이동합니다. 13:04 23 0
2894871 홍보에 관한 고찰? [3] 프갤러(121.172) 12:43 33 0
2894869 원피스 1162화 ♥덩냥이♥갤로그로 이동합니다. 12:24 37 0
2894868 애니뉴스야 너 모바일 웹소켓 wss로 했냐? [5] ㅆㅇㅆ(124.216) 12:23 43 0
2894867 디시 짤댓글기능 잘만든거같음 박민준갤로그로 이동합니다. 12:22 18 0
2894866 음코 딱 좋당 이기양~❤+ ♥덩냥이♥갤로그로 이동합니다. 12:16 28 0
2894865 웹소켓 모바일 기기 접속 오류 [3] 프갤러(121.172) 12:14 37 0
2894864 충전이 안되는데, 전면패널 원래 고장난건데, USB 3.0 과다 충전. 넥도리아2025(112.170) 12:06 10 0
2894863 ❤✨☀⭐⚡☘⛩나님 시작합니당⛩☘⚡⭐☀✨❤ ♥덩냥이♥갤로그로 이동합니다. 12:00 15 0
2894862 멍유님 제발 모모 성희롱 발언 좀 자제 해주세요 ♥덩냥이♥갤로그로 이동합니다. 11:53 26 0
2894861 임베에서 더 나은 처우를 받는법 [3] 박민준갤로그로 이동합니다. 11:46 47 0
2894859 나는 근데 뭘하든 할 수 있을거라 생각해서 걍 아무거나 하는중 ㅆㅇㅆ(124.216) 11:34 25 0
2894858 웹개발하다가 임베를 왜감 [3] 박민준갤로그로 이동합니다. 11:31 62 0
2894857 혼자 뭘 해보기엔 게임이 그나마 괜찮을 편일걸 프갤러(110.8) 11:30 23 0
2894856 게임은 로직도 로직인데 일단 에셋 비용이 필요함 [4] ㅆㅇㅆ(124.216) 11:20 41 0
2894855 근데 프로그래밍만큼 재밌는 취미가 있나 읽을거리랑 볼 거리 많잖아 [2] ㅆㅇㅆ(124.216) 11:08 43 0
2894854 근데 게임만큼 비효율적인 바닥이 없다 [3] 루도그담당(58.239) 11:00 65 0
2894853 최근에 WASM 문서 다 읽어봤는데 이걸 굳이? 싶더라 [1] ㅆㅇㅆ(124.216) 10:59 36 0
2894852 오랜만에 휴식하니까 좋네 ㅆㅇㅆ(124.216) 10:51 20 0
2894851 게임 만들고 싶어도 게임 자체가 비용이 있어야함 그림쟁이 없으면 [1] ㅆㅇㅆ(124.216) 10:50 35 0
2894848 공무원인데 개발자 일 배우는거 추천하냐? [6] 프갤러(124.57) 10:16 63 0
2894847 게임 개발하려고 객체지향 이론 3년 공부했다 ㅇㅇ(211.235) 10:11 34 2
2894846 지뢰계 [1] 발명도둑잡기(118.216) 10:09 29 0
2894845 ❤✨☀⭐⚡☘⛩나님 시작합니당⛩☘⚡⭐☀✨❤ ♥덩냥이♥갤로그로 이동합니다. 09:56 35 0
2894843 야한노래가 성경험 촉진 발명도둑잡기(118.216) 09:39 32 0
2894842 美 노랫말 33%에 '술' '마약' 들어간다 발명도둑잡기(118.216) 09:36 20 0
2894840 연휴라 일도 없고 게임한다고 개발일 이틀쉬는중 [5] ㅆㅇㅆ(124.216) 08:43 52 0
2894839 참취..ㅇㅅㅇ [2] 헤르 미온느갤로그로 이동합니다. 08:15 25 0
2894838 스타트, 중소 기업 개발자분들 워라벨 어때요? [4] 프갤러(39.112) 08:10 54 0
2894837 태연 ㅇㅅㅇ 헤르 미온느갤로그로 이동합니다. 08:06 23 0
2894836 하루 한 번 헤르미온느 찬양 헤르 미온느갤로그로 이동합니다. 08:05 36 0
2894835 Ada왜바이럴하는거잉? moo토낑7920(220.122) 08:05 28 0
2894833 웹 말고 다른 개발하는 사람들도 좀 잇나 ㅇㅇ갤로그로 이동합니다. 07:37 42 0
뉴스 글로벌 인플루언서 엑스포, '케이팝 데몬헌터스 챌린지' 열린다. 디시트렌드 10.05
갤러리 내부 검색
제목+내용게시물 정렬 옵션

오른쪽 컨텐츠 영역

실시간 베스트

1/8

뉴스

디시미디어

디시이슈

1/2