<Windows API>
어제 복습
스크립트란? -> 지껄이다. 라는 뜻 – 어떤 것에 대한 설명
어제의 리소스처럼 어떤 형태를 글자로 표현하는 것을 스크립트 라고 한다.
프로그래밍 언어와 다른 부분은, 컴파일을 거쳐야 하는 프로그래밍 언어와 틀리게,
스크립트 자체가 바로 실행을 할 수 있도록 되어 있는 것으로 구분지을 수 있다.
단점 – 느리다. 번역을 해서 실행을 해야하니까.
장점 – 알아보고, 작성하기 쉽다.
이 중간지점에 있는 것이 자바 의 JVM (java virtual machine)
리소스를 작성할 때 자동생성되는 resource.h 는 소스코딩도 지가 알아서 해주니까
보통 손볼일이 없다.
IDR_MENU1 은, 헤더파일 열어보면 101 로 정의되어 있는데,
MAKEINTRESOURCE 로 정수 변환 ->
내가 변경을 한다고 해도, 헤더파일 내부에 정해놓은 규칙적인 이름(IDR_MENU1) 이
사라지진않는다. 쓰레기소스가 생겨버린다.
뭐 IDR_MENU1 지우면 되지만 어지간하면 안건드는게 좋음. 어지간하면
지어주는대로 쓰자. 수정하지말고 ㅋㅋ
근데 주석보면;; vs가 알아서 만들어준다. 와 지림;
메뉴를 누르면 WM_COMMAND 메시지가 발생.
이러한 메뉴에서 발생하는 메시지는 wParam 의 LOW 부분에서 추출된다.
File1_smart 는 그래도 남아있다
또한 새로운 메뉴를 또 생성했을 경우, 강제적으로 수정을 해줘도
건너뛰면서 코딩된다.
즉, 자동화의 장점과 단점을 동시에 가지고 있는거임
게다가 메뉴 이름을 바꾸면 관련된 소스네임도 당연히 다 바꿔줘야한다
...졸 귀찮 걍 안건드는게 낫겟다.
제 6장 그래픽
6-1-가. GDI 오브젝트
GDI(Graphic Device Interface)
- 화면, 프린터 등의 모든 출력 장치를 제어하는 윈도우즈의 핵심 모듈중 하나 이다.
- 출력을 위한 중앙 통제 센터
GDI Object
- 그래픽 출력에 사용되는 도구 (펜, 브러시, 비트맵, 폰트 등등)
- GDI 가 그래픽을 출력할때는 GDI 오브젝트를 사용.
ex) 선을 그릴 때 -> 펜, 면 -> 브러시 등등
6-1-나 스톡 오브젝트
Stock Object
- 윈도우가 기본적으로 제공하는 GDI 오브젝트
HGDIOBJ GetStockObject(int fnObject) 로 스톡오브젝트를 얻을 수 있다
(dc처럼)
색칠하는 기계가 있을 때, 무슨 색을 칠해! 하고 새 붓을 쥐어 줄 때
기존에 쥐고있는 default 붓은 내가 가지고와야지.
SelectObject 로 쥐고 있던 붓을 가지고 온다.
1) 브러시 변수 두 개 선언
2) My Brush 에 내가 원하는 붓을(회색) 얻어와서 담아준다(GetStockObject)
3) SelectObject 로 회색을 쥐어준 다음 기존에 쥐고있던(Default) 붓을 Old 에 백업
4) (회색)으로 사각형을 그린다.
5) Old_Brush 가 담고 있는 Default 색을 다시 쥐어준다.
와 같은 5단계의 과정을 거쳐 ‘색이 있는’ 사각형을 그릴 수 있었다
신기해 ^~^)/
이때 사용한 SelectObject 는
HGDIOBJ SelectObject(HDC hdc, HGDIOBJ hgdiobj); 이다.
- DC의 핸들
- GDI 의 오브젝트 핸들
DC에 해당 오브젝트를 선택, 그래픽을 출력시에 선택된 오브젝트를 사용 하고,
기존에 쥐고 있던 색(브러시)를 반환한다.
6-1-다. 색상
DOS에서 White, Yellow, Red 등의 매크로 상수를 색상으로 표현
이 매크로들의 실제값은 0~15 까지의 정수(Hexa)였다.
도스에서는 16색상만 사용할수 있었기 때문에 Windows COLORREF 라는 데이터형을 사용
typedef DWORD COLORREF;
부호없는 32BIT 크기의 정수형 8BIT 씩 빨간색, 초록색, 파란색의 농도를 나타내며,
상위 1BYTE 는 사용하지 않는다. 각 색상 요소는 1BYTE의 크기를 가짐.
0~255 의 농도 표현 가능 ->> 이를 조합하여 색상 하나를 표현한다.(RGB)
4BYTE 의 16 진수로도 표현이 가능하다.
|
B |
G |
R | |||||||||||||||||||||
|
1 |
1 |
1 |
1 |
1 |
1 |
1 |
1 |
0 |
0 |
0 |
0 |
0 |
0 |
0 |
0 |
0 |
0 |
0 |
0 |
0 |
0 |
0 |
0 |
=> |
0x FF 00 00 00 |
|
|
예를 들어서 파란색을 위와 같이 표현 할 수도 있다.
근데 이런건 초보자가 하기 힘드니까 보편적으로 RGB매크로 함수를 사용.
#define RGB(r,g,b)((CLOLORREF)(((BYTE)(r)|(WORD)((BYTE)(g))<<8))|(((DWORD)(BYTE)(b))<<16)))
비트연산자를 활용, 걍 밀어준다 정도만 생각하자;; 캐스팅이 너무 많지만 어차피
사용법은 간단하다.
ex)
RGB매크로로 RGB(255,111,000) 과 같이 쉽게 표현이 가능하다.
GetRValue, G,B매크로를 활용하여 각각의 값을 추출할 수도 있다.
6-1-라. 펜
- 펜은 선을 그을 때 활용되는 GDI 오브젝트 이며, 사용 함수는 다음과 같다.
HPEN CreatePen(int fnPenStyle, int nWidth, COLORREF crColor);
- fnPenStyle 점의 모양을 지정한다. 실선, 점선, 일선, 쇄선 등의 표현이 가능하다.
- nWidth 선의 폭을 지정한다. 기본은 1부터 조절 가능. 단, 0일 경우는 무조건 1로 정정
- crColor 선의 색상을 지정, COLORREF Type 이기 때문에 RGB 매크로 함수 사용
- return -> 위의 인수들로 인해 새로 만들어진 팬의 핸들이 리턴 된다.
1) CreatePen 호출 하여 펜을 만든 뒤 MyPen 에 담는다.
2) SelectObject 로 기본 펜 설정을 백업, MyPen을 적용
3) 사각형 생성후
4) 다시 기본펜 으로 복구
5) 생성된 MyPen 은 동적 할당처럼 반드시 삭제해주자!
DeleteObject를 사용할 경우, 현재 사용하고 있는 펜에 대해서 삭제가 되지 않으니,
반드시 Old_Pen 으로 백업한 기본값으로 돌려놓고 삭제를 하도록 하자.
SelectObject(hdc, OldPen);
DeleteObject(MyPen); 잊지말자!
다음과 같은 소스로 줄일 수도 있다.
DeleteObject(SelectObject(hdc,OldPen); <- 반환값을 인자로 받아서 삭제하겠다는거;
기존에 다 해오고 해봤던 부분이다.
위에서 글로 표현한 것을 그림으로 정리해놓은 부분이다.
6-1-마. 브러시
- 위의 예제에서도 활용 했듯이 브러시는 ‘면’ 의 채색 해준다.(붓!)
펜에서 했던것과 매한가지이지만 짚고넘어가보자.
HBRUSH CreateSolidBrush(COLORREF crColor);
HBRUSH CreateHatchBrush(int fnStyle , COLORREF clrref);
첫 번째 함수의 경우는 단색의 브러시
두 번째 함수는 색상, 무늬 또한 지정이 가능하다.
예제로 사용 예를 확인해보자.
구분을 위해 비슷한 소스끼리 붙여놨더니 정말 똑같다;
걍 그렇구나! 하고 이해했음 넘어가자
6-1-바. Old 의 의미.
GDI 오브젝트를 사용할때마다 항상 같은 타입의 Old 핸들을 선언, SelectObject 로 선택 시
이전 선택 객체를 Old에 백업해놨다가 파괴전에 돌려주는 과정을 왜 하나?
case WM_LBUTTONDOWN:
hdc = GetDC(hWnd);
for(i = 0;i<1000;i++)
{ hPen = CreatePen(PS_SOLID,2,RGB(255,0,0)
SelectObject(hdc,hPen); }
ReleaseDC(hWnd,hdc);
return 0; 이라는 소스가 있다.
1번 클릭하면 1000번 동안 펜을 생성하고, 해당 Pen을 쥐어주는 소스인데
이 프로그램을 한참 실행하다보면,
리소스 영역이 바닥나서 펜,폰트,브러시 등의 GDI오브젝트의 생성이 불가능해진다.
GDI 오브젝트를 저장하는 리소스 영역은 메인 메모리와 다른 특수영역인데, 이 영역의
크기가 크지않고 오브젝트의 과다한 생성 시에는 금방 다 차버린다.
그리기에 사용할 도구를 만들지 못하므로 화면 출력이 제대로 되지 않는다는 것.
그렇기 때문에 위의 소스를 보안하려면
case WM_LBUTTONDOWN:
hdc = GetDC(hWnd);
for(i = 0;i<1000;i++)
{ hPen = CreatePen(PS_SOLID,2,RGB(255,0,0)
SelectObject(hdc,hPen);
DeleteObject(hPen) ; }
ReleaseDC(hWnd,hdc);
return 0; 와 같이 해야하지만, 이 소스에도 마찬가지로 문제가 발생한다.
DC에 속해있는, 오브젝트는 삭제할 수가 없다 – 펜 없이 선을 어떻게 그음?
즉, DC는 어쨌든 하나의 펜,브러시등 기본값을 지니고 있어야한다
그렇다면 SelectObject 함수를 활용, 할때마다 hPen -> 다른 펜 으로 바꿔주고
(스톡 펜) (새로운 스톡펜)
hPen을 지운다면 어떨까?
그런 소스는 범용성이 부족해진다. 즉, 반드시 스톡펜(hPen)을 DC가 쥐고 있다면
확신이 있어야 가능하며, 작은소스라면 몰라도 큰 , 많은 소스에서 그런 방식으로
소스를 짜다보면 결국 위험성을 무시할 수 없을 것이다.
(다른 함수로 가져간다거나, 앞뒤로 다른 오브젝트를 쓰는 코드가 된다면?)
그렇기 때문에 Old Pen 변수를 생성하여 저장을 하고, 복구를 해주는 것이다.
10000번간 랜덤 위치에, 랜덤한 색상으로 선을 긋는 소스이나,
1,2 번째 인자로 온 값이 참이냐 거짓이냐를 판별하여 DC의 pen 선택 해제, 삭제를
수행 하거나 하지 않는 소스 이다.
1번은 문제 없이 수행, 2번의 경우는 그냥 잘되긴 하는거 같다
3번의 경우는 하다보면 선이 좀 얇게 그어진다. 기분탓인지 다른 작업들이 버벅거리기도 했다;
이러한 부분을 감안하여 올바른 소스를 코딩하도록 노력하자.
6-1-사. 투명 오브젝트
NULL_BRUSH(HOLLOW_BRUSH) 와 NULL_PEN 은 뭐하는 거지?;;
위에서 사각형에 색을 넣을때는, Pen 과 Brush를 동시에 사용했었는데,
이중 하나를 그리고 싶지 않을 때(외각선이 없는 사각형이라던가) 투명 오브젝트를
선택해놓고 그리기를 한다. 이것을 예제로 확인해보자.
각각 색이 있는 브러쉬 펜, 브러시 NULL, 펜 NULL을 사용하여, 각각 원을 그려보았다
6-2 그리기 모드
6-2-가. 흑백에서의 그리기모드
- 뭔가 그려져있을 때, 위에 다른 무언갈 출력하면 덮어쓴다.
- 그리기모드 : 도형이 그려질 때 원래 있던 그림과 새로 그려지는 그림과의 관계 정의!
원본과 그림과 각각 copy, or, and, xor 의 결과를 확인 할 수있다.
6-2-나. 그리기 모드의 종류
- 윈도우즈의 Default 그리기 모드는 R2_COPYPEN 모드 이다.
(위의 그림에서 보이듯이 기존의 그림을 지우고, 새로 덮어그리는 개념)
이러한 모드를 변경하는 함수가 존재한다.
int SetROP2(HDC hdc, int fnDrawMode);
int GetROP2(HDC hdc);
- 첫 번째는 하도 자주 쓰는, 그리고자 하는 곳의 DC 핸들이다
- 두 번째 인수는 각각의 모드가 존재한다.
그리기 모드 |
설명 |
R2_BLACK |
항상 검은색 |
R2_WHITE |
항상 흰색 |
R2_NOP |
아무런 그리기를 하지 않는다. |
R2_NOT |
원래의 그림을 반전 시킨다. |
R2_COPYPEN |
원래의 그림을 덮어버리고 새 그림을 그린다(기본) |
R2_NOTCOPYPEN |
새 그림을 반전시켜 그린다. |
R2_NOTXORPEN |
XOR 의 결과의 반대값을 써 넣는다. |
R2_MERGEPEN |
OR 연산으로 겹치는 부분만 그린다. |
R2_MASKPEN |
AND 연산으로 겹치는 부분만 그린다. |
R2_XORPEN |
XOR 연산으로 겹치는 부분만 반전시킨다. |
6-2-다. 그리기모드
CM의 보충설명!
SetROP 에 인자루 R2_NOT이 오면 반전이 된다.
버튼을 눌려서 (wm_Lbottondown) 하면 초기 좌표가 잡히고 -> move 함으로 인해서
반전, 선이 그려지고 바뀐점을 Old 좌표 x,y 에 대입
두 번째로 무브가 되면서 기존의 선이 지워진다(반전) 그 상태에서 새로 찍힌 좌표를
기준으로 다시 선이 그려진다. 즉, 마우스가 움직이는대로 선이 따라다니는 것처럼 보인다.
예제)
마우스가 움직였을 때 쥐고있는 좌표 sx,sy 까지 그린다.
단, R2_NOT 이기 때문에, 움직이는 점이 달라질때마다 기존의 선은 삭제,
새로 움직인 새 좌표 sx,sy 와 처음의 클릭지점(oldx,oldy)의 선이 새로 생성,
마우스를 누르고 있는 동안 이것이 유지되며 선을 수없이 지우고, 생성하면서
오로지 한 선 만이 현재의 마우스 위치를 따라다니는 것처럼 보이게 동작한다.
버튼 상승과 함께 그리기모드는 거짓이 되며, 마지막에 클릭한 부분에서 한 선이 남게 된다.
(또한 여러개의 선을 그을 때, 선이 겹치면 NOT 인수 때문에 선이 지워지는걸 확인할 수 있다)
또한, 아얘 SetROP 함수를 주석처리 해버리거나, R2_BLACK 설정을 해버리면,
기존의 선이 지워지지 않기 때문에
과 같이 출력된다.
6-3 비트맵
6-3.가 비트맵 출력
그리기 함수를 이용해서 그려야 하는 경우도 있지만,
사진같은 이미지를 그리기 함수로 그리는 것은 생각만해도 엄청난 비효율이다.
그럼, 사진 File을 프로그램에서 가져오는 것을 확인해보자.
여태까지 해왔던 리소스 사용과 동일하다.
실행결과
다시 정줄잡고 6-3-나. 메모리 DC
- 윈도우즈는 비트맵을 곧바로 화면 DC 로 출력하는 함수는 없으니까 음슴체로 가겠음.
왜 없냐면, 비트맵 자체가 크기가 큰 데이터 덩어리 -> 출력 속도가 형편없음
즉, 파일을 읽고 싶으면 반드시 열기, 읽기, 닫기의 과정을 거쳐야 함.
마찬가지로 비트맵도 워낙 대용량이라 직접출력하는 제공하지 않으며,
약간의 준비를 거친 후 출력해야 한다. 이렇게 준비를 거친 후 출력하면
여러번 출력시의 전송하기만되면 출력 속도가 빠르고 예비 동작을 미리 취해놓을 수 있음
비트맵은 화면으로 직접 출력할 수 없고, 반드시 메모리DC에 미리 준비후 사용한다.
메모리 DC – 화면 DC와 동일한 특성을 가지며, 그 내부에 출력 표현을 가진 메모리 영역
메모리에 있기는 하지만 화면 DC에서 사용할 수 있는 모든 출력을 메모리 DC도 할 수 있다
그래서, 메모리 DC에 먼저 그림을 그린 후 사용자 눈에 그려지는 과정은 보여주지 않고
그 결과만 화면으로 고속 복사하는 방법(더블 버퍼링)을 많이 사용한다.
비트맵도 일종의 GDI 오브젝트 이지만, 화면 DC에는 선택할수 없으며, 메모리 DC 만이
비트맵을 선택할수 있다.
메모리 DC 생성 함수
HDC CreateCompatibleDC(HDC hdc);
- 인수로 화면 DC의 핸들을 주면, 이 화면 DC와 동일한 특성을 지닌 DC를 메모리에 만들어
그 핸들을 리턴한다. (위의 소스에서는 MemDC가 반환을 받는 쪽, hdc 가 인수)
동일한 특성(호환됨) -> 색상수, 색상면또한 모두 동일
이렇게 생성된 메모리DC에 비트맵을 읽어와 메모리 DC에 선택한다.
다른 GDI 오브젝트와 같이, SelectObject 함수를 사용, LoadBitmap 함수를 사용해 읽어온다.
HBITMAP LoadBitmap(HINSTANCE hInstance, LPCTSTR lPBitmapName);
- 1번째 인수는 비트맵 리소스를 가진 인스턴스의 핸들
- 2번째 인수는 비트맵 리소스의 이름
6-33-다. BitBlt (빗블릿)
DC간의 영역끼리 고속복사를 수행하는 함수
BOOL BitBlt(HDC hdcDest, int nXdest, int nYDest, int nWidth, int nHeight, HDC hdcSrc, int nXSrc, int nYSrc, DWORD dwRop);
- 1번째 인수 : 복사대상의 DC
- 2~5 째 인수 : 복사 대상의 XYWH(가로세로길이 폭 높이)
- 6번째 인수 : 복사원의 DC hdcSrc
- 7,8 번재 인수 : nx,ySrc 는 복사원의 좌표이되 BitBlt 은 비트맵의 크기를 변경하지 않고 복사를 수행하기 때문에, 폭과 높이는 복사 대상에서 한번만 지정하고 복사원에서는 그 값을 그대로 사용. 소스를 보면 MemDC 의 0,0 위치를 복사대상의 0,0 위치에 폭 200, 높이 200 만큼 복사하고 있음을 확인 할 수있다.
- 9번째 인수 : 래스터 연산방법을 지정, SRCCOPY (우리 소스에서 사용) 복사원을 그대로
복사대상으로 복사하였다. 다음과 같은 옵션이 존재한다.
그리기 모드 |
설명 |
BLACKNESS |
대상영역을 검정색으로 가득 채운다. |
DSTINVERT |
화면을 반전시킨다. |
MERGECOPY |
소스 비트맵과 대상 화면을 AND 연산 |
MERGEPAINT |
소스 비트맵과 대상 화면을 OR 연산 |
SRCCOPY |
소스 영역을 대상 영역에 복사 |
WHITENESS |
대상영역을 흰색으로 채운다. |
CM 강의.
용량이 크면 클수록 화면은 느리게 그려진다.
교재에 나와있듯이 사용자에게 화면이 그려지는 과정은 막 번쩍거리고 하나도 안깔끔하다
그래서 반드시 메모리 DC를 사용해야 한다.
게임의 경우에도 무효화영역을 사용하면서,
모든게 끝났을 때 다시 그리는 -> 메모리 DC 방식을 사용한다.
윈도우가 사용하는 영역의 정보를 똑같이 복사, 화면DC (MemDC) 를 생성
우리는 메모리DC에 비트맵 파일을 적재, 이것을 읽어들인다.
즉, HDD에 있는 비트맵을 읽어들이는 LoadBitmap 함수는 그 처리시간이
비트맵의 크기만큼 느리다. 무지 걸림 덜덜덜
빛의 3대 구성요소 RGB 빨녹파 빛을 섞으면 밝아진다. - 빛의 3원색
1 픽셀을 확대해보면
즉,
R |
8 bit |
0~255 |
G |
8 bit |
0~255 |
B |
8 bit |
0~255 |
즉, 1024 * 768 의 화면 해상도 라면 *3 해서 => 2,359,296 즉, 2.25 mbyte 가
화면 하나의 비트맵 이미지 크기 이다.
자, 이게 동영상으로 가면 더 골치아프다. 초당 24프레임만 적용해도
소리 없이 용량 정하면 무시무시해진다.
이러한 것들중 불필요하거나 구분하기 힘든 영역을 잘라내고 남는 영역을 가지고 만들어서
용량을 줄이는 (압축) 방식이 종류에 따라서 avi, mp4 등등 의 방식이다.
동영상에서도 그와 동시에 무효영역을 지정하여 다시 부담을 줄이려고 노력한다.
(마우스 클릭했을 때 화면이 일시적으로 깨지는 현상이 생기는 이유)
비트맵이 용량이 큰 이유는, 원본 (아무런 수정을 거치지 않은) 이기 때문이다.
CDP가 흔들리면 소리가 끊기는 이유- 용량이 크니까(WAV) 메모리를 통째로 들어서
출력이 힘들다. 일부씩 올려서 출력하는데 통 튀면 못읽어들여서 중간에 노래재생이 끊어지는거
mp3 는 용량이 작기 때문에 한곡 통짜로 들어서 메모리에 적재후 출력하기 때문에
그런 현상이 없는 것이다.
비트맵도 Header + Data 의 구조이다.
2.25 mb + 헤더 File 의 크기가 나온다.
또한, 저장할 때, 24bit BitMap 8bit *3 의 구조인 것을 확인 할 수 있다.
두환이행님 피쳐링??
시험때문에 죄송합니다 다음에 열심히하도록 하겠습니다!!
'코스웨어 > 14년 스마트컨트롤러' 카테고리의 다른 글
20140923 일일업무보고서 11번 문대영 (4) | 2014.09.23 |
---|---|
20140919_일일업무보고_9번 김해성 (6) | 2014.09.20 |
20140918 일일보고서 출석번호8번 김진철 (8) | 2014.09.18 |
20140917 일일보고 7번 김재성 (9) | 2014.09.17 |
2014.09.15 출석번호 5번 김상엽 -업무일지 수정 (8) | 2014.09.15 |
2014.09.12 업무일지] 김대희 (10) | 2014.09.12 |
[2014.09.11 업무일지] 고한솔 (9) | 2014.09.11 |
2014.09.04. 업무보고서 출석번호22 허수웅 (6) | 2014.09.05 |