원인을 찾아보았더니, 마우스의 WM_MOVE 메세지 처리시에 너무 많은 Event가 호출이 되어서 프리징이 걸리는 것 같다. 마우스 포지션 부분을 주석처리 하였더니 에러가 나지 않는 것으로 보아 그게 맞는 것 같다.
수정하기 위해서는 2가지 방법이 있다. 첫번째는 위치값을 큐에 넣지 않고 바로 메모리에 반영하도록 하는 방법이 있고, 두번째는 큐의 크기를 제한하도록 하는 것이다. 2가지 방법을 모두 시행해야 겠다. 일단 MouseMove는 첫번째 방법으로 수정하자. 그리고 찾아보니 키 메세지에 해당 키가 이전에 눌렸는지 여부를 알려주는 비트가 존재하고 있었다.
내가 억지로 만든 PostUpdate 등을 하지 않더라도 KeyDown, KeyUp 처리를 32, 31 번째 비트를 가지고 처리를 할 수 있었다. 그래서 문제점 수정과 함께 키 이벤트에 대해서도 수정을 해보고자 한다.
그러면 32번째, 31번째 비트에 접근하려면 어떻게 해야할까?
lParam은 4바이트 짜리이므로 16진수로 표현하면 16진수 한자리 숫자당 4비트, 2개면 1바이트를 표현할 수 있다. 즉 2 * 4 = 8이므로 8자리 수가 될 것이다. --> 0x00000000
그러면 이제 16진수의 한자리수에 대해 살펴보자. 0~15까지 숫자가 가능한데,
0인 경우는 모든 자리수가 0이니 의미없고,
1인경우는 0001, 2인 경우는 0010, ... 8인경우 1000이 된다.
즉,
32번째 비트가 1인지 판별하려면 lParam & 0x80000000 을 하면 될 것이고,
31번째 비트가 1인지 판별하려면 lParam & 0x40000000 을 하면 된다.
LRESULT Input::MessageHandler(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
switch (message)
{
case WM_KEYDOWN:
{
unsigned char keycode = static_cast<unsigned char>(wParam);
//키가 이전에 눌려있을 경우 -> pressed
if (lParam & 0x40000000) OnInput(Event(Event::Type::Key, Event::State::pressed, keycode));
//키가 처음 눌린 경우 -> down
else OnInput(Event(Event::Type::Key, Event::State::down, keycode));
return 0;
}
...
이렇게 IsKeyDown과 IsKey를 따로 처리할 수 있게 되었다.
KeyUp의 경우는 굳이 Released와 구분할 필요가 없는 것 같다. 어차피 한번 호출되는데. Event도 다시 재설계 해야겠다.
마우스 이벤트와 키보드 이벤트의 차이점은 마우스에는 마우스 좌표값 등등이 포함되며, 키보드의 경우 문자 입력이 존재한다는 점이다. 그러므로 마우스와 키보드의 이벤트도 분리해야 할 것이다.
그리고 KeyState는 KeyDown, Key, KeyUp, InValid 4가지로 두도록 한다.
다만 문제점이 하나 있는데, KeyDown과 Key, KeyUp, Invalid 상태를 저장하는 버퍼가 있어야 한다는 것이다.
그냥 bool로 Pressed, Released를 하였을 경우 해당 프레임에서 IsKeyDown() 함수를 호출하였을 때 어떻게 현재 키가 딱 눌렀을 타이밍이며 동시에 눌려 있도록 하겠는가? 결국 KeyDown여부 판정을 위한 bool, 키 눌림 떼임만을 판정하는 bool, KeyUp 판정을 위한 bool 총 3가지의 bool 배열이 필요하다.
이를 단순히 bool[3] 이렇게 배열로 선언하기 보단, 다음과 같은 컨테이너를 사용해보고자 한다.
std::bitset
https://ko.cppreference.com/w/cpp/utility/bitset
std::bitset - cppreference.com
bitset 클래스 템플릿은 고정된 크기의 N 비트 순열을 표현할 수 있다. 표준 논리 연산자로 Bitset을 다룰 수 있으며, 문자열 및 정수로 전환하거나, 문자열 및 정수로 부터 전환될 수 있다. bitset은 CopyConstructible와 CopyAssignable의 요구조건을 충족한다. [편집] 템플릿 인자 N - 저장공간으로 할당할 비트의 갯수 [편집] 멤버 형식 비트에 대한 참조자를 가리키는 프록시 클래스 (class) [편집] 멤버 함수
ko.cppreference.com
바이트가 아닌 비트를 저장하기 위한 컨테이너인데, 내부적으로 어떻게 구현했는지는 명확히 알 수 없지만 char 같이 1바이트 짜리 공간을 기준으로 8비트를 넘게 쓰게 되면 vector 처럼 확장하는 식이지 않을까 한다. 어쨌든 bool로 하였을 때보단 공간이 절약될 것이다.
bool states[3] --> std::bitset<3> states;
라고 생각했지만 테스트 해보니 bitset의 기본 크기가 4바이트로 나온다. 즉 아까 lParam과 같은 크기로 총 32개의 비트가 default이다. 즉, 키가 256개나 있는 keyboard는 bitset을 쓰는 게 효과적이지만 mouse는 왼, 오, 휠 3가지 밖에 없기 때문에 bitset를 쓰기 보단 bool 배열을 쓰거나 char를 가지고 지지고 볶는 게 차라리 효과적이다. mouse의 경우 공부할 겸 그냥 char를 가지고 비트연산을 하려고 한다.
'진행과정 기록 > GameEngine' 카테고리의 다른 글
20200131 Texture, SamplerState (0) | 2020.01.31 |
---|---|
20200130 Input class - Wheel, Mouse Raw Input (0) | 2020.01.30 |
20200128 Camera, imgui (1) | 2020.01.28 |
20200122 Vertex, InputLayout (0) | 2020.01.22 |
20200121 enum value를 template parameter로 사용하려면...? (0) | 2020.01.21 |