일지

유니티 화면 비율 고정 처리...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를 각각 가져와 크기의 차이를 구한 뒤 화면 크기를 조절하고 메뉴바의 크기만큼을 더해서 위치나 크기가 틀어지지 않도록 처리한 것 같다.

 

그런데 단순하게 코드는 이해가 되지만 어떤 식으로 오버 로딩을 한 것인지 이해가 되지 않아 한동안 이 부분을 분석해야 할 것 같다.