디시인사이드 갤러리

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

갤러리 본문 영역

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

∫ 2t dt=t²+c갤로그로 이동합니다. 2009.11.20 18:03:34
조회 869 추천 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/13 - -
AD 프로게이머가 될테야!! 운영자 25/10/01 - -
공지 프로그래밍 갤러리 이용 안내 [96] 운영자 20.09.28 47903 65
2896136 강남 인기장소사이트 인기사이트(118.235) 04:20 2 0
2896135 동네 어느나무에 핀 버섯 ㅇㅅㅇ 헤르 미온느갤로그로 이동합니다. 02:41 9 0
2896134 태연 ㅇㅅㅇ 헤르 미온느갤로그로 이동합니다. 02:39 11 0
2896133 하루 한 번 헤르미온느 찬양 헤르 미온느갤로그로 이동합니다. 02:39 15 0
2896132 전자공학과 자퇴하고 국비로 IT업계 취업 노리는거 어떰..? 프갤러(121.144) 02:33 19 0
2896131 복분자주 마셔본사람 ㅇㅅㅇ?? 술집에서 얼마에파냐 ㅇㅇ(223.38) 02:13 11 0
2896130 한때 사직동 하숙할 때 주인할매가 그러던데 프갤러(49.165) 02:09 15 0
2896123 홈랩은 왜 하는거임?? 타이밍뒷.통수한방(1.213) 01:10 20 0
2896122 컴공 전공지식이라고 배우는것들은 다 저수준인데 ㅆㅇㅆ(124.216) 00:47 45 0
2896121 전공지식이 도움되려면 비전공 병신들이 엄두도 못내는데 가야 [3] 프갤러(110.8) 00:41 45 0
2896119 결국 오늘도 차단당했구나 ㅇㅇ(124.48) 00:23 28 0
2896118 진짜 다시 무시하고 차단해도 아이피를 계속 바꿔대니 [3] ㅆㅇㅆ(124.216) 00:12 54 0
2896117 학생때 배운거 써본적 거의 없는듯 [4] 루도그담당(58.239) 00:09 64 0
2896115 너가 따라다닌게 1년이 넘음 친구야 인생 낭비라 생각 안하냐 ㅆㅇㅆ(124.216) 00:06 35 0
2896114 갤 분위기 초상났네 [6] 루도그담당(58.239) 00:02 75 0
2896113 진짜 진심으로 안타까운데, 저새끼 계속 내 글마다 댓글달려서 알람울리는게 [2] ㅆㅇㅆ(124.216) 10.13 57 0
2896112 취직했다는 놈이 당장 뭐 말하는 개념마다 빈틈 털려서 딴새끼한테 [1] ㅆㅇㅆ(124.216) 10.13 50 0
2896110 여기서 남 욕한다고 니 인생이 바뀌는게 전혀 아님 124.48아 ㅇㅇ [1] ㅆㅇㅆ(124.216) 10.13 31 0
2896108 진심 이해가 안가는게 그거임. 내가 저새끼 나이때는 대학원가볼라고 [1] ㅆㅇㅆ(124.216) 10.13 40 0
2896106 자존감이 단단한 사람일수록 자길 내세우지 않는거임 [2] ㅇㅇ(218.149) 10.13 48 0
2896104 쟤 이해가 안 감. 보통 자기가 백수면 노력하지 않나? [3] ㅆㅇㅆ(124.216) 10.13 31 0
2896103 염병하지말고 현실에서 착실하게 살아라.. 좆병신새끼야 [1] ㅇㅇ(218.149) 10.13 23 0
2896102 저새끼는 자존감 채우는 방식 자체가 미숙함 [1] ㅇㅇ(218.149) 10.13 31 0
2896100 앱 웹 개발자는 개인정보 [3] ㅇㅇ(211.187) 10.13 40 0
2896099 '최신' 리액트 쓴다는놈이 Next.js 안써봤다 [1] ㅆㅇㅆ(124.216) 10.13 40 0
2896098 해결법을 다오. [3] 루도그담당(58.239) 10.13 34 0
2896097 웹상에서 자존감 채우려고 하니까 그따위 허영부리며 사는거야 [2] ㅇㅇ(218.149) 10.13 27 0
2896095 딱봐도 실력없어서 과제대행으로 용돈벌이나 하는 사회 최하층민새끼가 [5] ㅇㅇ(218.149) 10.13 32 0
2896093 개인사업자면 홈텍스를 인증해라.. [2] ㅇㅇ(218.149) 10.13 46 0
2896089 진짜 신기하지 않냐? 124.48 점마는 지가 말할수록 백수라는게 드러남 [1] ㅆㅇㅆ(124.216) 10.13 33 0
2896087 124.48 쟤는 거짓말이 너무 티가남. 그게 문제임 [3] ㅆㅇㅆ(124.216) 10.13 45 0
2896086 암만봐도 타임라인 진짜 씹쓰레기 같네 [4] 루도그담당(58.239) 10.13 56 0
2896082 전공에서 배운거 실무에서 얼마나 써먹는중? [6] ㅇㅇ갤로그로 이동합니다. 10.13 66 0
2896081 네트워크는 ㅈㅈ쳤다 ㅈㄴ노잼에어렵네 프갤러(14.43) 10.13 23 0
2896080 너네 아직도 그러고 사냐? 프갤러(59.16) 10.13 25 0
2896078 혹시 치킨한마리 나눔해주실분 계십니까. ㅇㅇ(223.39) 10.13 13 0
2896077 마이크로소프트10년동안 발전보다버그투성이가됬누 타이밍뒷통수한방(1.213) 10.13 13 0
2896075 나 오랜마네 바카라 사이트 들어가서 3번 찍었는데 다맞음 ㅇㅅㅇ ㅇㅇ(223.39) 10.13 11 0
2896074 님들아 백준 알고리즘 풀때 유튜브 영상틀어놓거나 노래들으면서 풀음? 프갤러(123.212) 10.13 16 0
2896073 북괴 김정은 한국에 홍수 일으켜 인명살상 노렸나 충격 ♥덩냥이♥갤로그로 이동합니다. 10.13 15 0
2896071 한우물 진득하고 꾸준하게 팔 수 있는거도 재능인거 같다 [6] chironpractor갤로그로 이동합니다. 10.13 46 0
2896070 야애니 ♥덩냥이♥갤로그로 이동합니다. 10.13 24 0
2896069 [단독] 서울시, 첫 민간인 ‘핵 벙커’ 만든다 발명도둑잡기(118.216) 10.13 17 0
2896068 신문고로 불법주차 신고하는 놈들 중 정상인은 없다는게 팩트임 [11] 야옹아저씨갤로그로 이동합니다. 10.13 44 5
2896067 엔지) 프갤러(211.243) 10.13 18 0
2896065 ‘근무시간 노래방’ 판사, “2차는 애기 보러가자”는 변호사에 “좋죠 형 발명도둑잡기(118.216) 10.13 15 0
2896063 특전사 前단장 "케이블타이 체포용 아냐…끌어내라 지시 못들어" 발명도둑잡기(118.216) 10.13 21 0
2896062 어제 쓰던글 이어서 쓰려다가 피궁해서 못쓰겟당 ♥덩냥이♥갤로그로 이동합니다. 10.13 32 0
2896061 윤석열·김건희 프랑스 방문 때 반려견 동반 위해 '개 의전' 준비 발명도둑잡기(118.216) 10.13 17 0
갤러리 내부 검색
제목+내용게시물 정렬 옵션

오른쪽 컨텐츠 영역

실시간 베스트

1/8

디시미디어

디시이슈

1/2