Dec 20 2012

3ds Max Viewport Resizeing and Capturing explained

So i recently was asked by a fellow artist, how to properly re-size the view-ports for making previews.
it was something I had been meaning to look into but had avoided due to some bad experience i had while attempting to write a better preview tool 8 years ago (max 5) working at Digital Dimension on the Blade Trinity project.
Anyway it seems many years have passed now, and with the introduction to dotNet in maxscript some one has figured out i good way to control the size of the view port with out causing major distortion.

anyway I’ve put a simple structure that make the method of capturing a view port much simpler using some technique that i found on this cgtalk thread while i was doing my research.

the things to pay attention here is how to compile c# code at run time in order to expose the function SetWindowPos that can be found in the user32.dll

struct viewPortPreviewTools
(
	fn getViewPortAssembly =
	(
		source = "using System;\n"
		source += "using System.Runtime.InteropServices;\n"
		source += "using System.Text;\n"
		source += "class assembly\n"
		source += "{\n"
		source += " [DllImport(\"user32.dll\")]\n"
		source += " public static extern bool SetWindowPos(IntPtr hWnd, int hWndArg, int Left, int Top, int Width, int Height, int hWndFlags);\n"
		source += " [DllImport(\"user32.dll\")]\n"
		source += " static extern bool GetWindowRect(IntPtr hWnd, out RECT rect);\n"
		source += " public struct RECT\n"
		source += " {\n"
		source += " public int Left;\n"
		source += " public int Top;\n"
		source += " public int Right;\n"
		source += " public int Bottom;\n"
		source += " }\n"
		source += " public int[] getWindowRect(IntPtr hWnd)\n"
		source += " {\n"
		source += " RECT rect;\n"
		source += " if ( GetWindowRect(hWnd, out rect) )\n"
		source += " {\n"
		source += " return new int[] { rect.Left, rect.Top, rect.Right - rect.Left, rect.Bottom - rect.Top };\n"
		source += " }\n"
		source += " return null;\n"
		source += " }\n"
		source += "}\n"

		csharpProvider = dotnetobject "Microsoft.CSharp.CSharpCodeProvider"
		compilerParams = dotnetobject "System.CodeDom.Compiler.CompilerParameters"

		compilerParams.GenerateInMemory = true
		compilerResults = csharpProvider.CompileAssemblyFromSource compilerParams #(source)
		assembly = compilerResults.CompiledAssembly.createInstance "assembly"
		assembly
	),
	fn setwindowpos hWnd hWndArg Left Top Width Height hWndFlags =
	(
		ass = getViewPortAssembly()
		ViewHwnd = (dotnetobject "system.intptr" hWnd)
		ass.SetWindowPos ViewHwnd hWndArg Left Top Width Height hWndFlags 
		return true
	),
	fn getSuperViewportDib w:renderWidth h:renderHeight mult:1.0 displayImage:false  =
	(
		w = w * mult
		h = h * mult
		ViewHwnd = for w in (windows.getChildrenHWND #max) where w[4] == "ViewPanel" do exit with w[1]
		if act = (viewport.numViews != 1) do max tool maximize
		setwindowpos ViewHwnd 0 0 0 w h 0
		completeRedraw()
		img = (gw.GetViewportDIB())
		hwnd = windows.getmaxhwnd()
		WM_EXITSIZEMOVE = 0x232
		windows.sendmessage hwnd WM_EXITSIZEMOVE 0 0 -- force to update views client area
		if act do max tool maximize
		completeRedraw()
		if displayImage then display img
		img
	)

)

after sourcing in this code capturing the viewport in any size should be a simple as running the following code

vPPT = viewPortPreviewTools()
img = vPPT.dibFn mult:1 displayImage:True

i would like to thank all those involved in the cgtalk thread. this is one of those things that with out their contribution i could not have put together..
allot of the code here was taken from Lo and DenisT’s examples.

Leave a Reply