일지
유니티 화면 비율 고정 처리...14
niamdank
2021. 10. 15. 02:05
WinAPI의 WM_SIZING 오버 로딩을 통한 화면 비율 고정
구글링을 하다 보니 WinAPI의 WM_SIZING를 오버 로딩하여 화면 비율을 조정하는 코드가 존재했다.
오버 로딩 한 코드만 따로 가져와서 보면 다음과 같다.
winProc 오버 로딩
IntPtr wndProc(IntPtr hWnd, uint msg, IntPtr wParam, IntPtr lParam)
{
// Check message type.
// We are only interested in resize events, so ignore everything else.
if (msg == WM_SIZING)
{
// Get window size struct.
RECT rc = (RECT)Marshal.PtrToStructure(lParam, typeof(RECT));
// Calculate window border width and height.
RECT windowRect = new RECT();
GetWindowRect(unityHWnd, ref windowRect);
RECT clientRect = new RECT();
GetClientRect(unityHWnd, ref clientRect);
int borderWidth = windowRect.Right - windowRect.Left - (clientRect.Right - clientRect.Left);
int borderHeight = windowRect.Bottom - windowRect.Top - (clientRect.Bottom - clientRect.Top);
// Remove borders (including window title bar) before applying aspect ratio.
rc.Right -= borderWidth;
rc.Bottom -= borderHeight;
// Clamp window size.
int newWidth = Mathf.Clamp(rc.Right - rc.Left, minWidthPixel, maxWidthPixel);
int newHeight = Mathf.Clamp(rc.Bottom - rc.Top, minHeightPixel, maxHeightPixel);
// Resize according to aspect ratio and resize direction.
switch (wParam.ToInt32())
{
case WMSZ_LEFT:
rc.Left = rc.Right - newWidth;
rc.Bottom = rc.Top + Mathf.RoundToInt(newWidth / aspect);
break;
case WMSZ_RIGHT:
rc.Right = rc.Left + newWidth;
rc.Bottom = rc.Top + Mathf.RoundToInt(newWidth / aspect);
break;
case WMSZ_TOP:
rc.Top = rc.Bottom - newHeight;
rc.Right = rc.Left + Mathf.RoundToInt(newHeight * aspect);
break;
case WMSZ_BOTTOM:
rc.Bottom = rc.Top + newHeight;
rc.Right = rc.Left + Mathf.RoundToInt(newHeight * aspect);
break;
case WMSZ_RIGHT + WMSZ_BOTTOM:
rc.Right = rc.Left + newWidth;
rc.Bottom = rc.Top + Mathf.RoundToInt(newWidth / aspect);
break;
case WMSZ_RIGHT + WMSZ_TOP:
rc.Right = rc.Left + newWidth;
rc.Top = rc.Bottom - Mathf.RoundToInt(newWidth / aspect);
break;
case WMSZ_LEFT + WMSZ_BOTTOM:
rc.Left = rc.Right - newWidth;
rc.Bottom = rc.Top + Mathf.RoundToInt(newWidth / aspect);
break;
case WMSZ_LEFT + WMSZ_TOP:
rc.Left = rc.Right - newWidth;
rc.Top = rc.Bottom - Mathf.RoundToInt(newWidth / aspect);
break;
}
// Save actual Unity game area resolution.
// This does not include borders.
setWidth = rc.Right - rc.Left;
setHeight = rc.Bottom - rc.Top;
// Add back borders.
rc.Right += borderWidth;
rc.Bottom += borderHeight;
// Trigger resolution change event.
resolutionChangedEvent.Invoke(setWidth, setHeight, Screen.fullScreen);
// Write back changed window parameters.
Marshal.StructureToPtr(rc, lParam, true);
}
// Call original WindowProc function.
return CallWindowProc(oldWndProcPtr, hWnd, msg, wParam, lParam);
}
단순히 코드를 보면 메뉴바의 크기를 잘라내기 위해 AdjustWindowRect를 사용하는 대신 windowRect와 clientRect를 각각 가져와 크기의 차이를 구한 뒤 화면 크기를 조절하고 메뉴바의 크기만큼을 더해서 위치나 크기가 틀어지지 않도록 처리한 것 같다.
그런데 단순하게 코드는 이해가 되지만 어떤 식으로 오버 로딩을 한 것인지 이해가 되지 않아 한동안 이 부분을 분석해야 할 것 같다.