I think I got it figured out …
EDIT: changed it all again.
EDIT 2: added a windows implementation of wkwan’s idea (see comments)
The short way on Windows:
- parameters: master.width / master.height is the resolution we wanted to have
- Screen.width / Screen.height is what Unity is running atm.
This solution is used to convert screen-coordinate input into pixel-exact positions referring to a (master.width, master.height) - resolution.
[StructLayout( LayoutKind.Sequential )]
public struct POINT
{
public int X;
public int Y;
public static implicit operator Vector2( POINT p )
{
return new Vector2( p.X, p.Y );
}
}
[DllImport( "user32.dll" )][return: MarshalAs( UnmanagedType.Bool )]
static extern bool GetCursorPos( out POINT lpPoint );
public static void Init( PanoramaMaster master )
{
Vector2 inputCursor = Input.mousePosition;
// flip input Cursor y (as the Reference "0" is the last scanline)
inputCursor.y = Screen.height - 1 - inputCursor.y;
POINT p;
GetCursorPos( out p );
renderRegionOffset = p - inputCursor;
renderRegionScale = new Vector2( (float) master.width / Screen.width, (float) master.height / Screen.height );
Debug.Log( "Scale: " + renderRegionScale + "
Offset: " + renderRegionOffset + "
" );
}
Don’t do it like this:
Earlier I came up with the following function, which gets the offset of the gameView’s rendering region within its containing window’s client region. I.e. Unity, or the window around a stand-alone gameview. Then I found some nice WinAPI references to find the missing pieces (window position, size of decorations):
[DllImport( "user32.dll" )]
static extern int GetSystemMetrics( SystemMetric smIndex );
[DllImport( "user32.dll" )]
static extern IntPtr GetActiveWindow();
[DllImport( "user32.dll", SetLastError = true )]
static extern bool GetWindowRect( IntPtr hwnd, out RECT lpRect );
[StructLayout(LayoutKind.Sequential)]
public struct RECT
{
public int Left, Top, Right, Bottom;
public override string ToString()
{
return string.Format( System.Globalization.CultureInfo.CurrentCulture, "{{Left={0},Top={1},Right={2},Bottom={3}}}", Left, Top, Right, Bottom );
}
}
public enum SystemMetric : int
{
SM_CXSCREEN = 0, // 0x00
SM_CYSCREEN = 1, // 0x01
SM_CXVSCROLL = 2, // 0x02
SM_CYHSCROLL = 3, // 0x03
SM_CYCAPTION = 4, // 0x04
SM_CXBORDER = 5, // 0x05
SM_CYBORDER = 6, // 0x06
// [...] shortened ...
}
public static Vector2 PixelOffsetFromScreen()
{
System.Type T = System.Type.GetType( "UnityEditor.GameView,UnityEditor" );
EditorWindow gameview = EditorWindow.GetWindow( T );
Rect Pom = gameview.position;
System.Reflection.MethodInfo RenderRect = T.GetMethod( "GetMainGameViewRenderRect", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Static );
Rect ReRe = (Rect) RenderRect.Invoke( null, null );
RECT WinR;
GetWindowRect( GetActiveWindow(), out WinR );
int bw = GetSystemMetrics( SystemMetric.SM_CXBORDER );
int bh = GetSystemMetrics( SystemMetric.SM_CYBORDER );
int ch = GetSystemMetrics( SystemMetric.SM_CYCAPTION );
// try to retrieve the Window's client rect and its position on screen
Vector2 Res;
Res = new Vector2( WinR.Left + bw + Pom.xMin + ReRe.xMin, WinR.Top + ch + bh + Pom.yMin + ReRe.yMin );
return Res;
}
The final cut it needs: make it also work with a compiled game, where there’s no editor available …