Apr 4 2013

3dsmax .Net and the windows environment

so i have never been a big fan of tying my tools to windows environment..
but the reality is that people do this all the time…
at some point when trouble shooting a script plugin or in my case BlurPython qt deployment you are going to have to see what the current windows environment looks like inside of the max session, which unfortunately can be very different from what the windows environment looks like to the current session of windows and other apps..
anyway.. i put small snippet togather that build on the previous hashTable (.net dictonary) example, that allows us to not only print the windows environment variables visible to max, but also returns a hash table that we could use refer to the values at a later time..
here’s the good stuff..

fn getHashKeys hash =
(
    --spit the posible keys out
    DNArray = dotNetObject "System.string[]" hash.keys.count
    hash.keys.copyTo DNArray 0
    keys = for i = 1 to hash.keys.count collect (DNArray.get (i-1))
    keys
)

fn printWindowsEnv =
(
    Environment = dotNetClass "System.Environment"
    env = Environment.GetEnvironmentVariables()
    keys = getHashKeys (env)
    sort keys
    for k in keys do format "%=%\n" k env.item[k]
    env
)
printWindowsEnv()

give it a go! see what it prints for you!


Apr 2 2013

Python lambda functions (late to the party?)

So, I’m sure I’m not the only guy that’s been working late at night trying to fix some python code on some pipeline tool written by someone else that stumble into a “something = lambda x: self.blahBlah(x)” line and was like, WTF is this lambda stuff?? well like usual I’m late to the party, and I’m sure this is something most python programers will laugh at me for, but here’s a good tutorial that help me understand what his method was all about… I’m not sure that the lambda is something i couldn’t live with out but it seems like a neat way of making wrappers for functions with a single line of code..
Enjoy the link..
http://www.blog.pythonlibrary.org/2010/07/19/the-python-lambda/


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.


Dec 12 2012

dotNet DataGridView


So doing some work today i ran into a dotNet widget that believe it or now i have never used before.. i spend some time trying to dis cypher it and i must say it look very promising :D!!

in this snippet I’m creating a data grid with 3 columns a check box, text, and a drop box.. then i’m populating them with unique values..

the idea of having a listView where you can embed other widgets is very exiting in my opinion.. and this one is rather straight forward in use…

if you could handle parenting that the one in QT i would marry it in a hart beat πŸ˜›

any way.. i’ll drop some more notes later but for now.. here’s a quick snippet..

 

 

fn arrayToDotNet mArray = 
(
	netA = dotNetObject "System.String[]" mArray.count
	for i=1 to mArray.count do 
	(
		str = dotNetObject "System.String" mArray[i]
		indx = dotNetObject "System.Int32" (i-1)
		netA.SetValue str indx
	)
	netA
)
fn setDotNetWidgetColor dNObj =
(
	ClrBackGround = ((colorMan.getColor #window)*255)	
	ClrForeGround = ((colorMan.getColor #text)*255)
	dNObj.backcolor = dNObj.backcolor.FromArgb ClrBackGround.x ClrBackGround.y ClrBackGround.z
	dNObj.forecolor = dNObj.forecolor.FromArgb ClrForeGround.x ClrForeGround.y ClrForeGround.z
)
rollout testRo "yo" width:600
(
	dotNetControl dgv "System.Windows.Forms.DataGridView" height:200
	on testRo open do
	(
		--init basic dataGrivView settings
		setDotNetWidgetColor dgv
		dgv.AllowUserToAddRows = false
		dgv.AutoSize = true
		dgv.AutoSizeColumnsMode = dgv.AutoSizeColumnsMode.Fill
		dgv.ShowEditingIcon = dgv.RowHeadersVisible = true
		dnSelectionMode = dotNetClass "System.Windows.Forms.DataGridViewSelectionMode"
		dgv.SelectionMode = dnSelectionMode.FullRowSelect 
		--create some colum data
		colAr = #()
		append colAr #(#bool,"On?",false,#Right)
		append colAr #(#text,"hey there guy!",true,#Right)
		append colAr #(#opt,"list of shit...",false,#Right)
		--use the column data to proceduraly create colums based on the data types
		for col in colAr do
		(
			dnNewColumn
			case col[1] of
			(
				(#Text):dnNewColumn = dotNetObject "System.Windows.Forms.DataGridViewTextBoxColumn"
				(#Bool):dnNewColumn = dotNetObject "System.Windows.Forms.DataGridViewCheckBoxColumn"
				default:dnNewColumn = dotNetObject "System.Windows.Forms.DataGridViewComboBoxColumn"
			)
			dnNewColumn.HeaderText = col[2]
			dnNewColumn.ReadOnly = col[3]
			dnAlignment = dotNetClass "System.Windows.Forms.DataGridViewContentAlignment"
			case col[4] of
			(
				#Right:		dnNewColumn.DefaultCellStyle.Alignment = dnAlignment.MiddleRight
				#Center:	dnNewColumn.DefaultCellStyle.Alignment = dnAlignment.MiddleCenter
				#Left:		dnNewColumn.DefaultCellStyle.Alignment = dnAlignment.MiddleLeft
				default:	dnNewColumn.DefaultCellStyle.Alignment = dnAlignment.MiddleLeft
			)
			--setDotNetWidgetColor dnNewColumn.style
			dgv.columns.add dnNewColumn
		)

		--move on to adding actuall values
		----create value array structure
		valueAr = #()
		for i = 1 to 10 do
		(
			append valueAr #(dotNetObject "System.Boolean" True ,dotNetObject "System.String" "Pedro",dotNetObject "System.Int32" 0,#("superMan","batMan"))
			append valueAr #(dotNetObject "System.Boolean" False ,dotNetObject "System.String" "Peter",dotNetObject "System.Int32" 1,#("Santo","BlueDemon"))
		)
		--once our data has been created lets apply it to our grid
		for v in valueAr do
		(
			tempRow = dotNetObject "System.Windows.Forms.DataGridViewRow"
			dgv.rows.add tempRow
			for it in v[4] do tempRow.cells.item[2].items.add it
			tempRow.SetValues v
			--let's apply preaty colors to our cells 
			for i=1 to tempRow.cells.count do setDotNetWidgetColor tempRow.cells.item[i-1].style

		)
	)
)
createDialog testRo

Sep 12 2012

Exporting .pc2 files straight out of maya..

So recently I’ve been working on maya to max pipeline…
i ran into some issues with the built in cacheFile mechanism in maya so i decided that seance .pc2 is such a simple binary format that i could just write my own .pc2 exporter!

here’s what i came up with πŸ™‚

ps. this heavily borrowed from the blender importer written by “Matt Ebb” http://mattebb.com

import maya.cmds as cmds
import struct

def frange(x, y, jump,):
    ar =[]
    while x < y:
        ar.append(x)
        x += jump
    return ar

    
def writePC2File(filename, shape, world=True, zUp=False, startF=0, endF=100, samplesPerFrame=1):
    sampleRate = 1.0/samplesPerFrame
    numPoints = cmds.polyEvaluate(shape,v=True)#len(me.verts)
    totalFrames = endF - startF
    timeRange = frange(startF, startF+totalFrames+sampleRate, sampleRate)
    numSamples = len(timeRange)
    
    headerFormat='<12ciiffi'
    headerStr = struct.pack(headerFormat, 'P','O','I','N','T','C','A','C','H','E','2','\0', 1, numPoints, startF, sampleRate, numSamples)
    
    file = open(filename, "wb")
    file.write(headerStr)
    #---loop through time..
    cmds.refresh(su=True)
    sampleFrames = [] #--generate sample frames...
    
    print "startF=%s endF=%s sampleRate=%s shape=%s" % (startF, startF+numSamples, sampleRate,shape)
    #print "range is ",range(startF, startF+numSamples, sampleRate)

    for i in timeRange:
        #print "time is ",i
        cmds.currentTime(i)
        for p in range(numPoints):
            vPos = cmds.pointPosition( shape+'.vtx['+str(p)+']',w=True)
            vFormat = "fff" #-- add a "less than" character at the begining of the string.. i removed it becuse my wordpress code syntax was doing goofy stuff"
            thisVertex = struct.pack(vFormat, vPos[0], vPos[1], vPos[2])
            file.write(thisVertex)

    
    cmds.refresh(su=False)
    file.flush()
    file.close()
    print filename," was sucessfully written out"
    return True
    
#example    
out = r'C:\testMaya\test.pc2'
shp = cmds.listRelatives(shapes=True)
writePC2File(out,shp[0],startF=1000,endF=1200,samplesPerFrame=2)

Jul 23 2012

.Net hash table and maxscript

don’t ask why but recently i have had to deal with .net hashtables inside of maxscript πŸ™‚
i found most of the information i needed to deal with this data type preaty eazly..
but the one thing that i could not find was how to print the key values of a given hash table (which is useful if your debugging stuff and you don’t know what the hash table currently holds)
Any way..
after doing some reserach on data types i cam came up with this solution… if there’s a better way to do it let me know..

fn printOutHashTableKeys =
(
	--build the has table
	hash = dotNetObject "System.Collections.Hashtable"
	hash.add "_valueA" 1
	hash.add "_valueB" 2
	hash.add "_valueC" 3
	hash.add "_valueD" 4
	hash.add "_valueE" 5

	--spit the posible keys out
	DNArray = dotNetObject "System.string[]" hash.keys.count
	hash.keys.copyTo DNArray 0
	for i = 1 to hash.keys.count do print (DNArray.get (i-1))
)
printOutHashTableKeys()

Jun 21 2012

Comments were not properly working, but have now been fixed…

so somewhere along the way of updating wordpress versions and me not knowing what the hell i was doing i broke my comments table.

anyway from anyone who left comments and never got a response from me, or so their comment approved, i apologize. i have now corrected the issue and hope to have some awesome discussion will all of you out there.

by the way, I’m also trying to get this wordpress plug-in to work comment-reply-notification i have installed it but it doesn’t seem to be doing anything.. if any one has any advice let me know!

cheers,

Los.

p.s

i have anΒ  interesting lite tutorial on mechanical rigging I’m hoping to put up soon… might make for some interesting discussion.

 


Sep 15 2011

My Sql Dotnet and maxscript…

Today i ran in to a great snippet that shows how to interact with a mysql server via maxscript…

i have had a chance to try it out but it looks very promesing.

the snippet was taken from “Ofer Zelichover” site (http://www.oferz.com)

check it out if you have a chance…

 

( 
  /*
  -- This is a small tutorial on how to use the MySQL Connector to query a MySQL database.
  -- This tutorial assumes you have a MySQL server already set-up, that you installed the 
  -- MySQL Connector (available at MySQL website) and that you have basic knowledge of SQL.
  -- I will create a wrapper for easier usage in the near future. 
  -- Enjoy. -- Ofer Zelichover (www.oferz.com) 2008-03-08
  -- First load the dotNet assembly. Make sure the string points to the place where you installed 
  -- the MySQL Connector DLL file. 
  */
  dotNet.loadAssembly "C:\\Program Files\\MySQL\\mysql-connector\\bin\\MySql.Data.dll" 
  
  /*-- Now define the connection parameters.*/ 
  local host = "localhost" -- The name of the MySQL server 
  local database = "test"-- The name of the database to use 
  local user = "test" -- The user name to use 
  local password = "test"-- The password to use 
  /*-- And build the connection string */
  local connectionString = "Database=" + database + ";Data Source=" + host + ";User Id=" + user + ";Password=" + password 
  /*-- Create a connection object */
  local DBConnection = dotNetObject "MySql.Data.MySqlClient.MySqlConnection" 
  /*-- Set the connection parameters using the connection string. */
  DBConnection.ConnectionString = connectionString 
  /*-- Open the DB connection */
  DBConnection.open() 
  /*-- Print the connection status: 1 - connected; 0 - not connected. */
  print DBConnection.state.value__

  /*-- Add a 2 new rows */
  local cmdObject = DBConnection.CreateCommand() cmdObject.commandText = "INSERT INTO test_table (`name`, `phone`) VALUES ('another name','1234567890'), ('yet another name','2468101214')" 
  local readerObject = cmdObject.ExecuteReader() -- Print the number of affected rows format "Added % new rows\n"
  readerObject.RecordsAffected readerObject.close()
  /*-- Change the value of the the second row in the table: */
  local cmdObject = DBConnection.CreateCommand() 
  cmdObject.commandText = "UPDATE test_table tt SET tt.name='modified name', tt.phone=78978979 WHERE tt.id=2" local 
  readerObject = cmdObject.ExecuteReader() 
  /*-- Print the number of affected rows*/
  format "Modified % row(s)\n"
  readerObject.RecordsAffected readerObject.close() -- Query the database:
  /*-- First create a command object. This object is used to send the query to the database.*/ 
  local cmdObject = DBConnection.CreateCommand() 
  /*-- Define the SQL query you wish to execute: */
  cmdObject.commandText = "SELECT * FROM test_table tt" 
  /*-- Then execute the command to create a reader object. local*/ 
  readerObject = cmdObject.ExecuteReader() 
  /*-- Print the field names from the result: */
  for i = 0 to (readerObject.FieldCount - 1) do print (readerObject.getName i) 
  /*
  -- Print the results: 
  -- The readerObject.read() method advances to the next record in the reader object. 
  */
  while readerObject.read() do
  (
     local record = readerObject.item 
     /*-- Now print the record values. This assumes you know the field names: */
     format "%\t%\t%\n" record["id"] record["name"] record["phone"] 
     /*-- Another option, if you don't want to use explicit field names:*/ 
     for i = 0 to (readerObject.FieldCount - 1) do format "%\t" record[i] format "\n" ) 
     /*-- Close the reader object*/
     readerObject.close() 
     /*-- Close the connection*/
     DBConnection.close()
  ) 

Sep 14 2011

Another great link about using quaternian rotation in rigging

http://www.cuneytozdas.com/tutorials/maxscript/


Sep 14 2011

This guy is really smart!

Check out his work!
http://joleanes.com/tutorials/flippingless/flippingless_01.php