|
heartsim 님이 쓰신 글 :
: 안녕하세요.heartsim(박경원)입니다.
: 아침에 출근해서 QA란을 보고 이렇게 글 올립니다.
: 요즘 바빠서 겨를이 없는데, 차마 그냥 지나치지 못하겠더군요.
: 간단하게 API함수를 이용한 비트맵 제어 내용을 달아드리죠.
: (요즘 API 함수쪽 공부를 하고 있습니다.^^;)
: 관련함수를 빌더에 맞게 잘 활용하시면 될것 같네요.
: 참고 하십시요.
:
: 1항목 소스는
: CreateCompatibleDC(hDC);
: BitBlt(hDC, 0, 0, nX, nY, hMemDC, 0, 0, SRCCOPY);
: 을 이용해서 메모리로 로드후 화면에 일정크기(그대로) 출력하는 소스입니다.
: 가장 전형적인 비트맵 출력 방법이죠.
:
: 님께서 원하는 내용 즉, 비트맵을 메모리로 로드하고 화면크기에 맞게 확대 축소해서
: 출력하는 내용은 항목2에 나와있습니다.
: hMemDC = CreateCompatibleDC(hDC);
: StretchBlt(hDC, 0, 0, rect.right, rect.bottom, hMemDC, 0, 0, nX, nY,
: SRCCOPY); <---------이 함수를 이용해서 확대축소 출력할 수 있음.
:
: 항상 운 좋은 날 되십시요.
:
:
: -- 비트맵 ---
:
: 윈도우즈에서 비트맵 그림을 출력하는 방법은 생각외로 간단합니다. 그런데 이 루
: 틴을 가지고 게임을 만들수 있을까요? 너무 느리죠.
: 이런 단점을 보완해서 나온것이 WinG라고 하는 그래픽 출력 라이브러리인데
: 그나마 속력이 많이 개선 되었다고 할수 있습니다. 우리가 아래에서 다룰 예제
: 로는 쉽게 빠르다는 것을 구분할수 없지만요...
: 자 그러면 먼저 일반적인 출력 방법부터 알아 봅시다. 일반적으로 비트맵을 다루
: 기 위해서는 리소스 파일에서 그 비트맵 파일을 정의 해 주었다는 것을 기억할 겁
: 니다. 역시 출력할 비트맵 파일을 리소스 파일에서 정의하면 됩니다. 비트맵 파일
: 을 정의하고 나서 그 파일을 이용하려면 비트맵 핸들을 얻었다는 것을 기억하십니
: 까? 잘 기억이 안난다고요? LoadBitmap()이라는 함수를 이용해서 했잖아요.
: 여기까지 이해가 된다면 이제 추가된 새로운 방법을 알아 봅시다. 먼저 비트맵 그림
: 을 출력하기 위해서는 메모리에 디바이스 컨텍스트 핸들을 생성해야 됩니다. 우리가
: 일반적으로 생성한 디바이스 컨텍스트 핸들을 이용해서 문자를 출력하면 바로 화면
: 에 보여질 겁니다. 그렇죠? 여지껏 그렇게 했잖아요. 그런데 메모리에 디바이스 컨
: 텍스트 핸들을 생성하고 그 핸들을 이용해서 출력하면 화면에 보일까요? 당연히 안
: 보이죠. 그런데 왜 비트맵을 출력할때 이런과정이 필요할까요? 그것은 메모리에
: 그림 전체를 출력해 놓은 다음에 그것을 디바이스 컨텍스트 핸들을 이용해서 통채로
: 복사하기 위해서입니다. 게임 프로그래밍을 해 보신 분은 쉽게 이해할수 있겠죠?
: HDC CreateCompatibleDC(HDC hDC);
: 위 함수를 이용해서 메모리에 디바이스 컨텍스트 핸들을 생성할수 있습니다. 파라
: 미터로 현재 디바이스 컨텍스트 핸들을 지정하면 됩니다. 메모리 디바이스 컨텍스
: 트 핸들을 생성해서 사용한후에는 꼭 헤제해주어야 합니다.
: BOOL DeleteDC(HDC hDC);
: 위 함수를 이용해서 해제해주면 됩니다. 파라미터로 메모리 디바이스 컨텍스트 핸들
: 을 지정해 주면 됩니다.
: 자 이번에는 비트맵 그림의 크기를 얻는 방법을 알아 봅시다. 우리가 출력할 비트맵
: 그림이야 그 크기가 얼마나 되는지 자신이 알고 있을수도 있지만 모르고 있는 경우
: 도 있습니다. 그런데 왜 그림의 크기를 알고 있어야 할까요? 메모리에 있는 그림을
: 현 디바이스 컨텍스트로 복사할때 사용하는 함수가 크기를 지정하도록 하는 파라미
: 터를 요구하기 때문입니다.
: int GetObject(HGDIOBJ hgdiobj, int cbBuffer, LPVOID lpvObject);
: 위 함수를 이용해서 비트맵 그림에 대한 정보를 얻을수 있습니다. 첫번째 파라미터
: 로 비트맵 핸들을 지정하면 되고 세번째 파라미터에 BITMAP 구조체로 선언한 변수
: 의 주소를 지정하면 됩니다. 두번째 파라미터는 이 BITMAP 구조체의 크기를 지정하
: 면 되구요. 두번째 파라미터에 sizeof(BITMAP)이라고 지정하면 되겠죠.
: 아래는 BITMAP 구조체의 원형입니다.
: typedef struct tagBITMAP {
: LONG bmType;
: LONG bmWidth;
: LONG bmHeight;
: LONG bmWidthBytes;
: WORD bmPlanes;
: WORD bmBitsPixel;
: LPVOID bmBits;
: } BITMAP;
: 위 구조체의 맴버중 bmWidth, bmHeight에 그 크기의 정보가 저장됩니다.
: BOOL BitBlt(HDC hdcDest, int nXDest, int nYDest, int nWidth, int nHeigth,
: HDC hdcSrc, int nXSrc, int nYSrc, DWORD dwRop);
: 위 함수를 이용해서 메모리에 있는 그림을 현 디바이스 컨텍스트 핸들로 복사할수
: 있습니다. 즉 화면에 출력할수 있는것입니다.
: 첫번째 파라미터가 출력할 현 디바이스 컨텍스트 핸들을 의미하는 것입니다. 두번
: 째 파라미터와 세번째 파라미터는 출력할 좌표를 의미하고 네번째, 다섯번째 파라
: 미터는 그 넓이와 높이를 의미합니다. 이 파라미터에 비트맵 그림의 크기를 지정
: 하면 됩니다. 여섯번째 파라미터는 메모리 디바이스 컨텍스트 핸들을 의미합니다.
: 그러면 일곱번째와 여덟번째 파라미터는 뭘 의미할까요? 바로 메모리 디바이스 컨
: 텍스트 핸들의 첫번째 좌표를 의미하는 것입니다. 처음부터 다 복사하려면 0, 0을
: 지정하면되죠. 마지막 파라미터는 복사를 어떻게 할것인지를 의미하는 것입니다.
: 이 파라미터에 올수 있는 예약어에는 다음과 같은것들이 있습니다.
: SRCCOPY 메모리의 내용을 그대로 복사한다.
: SRCAND 메모리의 내용과 현 화면과 AND 연산을 한다.
: SRCINVERT 메모리의 내용과 현 화면을 XOR 연산을 한다.
: SRCPAINT 메모리의 내용과 현 화면을 OR 연산을 한다.
:
:
: 1.항목
: 자 그러면 대략적으로 어떤식으로 되는지 알아 보았으니 실제로 이것을 이용한 예
: 제를 봅시다. 아래는 비트맵 그림을 화면에 출력하는 예제입니다.
: 먼저 리소스 파일입니다.
: #include <windows.h>
: MyBitmap BITMAP "test.bmp"
: 프로그램 소스입니다.
: #include <windows.h>
: #include <stdlib.h>
: #include <string.h>
: LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
: HBITMAP hBitmap;
: int WINAPI WinMain
: (HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpszArg, int nCmdShow)
: {
: static char szAppName[] = "Graphic Example";
: HWND hWnd;
: MSG msg;
: WNDCLASS WndClass;
: WndClass.style = CS_HREDRAW|CS_VREDRAW;
: WndClass.lpfnWndProc = WndProc;
: WndClass.cbClsExtra = 0;
: WndClass.cbWndExtra = 0;
: WndClass.hInstance = hInstance;
: WndClass.hIcon = LoadIcon(NULL, IDI_APPLICATION);
: WndClass.hCursor = LoadCursor(NULL, IDC_ARROW);
: WndClass.hbrBackground = GetStockObject(WHITE_BRUSH);
: WndClass.lpszMenuName = NULL;
: WndClass.lpszClassName = szAppName;
: if(!RegisterClass(&WndClass))
: return FALSE;
: hWnd = CreateWindow(
: szAppName,
: szAppName,
: WS_OVERLAPPEDWINDOW,
: CW_USEDEFAULT,
: CW_USEDEFAULT,
: CW_USEDEFAULT,
: CW_USEDEFAULT,
: NULL,
: NULL,
: hInstance,
: NULL
: );
: hBitmap = LoadBitmap(hInstance, "MyBitmap");
: ShowWindow(hWnd, nCmdShow);
: UpdateWindow(hWnd);
: while(GetMessage(&msg, NULL, 0, 0))
: {
: TranslateMessage(&msg);
: DispatchMessage(&msg);
: }
: return msg.wParam;
: }
: LRESULT CALLBACK
: WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
: {
: HDC hDC, hMemDC;
: BITMAP bitmap;
: PAINTSTRUCT ps;
: static int nX, nY;
: switch(message)
: {
: case WM_PAINT :
: hDC = BeginPaint(hWnd, &ps);
: hMemDC = CreateCompatibleDC(hDC);
: SelectObject(hMemDC, hBitmap);
: GetObject(hBitmap, sizeof(BITMAP), (BITMAP *)&bitmap);
: nX = bitmap.bmWidth;
: nY = bitmap.bmHeight;
: BitBlt(hDC, 0, 0, nX, nY, hMemDC, 0, 0, SRCCOPY);
: DeleteDC(hMemDC);
: EndPaint(hWnd, &ps);
: return 0;
: case WM_DESTROY :
: PostQuitMessage(0);
: return 0;
: }
: return DefWindowProc(hWnd, message, wParam, lParam);
: }
: 먼저 리소스 파일을 보면 알겠지만비트맵 파일을 정의하죠?
: hBitmap = LoadBitmap(hInstance, "MyBitmap");
: 정의한 비트맵 그림을 로드하는 함수입니다. 이미 설명을 드렸을 겁니다. 자 그러면
: 실제로 화면에 출력하는 WM_PAINT 메시지 부분을 보도록 합시다.
: case WM_PAINT :
: hDC = BeginPaint(hWnd, &ps);
: hMemDC = CreateCompatibleDC(hDC);
: 메모리에 디바이스 컨텍스트 핸들을 얻는 과정입니다.
: SelectObject(hMemDC, hBitmap);
: 메모리 디바이스 컨텍스트 핸들로 앞에서 로드한 비트맵 핸들을 취하는 과정입니다.
: GetObject(hBitmap, sizeof(BITMAP), (BITMAP *)&bitmap);
: 비트맵 핸들을 이용해서 비트맵에 관한 정보를 BITMAP 구조체에 넣는 과정입니다.
: nX = bitmap.bmWidth;
: nY = bitmap.bmHeight;
: 비트맵의 크기를 선언한 변수에 저장하고 있습니다. 이게 왜 필요한지는 아래 함수
: 를 보면 알수 있을 겁니다.
: BitBlt(hDC, 0, 0, nX, nY, hMemDC, 0, 0, SRCCOPY);
: 메모리 디바이스 컨텍스트 핸들을 이용해서 메모리에 출력했던 것을 현 디바이스
: 컨택스트 핸들을 취하는 현재 화면에 복사하는 과정입니다.
: DeleteDC(hMemDC);
: 메모리 디바이스 컨텍스트 핸들을 이용한후에는 반드시 해제 해 주어야 한다고 했
: 을 겁니다.
: EndPaint(hWnd, &ps);
: return 0;
:
: 2.항목
: 비트맵 그림을 출력하는 예제를 볼건데 이것은 그림의 크기에
: 관계없이 작업영역에 꽉차게 출력되게 하는 것입니다. 즉 그림크기가 작업영역
: 크기보다 작으면 확대하고 크면 축소해서 출력하는 것입니다.
: 역시 같은 방법으로 API 함수를 이용해서 하는 방법과 WinG 그래픽 라이브러리를 이
: 용해서 하는 방법 두가지로 알아 보겠습니다.
: 보면 알겠지만 앞에서 그림출력하는 과정을 잘 이해하셨다면 이번 부분은 특별하게
: 새로 배울 부분은 없을 겁니다. 왜냐하면 함수 하나만 다르거든요. 그림을 축소, 확
: 대 해서 복사하는 함수가 있습니다.
: 그러면 먼저 API 함수를 이용해서 해보도록 합시다. 작업영역의 크기만큼의 그림으로
: 출력할려면 작업영역의 크기를 얻는 과정이 있어야 합니다. 물론 여러분들은 어떻게
: 크기를 얻는지 알수 있을 겁니다. 앞에서 여러번 했으니까요. 그리고 한가지만 더
: 알면 됩니다. 바로 BitBlt() 함수대신에 StretchBlt()함수를 사용한다는 것입니다.
: BOOL StretchBlt(HDC hdcDest, int nXDest, int nYDest, int nWidthDest,
: int nHeigthDest, HDC hdcSrc, int nXSrc, int nYSrc, int nWidth,
: int nHeight, DWORD dwRop);
: 위 함수를 이용해서 축소하거나 확대 할수 있는데 네번째, 다섯번째 파라미터에 유
: 저가 값을 지정해주면 그 크기로 복사가 됩니다. 그리고 BitBlt() 함수에 없던 새로
: 운 파라미터가 있는데 바로 아홉번째와 열번째 파라미터입니다. 이 부분에는 실제
: 그림의 크기를 지정해 주면 됩니다.
: 자 그러면 예제를 보도록 합시다.
: 아래는 리소스 파일의 소스입니다.
: #include <windows.h>
: MyBitmap BITMAP "test.bmp"
: 프로그램 소스입니다.
: #include <windows.h>
: #include <stdlib.h>
: #include <string.h>
: LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
: HBITMAP hBitmap;
: int WINAPI WinMain
: (HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpszArg, int nCmdShow)
: {
: static char szAppName[] = "Graphic Example";
: HWND hWnd;
: MSG msg;
: WNDCLASS WndClass;
: WndClass.style = CS_HREDRAW|CS_VREDRAW;
: WndClass.lpfnWndProc = WndProc;
: WndClass.cbClsExtra = 0;
: WndClass.cbWndExtra = 0;
: WndClass.hInstance = hInstance;
: WndClass.hIcon = LoadIcon(NULL, IDI_APPLICATION);
: WndClass.hCursor = LoadCursor(NULL, IDC_ARROW);
: WndClass.hbrBackground = GetStockObject(WHITE_BRUSH);
: WndClass.lpszMenuName = NULL;
: WndClass.lpszClassName = szAppName;
: if(!RegisterClass(&WndClass))
: return FALSE;
: hWnd = CreateWindow(
: szAppName,
: szAppName,
: WS_OVERLAPPEDWINDOW,
: CW_USEDEFAULT,
: CW_USEDEFAULT,
: CW_USEDEFAULT,
: CW_USEDEFAULT,
: NULL,
: NULL,
: hInstance,
: NULL
: );
: hBitmap = LoadBitmap(hInstance, "MyBitmap");
: ShowWindow(hWnd, nCmdShow);
: UpdateWindow(hWnd);
: while(GetMessage(&msg, NULL, 0, 0))
: {
: TranslateMessage(&msg);
: DispatchMessage(&msg);
: }
: return msg.wParam;
: }
: LRESULT CALLBACK
: WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
: {
: HDC hDC, hMemDC;
: BITMAP bitmap;
: PAINTSTRUCT ps;
: RECT rect;
: static int nX, nY;
: switch(message)
: {
: case WM_PAINT :
: hDC = BeginPaint(hWnd, &ps);
: hMemDC = CreateCompatibleDC(hDC);
: SelectObject(hMemDC, hBitmap);
: GetObject(hBitmap, sizeof(BITMAP), (BITMAP *)&bitmap);
: nX = bitmap.bmWidth;
: nY = bitmap.bmHeight;
: GetClientRect(hWnd, &rect);
: StretchBlt(hDC, 0, 0, rect.right, rect.bottom, hMemDC, 0, 0,
: nX, nY, SRCCOPY);
: DeleteDC(hMemDC);
: EndPaint(hWnd, &ps);
: return 0;
: case WM_DESTROY :
: PostQuitMessage(0);
: return 0;
: }
: return DefWindowProc(hWnd, message, wParam, lParam);
: }
: 머리가 좋으신분은 이미 다 이해했을 겁니다. 너무 쉽죠.
: case WM_PAINT :
: hDC = BeginPaint(hWnd, &ps);
: hMemDC = CreateCompatibleDC(hDC);
: SelectObject(hMemDC, hBitmap);
: GetObject(hBitmap, sizeof(BITMAP), (BITMAP *)&bitmap);
: nX = bitmap.bmWidth;
: nY = bitmap.bmHeight;
: GetClientRect(hWnd, &rect);
: StretchBlt(hDC, 0, 0, rect.right, rect.bottom, hMemDC, 0, 0, nX, nY,
: SRCCOPY);
: 작업 영역의 크기를 얻은뒤 그 크기만큼 그림을 화면에 출력하는 과정입니다.
: DeleteDC(hMemDC);
: EndPaint(hWnd, &ps);
: return 0;
:
:
:
:
:
:
:
: 윤상영 님이 쓰신 글 :
: : 제가 비트맵을 확대 축소하고 싶은데..
: : 비트맵을 메모리에 저장 및 빼는 방법을 모르겠읍니다..
: :
: : CreateCompatibleDC
: : SelectObject
: : BitBlt
: :
: : 등등을 이용해서 어찌하는것 같은데..
: : 감이 없네요..
: :
: : 고수님들 도움을 부탁드립니다.,
: : 이왕이면 예제도 부탁드립니다..(욕심이 과한가요?? -_-)
: :
: : 그럼 좋은 하루되세요..
|