ABOUT ME

-

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

     

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

    댓글

Designed by Tistory.