Articles by " LoneRobot"

Shameless Plug Alert! – HitchHiker is being used at Volition Inc

Mar 31, 2010 by     No Comments    Posted under: DotNet, News, User Controls

It’s not often that you get an email from a maxscript legend like Jeff Hanna so I did have to do a double take at my inbox when it arrived. But as it transpired, Jeff had been looking to update one of the pipeline tools at games company Volition Inc.

Previously, the control used had been an ActiveX thumbnailer, but since the swap to X64 architecture, this had been made redundant. So Jeff informed me that he’d been looking for a dotnet alternative and wanted to use Hitchhiker. I implemented a couple of functionality requests and VPropShop4 is the result!

vPropShop_HitchHiker

VpropShop is an asset manager used at Volition Inc. It features a beta release of Hitchiker with added maxfile support. It is also able to capture a viewport thumbnail directly from the assembly, passing the maxscript call directly to max and then returning it as a dotnet image.

Thanks to Jeff for letting me use this, It’s always nice to find out the tools on LoneRobot.net are useful and helping artists and animators get their jobs done faster, giving them more time to do the really interesting stuff.

If you have done anything with Hitchiker (or another example of LR.net) whether its a simple viewer or a full asset browser please let me know, I’d love to post it.

There will be an update to Hitchhiker shortly showing the features above, plus enhanced thumbnail caching, and custom wildcard search parameters.

DotnetObject “LoneRobot.Child”

Mar 22, 2010 by     11 Comments    Posted under: Characters

I’d like to introduce the latest LoneRobot build – and it’s the one that I am most proud of.

VSBuild

He/She is due mid September and the beautiful Mrs.Robot is doing very well. I can only imagine that menu option 3 above will shortly become my life for the foreseeable future.

Floating Dialog Amnesty

Mar 16, 2010 by     9 Comments    Posted under: 3dsMax, DotNet, Maxscript, Tips and Tricks

WindowBoxUI.png

Ack, not another one of those posts where the only picture is a p*ss poor dialog with some stolen twinkly twink icons. My old art teacher would be despairing right now, and perhaps comforting himself by grinding a yellow ochre paste. Oh, how he loved that yellow ochre.

A situation existed recently where between working on the train and at work, I’d lost some dialogs on the screen space outside the resolution of my laptop monitor. A few of 3ds max’s window locations are stored in the ini file.

inipath = getMAXIniFile()
setINISetting inipath “MtlEditorPosition”  “MainWindow” “0 0 375 734”
setINISetting inipath “RenderVFBPosition”  “Position” “0 0”
setINISetting inipath “MaterialBrowserDialogPosition” “Dimension” “0 0 340 600”
setINISetting inipath “EnvironmentDialogPosition” “Dimension” “0 0 350 580”
setINISetting inipath “RenderDialogPosition” “Dimension” “0 0 360 750”
setINISetting inipath “mentalrayMessagesPosition” “Dimension” “0 0 600 400”
setINISetting inipath “RenderPresetsCategoryDialogPosition” “RenderPresetsCategoryDialogDimension” “0 0 210 280”

But most of the useful ones are not – like the layer manager and curve editor.

Unfortunately, you cant set their position like you can a rollout floater – it meant it was time for the programmatic equivalent of James Herriot putting on a large rubber glove.

Windows has a wealth of useful functions in the API that aren’t yet exposed to the dotnet framework – well not out the box, there is a managed API but I haven’t looked into this yet . However this doesn’t mean you cant use native API calls in a managed code environment. You can declare an API call in a dotnet assembly, and with a little coercion, get it working as you want.

pinvokelogoThe place to look for Win32 and API related stuff is pinvoke.net. This has loads of info about how to call these windows functions via the managed dotnet framework

From the site itself-

“The term PInvoke is derived from the phrase “Platform Invoke”. PInvoke signatures are native method signatures, also known as Declare statements in VB”

After looking on this site, I found the methods i was looking for.

  • GetWindowRect – Gets the size of the window from the window handle
  • GetWindowPlacement – Gets the current window location from the window handle
  • MoveWindow – Moves the window to a screen location

All that was need now was to convert these signatures into a format string ready to compile directly from 3dsmax, so that I could call these win32 functions from a dotnetobject within 3dsmax, and hopefully retrieve my missing windows.

When you compile a dll directly in 3dsmax, you are taking the code that you would write within the Visual Studio window and sending it to the compiler manually. So the flavour of managed language you are using dictates the compiler type.

The key to this class is to set up some custom properties so that the data coming out when used in 3dsmax is not too weird –  it is logical to return a drawing.point for a location, and a drawing.size for a window size for instance.

Getwindowrect uses a RECT structure (a structure is similar to a class) but creating one in max can be tricky. Mike Biddlecombe on CG Talk had posted a method to instantiate a structure in 3dsmax by adding it into an array and retrieving the first member. That was brilliant stuff and typical of the sort of stuff that Mike is figuring out the whole time. I decided in this case, that since I was compiling an assembly anyway, i’d just handle all of the structure business there and avoid any potential banana skins. So I added a width and height property to the RECT structure definition, meaning after it was instantiated, you can call the method from PInvoke and return a structure that has standard properties. Planning return values in your classes is something that helps in the long run – It makes deployment much easier in Max. I have found that since the VS interface is easier to debug, it’s a good place to do as much as you can there.

fn DialogWindowOpsClass =
(
source = “”
source += “Imports System.Runtime.InteropServicesn”
source += “Imports System.Drawingn”
source += “Public Class DialogWindowOpsn”
source += “Public Structure RECTn”
source += “Public left As Integern”
source += “Public top As Integern”
source += “Public right As Integern”
source += “Public bottom As Integern”
source += “Public ReadOnly Property Width() As Integern”
source += “Getn”
source += “Return right – leftn”
source += “End Getn”
source += “End Propertyn”
source += “Public ReadOnly Property Height() As Integern”
source += “Getn”
source += “Return bottom – topn”
source += “End Getn”
source += “End Propertyn”
source += “End Structuren”
source += “Public Structure POINTAPIn”
source += “Public x As Integern”
source += “Public y As Integern”
source += “End Structuren”
source += “Public Structure WINDOWPLACEMENTn”
source += “Public Length As Integern”
source += “Public flags As Integern”
source += “Public showCmd As Integern”
source += “Public ptMinPosition As POINTAPIn”
source += “Public ptMaxPosition As POINTAPIn”
source += “Public rcNormalPosition As RECTn”
source += “End Structuren”
source += “<DllImport(“user32.dll”)> _n”
source += “Public Shared Function MoveWindow(ByVal hWnd As System.IntPtr, ByVal x As Integer, ByVal y As Integer, ByVal nWidth As Integer, ByVal nHeight As Integer, ByVal bRepaint As Boolean) As Booleann”
source += “End Functionn”
source += “<DllImport(“user32.dll”)> _n”
source += “Public Shared Function GetWindowRect(ByVal hWnd As System.IntPtr, ByRef lpRect As RECT) As Booleann”
source += “End Functionn”
source += “<DllImport(“user32.dll”)> _n”
source += “Public Shared Function GetWindowPlacement(ByVal hWnd As System.IntPtr, ByRef lpwndpl As WINDOWPLACEMENT) As Booleann”
source += “End Functionn”
source += “Public Function WindowSize(ByVal Hwnd As System.IntPtr) As System.Drawing.Sizen”
source += “Dim LPRECT As RECTn”
source += “GetWindowRect(Hwnd, LPRECT)n”
source += “Dim WinSize As System.drawing.size = New System.drawing.size(LPRECT.Width, LPRECT.Height)n”
source += “Return WinSizen”
source += “End Functionn”
source += “Public Function WindowPosition(ByVal Hwnd As System.IntPtr) As System.Drawing.Pointn”
source += “Dim intRet As Integern”
source += “Dim wpTemp As WINDOWPLACEMENT = New WINDOWPLACEMENT()n”
source += “wpTemp.Length = System.Runtime.InteropServices.Marshal.SizeOf(wpTemp)n”
source += “intRet = GetWindowPlacement(Hwnd, wpTemp)n”
source += “Dim WinPoint As System.drawing.point = New System.drawing.point(wpTemp.rcNormalPosition.left, wpTemp.rcNormalPosition.top)n”
source += “Return WinPointn”
source += “End Functionn”
source += “End Class”

VBProvider = dotnetobject “Microsoft.VisualBasic.VBCodeProvider”
compilerParams = dotnetobject “System.CodeDom.Compiler.CompilerParameters”
compilerParams.ReferencedAssemblies.add “C:WindowsMicrosoft.NETFrameworkv2.0.50727System.drawing.dll”
compilerParams.GenerateInMemory = on
compilerResults = VBProvider.CompileAssemblyFromSource compilerParams #(source)

— this is very useful to debug your source code and check for referencing errors
if (compilerResults.Errors.Count > 0 ) then
(
errs = stringstream “”
for i = 0 to (compilerResults.Errors.Count-1) do
(
err = compilerResults.Errors.Item[i]
format “Error:% Line:% Column:% %n” err.ErrorNumber err.Line
err.Column err.ErrorText to:errs
)
MessageBox (errs as string) title: “Errors encountered while compiling VB code”
return undefined
)
return compilerResults.CompiledAssembly.CreateInstance “DialogWindowOps”
)

What this code does is make a class that can be instantiated in max and used to control the positions of the dialogs in the 3dsmax user interface, whether we can see them or not.

In order to call them though, we need an array of handles for the active max dialogs. Fortunately, Maxscript gives us a way of doing this –

UIAccessor.GetPopupDialogs()

The rest, was building an interface. I went for the datagridview – Its a complex user control and I am probably only scratching the surface of the sort of things you can do. Its designed for handling masses of complex data from data sources like sql databases but you can just use it like a listview. Its just got a few more options.

Maxscript also has methods for interacting with win32 functions, so it’s entirely possible that this could be achieved using that, but then that’d just be cheating, wouldn’t it?

download

Adding a post build event to Visual Studio

Mar 16, 2010 by     4 Comments    Posted under: DotNet

If you are developing dotnet tools for use in 3ds studio max, you will be used to a painfully slow method of evaluating your assemblies in max, unless you do something clever with dynamic compiling. Since the assembly cannot be unloaded after loading it you are forced to exit max, copy the assembly to the dll location and start max again.

I have sped this up slightly by adding a post build event to Visual studio, which means that on a successful build of the assembly, it automatically copies the dll to my Lonerobot folder (which is where I load all my custom assemblies from)

The procedure is pretty straightforward –

Right click the solution in the solution explorer

solutionwindow

Click Compile>Build events (the button at the bottom)

compile

In the textbox marked ‘Post build event command line’, I enter –

COPY "$(TargetPath)" "C:Program FilesAutodesk3ds Max 2010ScriptsLoneRobotClassLib"

postbuild

This will obviously be different for your assembly. This command should now copy the compiled assembly to the correct directory. Not revolutionary, but helpful me thinks.

We have all the time in the world

Mar 16, 2010 by     2 Comments    Posted under: Tips and Tricks

Time is commonly understood as something rather more than a linear pattern of execution. Many theoretical physicists believe in Einstein’s relativity theory which states that we are all experiencing a personal time relative to our current position in space. This intrapersonal time structure can curve and run parallel to others in space-time, potentially creating an indefinite number of alternate realities.

einstein

Einstein was obviously not a commuter, because he might have been able to spend a bit of this ‘relative’ time working out why I haven’t got any. So I’m well aware that my postings on lonerobot.net have been a little lapse as of late.

I will be adding as often as I can some maxscript hors d’oeuvres that will hopefully help with a few of the day to day things about using maxscript.

Perhaps it will grow into something sprawling and unstoppable, rather like an enormous platter of Ferrero Rocher at the Ambassador’s reception. And you will cry, “Oh Lonerobot, weev zis small snippets posting you are spoiling us no?”

That, or you’ll realise that the time you spent reading this can never be returned to you, in this reality or any number of alternate ones.