'-------------------------------------
'
' Skeleton Up Vector Creator v1.0
' Written by James Rogers
' Contact: jearogers@aol.com
' Date: 19/04/2001
' 
'-------------------------------------
'
' Sorry if I rant here, but I thought
' more people might read this rather than
' a seperate readme file.  Maybe I'll do
' a readme when the series is finished...
'
' WHAT DOES IT DO?
'
' Here is another script to help with
' character rigging (along with
' cube control).
' 
' Having drawn the skeleton in XSI,
' this script can be run to create 
' skeleton upvector constraint controls
' for legs, arms and backbone with a
' control cube.
'
' HOW IT WORKS (and HOW TO USE IT):
'
' The script works by prompting the
' user to select the root of the chain.
' Its coordinates are then stored as
' variables. The user is then prompted
' to select the effector, whose coordinates
' are also stored.
' A linear curve is created between the
' obtained coordinates. This curve is then
' evaluated at 50% along its length and
' the coordinates of that point are stored.
' (This was a bit easier to do in VBScript
' - I don't think it could handle any trig.)
' A control cube is created, with a blue
' wireframe and wireframe visability (if
' you are using "mixed viewing mode").
' The cube is then translated to the
' coordinates of the mid-point of the line
' minus five units in the z-axis. I chose
' a negitive value because I find this 
' control created less clutter when it
' is behind the object.
' The user is then prompted to select the
' first bone of the chain, which is in turn
' constrined (by a "skeleton up-vector"
' operation) to the control cube.
'
' If you are just learning scripting please
' go though it - I have commented it fully!
'
' Looking at the script you might say "ouch,
' that's a lot of variables!". The reason 
' for this is that this script works with
' the components of any name, i.e. if you 
' have drawn your skeleton and renamed say
' the root of each bone (and maybe the
' effector too) the the script would be
' useless if it only worked with the default
' names. So these extra variables are used
' to hold the name of each compnent so they
' can be restored when the script is finished.
' I am not saying this is the best way to do
' it, but it does add extra functionality to
' the script.
'
' LIMITATIONS:
'
' 1. Doesn't work if the the skeleton is part
'    of a model - I don't know why!
'    
'    Work Around: Use explorer to drag the
'    the skeleton under the scene root. Sorry
'    if this is a pain in the back-side.
'
' THINGS TO BE AWARE OF:
'
' This script was written on a day when there
' has been a lot of discussion on the XSI list
' about XSI's saving problems.  These might have
' been solved by the time you read this.  However,
' a clean save of your scene (using the "Save As")
' is recommended by SoftImage if scenes are
' corrupting. For more info check the list archive.
'
'--------------------------------------
'
' Please feel free to edit the script
' and send any updates to myself (email 
' at the top) or any free resource.
'
'--------------------------------------

application.statusbar = "Do your stuff with XSI"

'-----------'
' Variables '
'-----------'

' Here are all the variables used with basic descriptions of use

dim button ' dunno why this is there -see reference guide - Object Picker?

dim top, topname, newtopname, topnull   ' Root variables
dim bot, botname, newbotname, botnull   ' Effector variables

dim topposx, topposy, topposz   ' Root coordinate variables
dim botposx, botposy, botposz   ' Effector coordinate variables

dim line   ' line name variable
dim length   ' length of line

dim point   ' name of mid-point
dim pointposx, pointposy, pointposz   ' Mid point coordinate variables

dim up_cntrl   ' Control cube name variables
dim up_cntrlposz   ' Control cube coordinate operator

dim chainbone, chainbonename, newchainbonename   ' First bone variables

'------'
' Main '
'------'

' Get the position of the root

PickObject "Select Chain Root", "Select Chain Root", top, button   ' User prompt to select the root

topname = GetValue (top.Name)   ' Stores current name of root
LogMessage "Current root name = " & topname   ' Ouputs the current root name in the message box (peace of mind and useful debug feature)

if button <> 0 then

	SelectObj top, , True   ' Selects the picked root
	SetValue ".Name", "topnull"   ' Renames it topnull (for the momment)
	Refresh

	topposx = GetValue("topnull.kine.global.pos.posx")   ' This gets the coordinates of the root is x and stores it as "topposx"
	topposy = GetValue("topnull.kine.global.pos.posy")   ' This gets the coordinates of the root is y and stores it as "topposy"
	topposz = GetValue("topnull.kine.global.pos.posz")   ' This gets the coordinates of the root is z and stores it as "topposz"

	LogMessage "Root Position in x = " & topposx   ' These three lines output to the message box the coordinates for the same reason as before
	LogMessage "Root Position in y = " & topposy
	LogMessage "Root Position in z = " & topposz

	SelectObj top, , True   ' Makes sure the root is still selected
	newtopname = SetValue (".Name", topname)   ' Restores the root's original name

	application.statusbar = "Do your stuff with XSI"

' Get the position of the effector

	PickObject "Select Effector", "Select Effector", bot, button   ' User prompt to select the effector

	if button <> 0 then

		botname = GetValue (bot.Name)   ' Stores current name of effector
		LogMessage "Current effector name = " & botname   ' Ouputs the current effector name in the message box

		SelectObj bot, , True   ' Selects the picked effector
		SetValue ".Name", "effnull"   ' Renames it botnull (for the momment)
		Refresh

		botposx = GetValue("effnull.kine.global.pos.posx")   ' This gets the coordinates of the effector is x and stores it as "botposx"
		botposy = GetValue("effnull.kine.global.pos.posy")   ' This gets the coordinates of the effector is y and stores it as "botposy"
		botposz = GetValue("effnull.kine.global.pos.posz")   ' This gets the coordinates of the effector is z and stores it as "botposz"

		LogMessage "Effector Position in x = " & botposx   ' These three lines output to the message box the coordinates
		LogMessage "Effector Position in y = " & botposy
		LogMessage "Effector Position in z = " & botposz
		
		SelectObj bot, , True   ' Makes sure the effector is still selected
		newbotname = SetValue (".Name", botname)   ' Restores the effector's original name
		
	end if

end if

' Create the line between the root and effector

line = SICreateCurve ("line", 1, 1)   ' Creates the line called "line"
SIAddPointOnCurveAtEnd line, topposx, topposy, topposz, False   ' Adds first point at the root's coordinates
SIAddPointOnCurveAtEnd line, botposx, botposy, botposz, False   ' Adds the second point at the effectors' coordinates
Refresh

' Evaluate the line to find the length

GetCurveLength line, length   ' Find the length of the line and assigns it to the variable length
LogMessage "Length of line = " & length   ' Outputs to the message box the length of the line
Refresh

' Evaluate the line to find the mid-point

point = EvaluateCurveAt (line, 0.5, True, pointposx, pointposy, pointposz)   ' This find the mid-point of the line and stores the coordinates in variables 
LogMessage "Point Position in x = " & pointposx   ' These three lines output to the message box the coordinates
LogMessage "Point Position in y = " & pointposy
LogMessage "Point Position in z = " & pointposz

' Create the control cube

CreatePrim "Cube", "MeshSurface"   ' Creates the cube
SetValue ".Name", "cube"   ' Just to be sure, this line makes sure it is called "cube"

SetValue "cube.cube.length", 1.000 'sets the size of the cube   ' Sets the size of the cube to 1
MakeLocal "cube.display, siNodePropagation" 'This and the next line sets the cube's wireframe colour to blue
SetValue "cube.display.wirecol", 656

' Sets the cube as wireframe display for mixed viewing mode (very handy)

MakeLocal "cube.display", siNodePropagation
SetValue "cube.display.staticsel", 0
SetValue "cube.display.intsel", 0
SetValue "cube.display.staticunselnear", 0
SetValue "cube.display.intunselnear", 0
SetValue "cube.display.intunselfar", 0

SelectObj "cube", , True   ' Makes sure the cube is selected
SetValue ".Name", "up_cntrl"   ' Renames the cube as "up_cntrl"

' Cube translation function

up_cntrlposz = pointposz - 5.0   ' This line is where the cubes offset function is defined, working in the z-axis, and is set to -5

' Translation operation

Translate up_cntrl, pointposx, pointposy, up_cntrlposz, siAbsolute, siGlobal, siObj, siXYZ, False   ' The cube is then translated to the points of the midpoint. Note the z coordinate is acutally the translation function above
Refresh

' Delete the line

DeleteObj "line"   ' This deletes the line from the scene as it is no longer needed.
Refresh

application.statusbar = "Do your stuff in XSI!"

' Pick the first bone

PickObject "Select First Chain Bone", "Select First Chain Bone", chainbone, button   ' User prompt to select the first bone of the chain

if button <> 0 then

	chainbonename = GetValue (chainbone.Name)   ' Stores current name of first bone
	LogMessage "Current bone name = " & chainbonename   ' Ouputs the current effector name in the message box

	SelectObj chainbone, , True   ' Selects the picked first bone
	SetValue ".Name", "firstbone"   ' Renames it botnull (for the momment)
	Refresh

	' Apply the skeleton up-vector constraint

	ApplyOp "SkeletonUpVector", "firstbone;up_cntrl", 3, siPersistentOperation   ' Applies the skeleton up-vector constraint 

	SelectObj chainbone, , True   ' Makes sure the first bone is still selected
	newchainbonename = SetValue (".Name", chainbonename)   ' Restores the first bone's original name

end if

' Select the control cube for immediate manipulation

SelectObj "up_cntrl", , True   ' Makes sure the control cube is still selected
SetValue ".Name", "up_cntrl1"   ' Renames it to "up_cntrl1"

application.statusbar = "Do your stuff in XSI!"

' (*^.^*) PIKACHU!