Mod Tool/Scripting: Difference between revisions

m
using Image: consistently to make it easier to find all image refs on a page
m (DAE and FBX export)
m (using Image: consistently to make it easier to find all image refs on a page)
 
(17 intermediate revisions by 3 users not shown)
Line 14: Line 14:


'''Links'''
'''Links'''
* [http://softimage.wiki.softimage.com/index.php?title=Scripting_Tips_and_Tricks_%28XSISDK%29 xsi wiki page about scripting]
* [http://web.archive.org/web/20160803061035/http://softimage.wiki.softimage.com/index.php?title=Scripting_Tips_and_Tricks_%28XSISDK%29 xsi wiki page about scripting]
* '''[http://softimage.wiki.softimage.com/sdkdocs/scriptsdb/scriptsdb/scrdb_vbscript.htm many vbscript examples]'''
* '''[http://web.archive.org/web/20170616035120/http://softimage.wiki.softimage.com/sdkdocs/scriptsdb/scriptsdb/scrdb_vbscript.htm many vbscript examples]'''
* '''[http://ss64.com/vb/ vbs commands]'''
* '''[https://ss64.com/vb/ vbs commands]'''
* [http://www.activexperts.com/activmonitor/windowsmanagement/adminscripts/filesfolders/files/ objFSO/objWSHShell: Scripts to manage Files] (replace "Wscript.Echo" with "logmessage")
* [https://web.archive.org/web/20070510173452/https://www.activexperts.com/activmonitor/windowsmanagement/adminscripts/filesfolders/files/ objFSO/objWSHShell: Scripts to manage Files] (replace "Wscript.Echo" with "logmessage")
* [http://activexperts.com/activmonitor/windowsmanagement/adminscripts/other/textfiles/ objFSO/objWSHShell: Scripts to manage Text Files]
* [https://web.archive.org/web/20150504221146/http://activexperts.com/activmonitor/windowsmanagement/adminscripts/other/textfiles/ objFSO/objWSHShell: Scripts to manage Text Files]
* [http://www.kxcad.net/Softimage_XSI/Softimage_XSI_Documentation/script_basics_IncludingExternalScripts.htm using external scripts]
* [http://web.archive.org/web/20080905102848/http://www.kxcad.net/softimage_xsi/Softimage_XSI_Documentation/script_basics_IncludingExternalScripts.htm using external scripts]
* [http://download.autodesk.com/global/docs/softimage2013/en_us/sdkguide/index.html?url=si_om/XSIUIToolkit.html,topicNumber=si_om_XSIUIToolkit_html progress bar and open file dialog<!-- (hm, InitialDirectory code for quick save idea ?)-->]
* [https://download.autodesk.com/global/docs/softimage2013/en_us/sdkguide/index.html?url=si_om/XSIUIToolkit.html,topicNumber=si_om_XSIUIToolkit_html progress bar and open file dialog<!-- (hm, InitialDirectory code for quick save idea ?)-->]
<!--* [http://download.autodesk.com/global/docs/softimage2013/en_us/sdkguide/index.html?url=files/cus_ppg_FileBrowserWidget.htm,topicNumber=d30e11980,hash=WS34BA39B437A993419C80CAB58E3BEFA1-0059 text box]-->
<!--* [http://download.autodesk.com/global/docs/softimage2013/en_us/sdkguide/index.html?url=files/cus_ppg_FileBrowserWidget.htm,topicNumber=d30e11980,hash=WS34BA39B437A993419C80CAB58E3BEFA1-0059 text box]-->


Line 83: Line 83:
  logmessage GetGlobal ("MyGloVar")
  logmessage GetGlobal ("MyGloVar")


Further information are found over [http://download.autodesk.com/global/docs/softimage2014/en_us/sdkguide/si_cmds/SetGlobal.html HERE.]
Further information are found over [https://download.autodesk.com/global/docs/softimage2014/en_us/sdkguide/si_cmds/SetGlobal.html HERE.]




Line 100: Line 100:
  logmessage XSIUtils.Environment("MyVar")
  logmessage XSIUtils.Environment("MyVar")


As the information is a string you need to convert it back to what it was meant originally e.g. with cBool and cInt. For more conversion see [http://www.w3schools.com/vbscript/vbscript_ref_functions.asp HERE]
As the information is a string you need to convert it back to what it was meant originally e.g. with cBool and cInt. For more conversion see [http://web.archive.org/web/20150707131602/http://www.w3schools.com/vbscript/vbscript_ref_functions.asp HERE]




Line 130: Line 130:




===Object and scene fundamentals===
===Events===
logmessage selection.count
 
====OnStartup====
logmessage selection(0).Name
Loading objects on startup can fail in some aspects even though you use the same function for OnActivate.
For example a console might get correct position but wrong rotation.
logmessage selection(0).Materials(0).Name
 
logmessage selection(0).Materials(0).Library.name
In that case you might want to switch to another program and then back to XSI to use the OnActivate event. Or you do something else e.g. let the user click on a button. With that everything that happened OnStartup should had enough time to process.
logmessage selection(0).Materials(0).shaders(0).name
 
logmessage selection(0).Materials(0).CurrentImageClip.source.filename.value
 
logmessage selection(0).Materials(0).CurrentImageClip.source.Parameters("XRes").Value
====OnActivate====
logmessage selection(0).Material.CurrentImageClip.source.Parameters("YRes").Value
  function siOnActivateEventTest_OnEvent( in_ctxt )
Application.LogMessage "State: " + cstr(in_ctxt.GetAttribute("State"))
  logmessage selection(0).Material.CurrentUV.name
  ' TODO: Put your code here.
  ' Return value is ignored as this event can not be aborted.
logmessage selection(0).activeprimitive.geometry.clusters(0).name
siOnActivateEventTest_OnEvent = true
' look for UV cluster names
  end function
' xsi-generated: "Texture_Coordinates_AUTO"
' onisplit-generated: "NodeProperties"
logmessage selection(0).sclx.value
logmessage selection(0).scly.value
logmessage selection(0).sclz.value
   
logmessage selection(0).rotx.value
  logmessage selection(0).roty.value
logmessage selection(0).rotz.value
  logmessage selection(0).posx.value
logmessage selection(0).posy.value
logmessage selection(0).posz.value
logmessage selection(0).rotorder.value


'''State becomes "False" when XSI loses its focus.'''


====Materials and textures====
'''State becomes "True" when XSI regains focus.'''
'''get all targets of an image clip'''


set imgClip = GetValue("Clips._marker_blackness_tga")
Exchanging data between XSI and other programs is rather difficult.
set imgClipTargets = imgClip.GetShaderParameterTargets


logmessage imgClipTargets.count
Instead, whenever "True" is detected XSI could look into an exchange folder or exchange file*.
for each t in imgClipTargets
 
logmessage t
: *OniSplit GUI could save a vbs script to file and then it gets executed by XSI
next
 
:: Application.ExecuteScript( FileName, [Language], [ProcName], [Params] )




'''get all material libraries and materials
Full example (FillFile would have to be done by the GUI)


  for each ml in Application.ActiveProject.ActiveScene.MaterialLibraries
  Dim fso, wText, bInteractive, TestFile
logmessage ml
TestFile="C:\Oni\AE\Tools\Simple_OniSplit_GUI\XSI_exchange\test.vbs"
for each m in ml.items
logmessage m.name ' (material)
Main()
next
logmessage "--------------------------"
next
   
   
  ' INFO : Sources.Materials.DefaultLib
  '------------------------------------------------------------------------------
  ' INFO : Scene_Material
  ' NAME: FillFile
  ' INFO : sosMatBarrier
  '
  ' INFO : sosMatBlackness
  ' INPUT:
  ' INFO : sosMatDanger
  '
  ' INFO : sosMatGhost
  ' DESCRIPTION: Fill the test file
  ' INFO : sosMatImpassable
  '------------------------------------------------------------------------------
' INFO : sosMatStairs
  sub FillFile (in_file)
' INFO : --------------------------
  wText.WriteLine "Main()"
' INFO : Sources.Materials.MaterialLibrary
  wText.WriteLine ""
' INFO : AIR_STAIRWALL_LOB1
   
' INFO : AIR_WAITSEAT3
  wText.WriteLine "sub log_some_messages(an_int, a_string)"
' INFO : AIR_WAITSEAT2
  wText.WriteLine "logmessage ""the int : "" & an_int"
' INFO : COLLISION
  wText.WriteLine "logmessage ""the string : "" & a_string"
' INFO : --------------------------
  wText.WriteLine "end sub"
 
  wText.WriteLine ""
 
'''check an object's main material for TwoSided-ness'''
 
' test and toggles an object's main material for TwoSided-ness
  ' this is also a prerequired test for transparency
' the difficulty is to get the TextureObject (often named Image)
' the magic happens at FindShaders, I often fail to find such trivial stuff
  ' imo the xsi is terrible incomplete/unintuitive
' e.g. look at "Find (ShaderCollection)" in the help
' it will give you information about meshes such as cubes ...
   
   
  wText.WriteLine "sub main()"
  wText.WriteLine "CreatePrim ""Sphere"", ""NurbsSurface"""
  wText.WriteLine "end sub"
  wText.Close
end sub
   
   
  matLib = selection(0).Materials(0).Library.name
  sub main()
  Set fso = CreateObject("Scripting.FileSystemObject")
  Set wText = fso.CreateTextFile( TestFile, 1)
   
   
set mat = selection(0).Material
  FillFile TestFile
materialName = mat.name
   
   
' let us see if there is an Image TextureObject
  ExecuteScript TestFile
set shaders = mat.FindShaders(siShaderFilter)
textureObj = "Image"
   
   
'if typename(shaders(textureObj)) = "Texture" then ' if not it is Nothing
  dim aParams
  ' logmessage "material has texture object ""Image"""
  aParams = Array(123456789, "toto")
  'end if
  ExecuteScript TestFile,,"log_some_messages", aParams
end sub
 
====OnValueChange====
' this event is fired 4 times (2 local, 2 global)
  ' everytime when created, translated, rotated, or scaled
  ' we only want one global
   
   
  Set list = CreateObject("System.Collections.ArrayList")
  firstValue = false
for each n in shaders
function siOnValueChangeEventTest_OnEvent( in_ctxt )
list.Add n.name
next
   
   
foundShaderParameterTransparency = false
  if instr(cstr(in_ctxt.GetAttribute("Object")), ".kine.global") > 0 then
'foundUniqueShaderName = false
  if firstValue = false then
shaderName = ""
  if list.Contains(textureObj) = true then
' add more exit conditions here
set oColorShareShader = GetValue("Sources.Materials." & matLib & "." & mat.name & "." & textureObj)
' e.g. selection mode
set oTargets = oColorShareShader.GetShaderParameterTargets("")
' selection count
' if obj is not an Oni obj or camera
   
   
scriptObjArray = split(oTargets(0), ".")
'logmessage scriptObjArray(0) ' Sources (fixed name? Could be considered a folder.)
'logmessage scriptObjArray(1) ' Materials (fixed name? Could be considered a folder.)
'logmessage scriptObjArray(2) ' MaterialsLib (usually each object has its own MaterialsLib)
'logmessage scriptObjArray(3) ' Material
'logmessage scriptObjArray(4) ' Shader e.g. Phong
shaderName = scriptObjArray(4)
for each t in oTargets
logmessage t
if t.name = "transparency" then
foundShaderParameterTransparency = true
exit for
end if
next
end if
   
   
if foundShaderParameterTransparency = false then
    if selection.count > 0 and not replace(cstr(in_ctxt.GetAttribute("Object")),".kine.global", "") = "Camera_Interest" then
logmessage "material is not TwoSided, lets reverse now"
        logmessage "Object at: " & selection(0).posx.value & " " & selection(0).posy.value & " " & selection(0).posz.value
SIConnectShaderToCnxPoint "Sources.Materials." & matLib & "." & materialName & ".Image", "Sources.Materials." & matLib & "." & materialName & "." & shaderName & ".transparency", False
    end if
else
    if replace(cstr(in_ctxt.GetAttribute("Object")),".kine.global", "") = "Camera_Interest" then
logmessage "material is TwoSided, lets reverse now"
        logmessage GetValue("Camera_Interest.kine.global.posx") & " " & _
RemoveAllShadersFromCnxPoint "Sources.Materials." & matLib & "." & materialName & "." & shaderName & ".transparency", siShaderCnxPointBasePorts
          GetValue("Camera_Interest.kine.global.posy") & " " & _
          GetValue("Camera_Interest.kine.global.posz")
  logmessage "Obj is cam"
    end if
    firstValue = true
  else
    firstValue = false
  end if
  end if
  end if
end function


Output example:
  ' INFO : Object at: -22,0187049984705 6,63004918144234 5,08830153431981
  ' INFO : Sources.Materials.DefaultLib.Material.Phong.diffuse
  ' INFO : Obj is cam
' INFO : material is not TwoSided, lets reverse now
SIConnectShaderToCnxPoint "Sources.Materials.DefaultLib.Material.Image", "Sources.Materials.DefaultLib.Material.Phong.transparency", False
  ' INFO : Sources.Materials.DefaultLib.Material.Phong.diffuse
' INFO : Sources.Materials.DefaultLib.Material.Phong.transparency
' INFO : material is TwoSided, lets reverse now
RemoveAllShadersFromCnxPoint "Sources.Materials.DefaultLib.Material.Phong.transparency", siShaderCnxPointBasePorts


====Clusters====
This could be used to track camera and sound spheres positions. They values could be passed as command line argument to GUI.
'does a certain cluster type exist ?
 
'set cls = selection(0).activeprimitive.geometry.clusters.find( siPolygonCluster )
 
 
===Suppress events in batch processing===
' more interesting is how many of that type exist
Events that get triggered by code inside functions don't delay the function for processing the event.
for each n in selection(0).activeprimitive.geometry.clusters
 
    logmessage "Cluster " & n.name & " is of type " & n.type
The events are precessed after the function finished.
next
' "poly" = polygon cluster
' "sample" = UV cluster


Output example:
This can pose a serious problem with batch processing where you might create and select each object several times.
' INFO : Cluster Polygon4 is of type poly
' INFO : Cluster Polygon1 is of type poly
' INFO : Cluster Texture_Coordinates_AUTO is of type sample




====layers====
====Negative-example====
'''check if obj is member of layer'''
  function XSILoadPlugin( in_reg )
  logmessage isMemberOfLayer(selection(0), "layerNameToTest")
in_reg.Author = ""
in_reg.Name = "Sel Plug-in"
function isMemberOfLayer(obj, layerName)
in_reg.Major = 1
  dim list
  in_reg.Minor = 0
  set list = selectMembers ("Layers." & layerName, 0) ' 0 = for not changing the current selection
  in_reg.RegisterEvent "Selection",siOnSelectionChange
   
XSILoadPlugin = true
  for each o in list
  end function
if o = obj then
function XSIUnloadPlugin( in_reg )
isMemberOfLayer = "yes"
  dim strPluginName
exit for
strPluginName = in_reg.Name
end if
Application.LogMessage strPluginName & " has been unloaded.",siVerbose
  next
  XSIUnloadPlugin = true
  end function
  end function
 
  function Selection_OnEvent( in_ctxt )
 
' get select event, ignore unselect events (0)
'''get layer name of an object'''
if cstr(in_ctxt.GetAttribute("ChangeType")) = 1 then
logmessage RecursiveEnum (selection(0), false, false)
exit function
end if
  function RecursiveEnum( in_Comp, in_Type, in_FirstParentOnly )
if XSIUtils.Environment("IgnoreMe") = "true" then
  dim list, elem, layerNameToCheck
exit function
  set list = EnumElements( in_Comp, in_Type )
else
  if TypeName(list) <> "Nothing" then
logmessage "hi !"
      for each elem in list
end if
          if instr(elem, "Layers") = 1 and instr(elem, ".Members") > 1 then
Selection_OnEvent = true
          layerNameToCheck = replace(replace(elem,"Layers.", ""),".Members", "")
      if not layerNameToCheck = "" then
RecursiveEnum = layerNameToCheck
end if
      exit for
          end if
      next
  end if
  end function
  end function
' INFO : Layer_Default


Code to be called from somewhere else.


===Events===
XSIUtils.Environment.Setitem "IgnoreMe", "true"
SelectObj "cylinder", , True
XSIUtils.Environment.Setitem "IgnoreMe", "false"


====OnStartup====
The selection event outputs "hi !" despite "IgnoreMe" is set to "true" at the beginning.
Loading objects on startup can fail in some aspects even though you use the same function for OnActivate.
For example a console might get correct position but wrong rotation.


In that case you might want to switch to another program and then back to XSI to use the OnActivate event. Or you do something else e.g. let the user click on a button. With that everything that happened OnStartup should had enough time to process.
That's because the event becomes processed after the function finished after "IgnoreMe" was set to "false".




====OnActivate====
====Positive-example====
  function siOnActivateEventTest_OnEvent( in_ctxt )
  function XSILoadPlugin( in_reg )
  Application.LogMessage "State: " + cstr(in_ctxt.GetAttribute("State"))
in_reg.Author = ""
' TODO: Put your code here.
in_reg.Name = "Sel2 Plug-in"
' Return value is ignored as this event can not be aborted.
in_reg.Major = 1
  siOnActivateEventTest_OnEvent = true
in_reg.Minor = 0
in_reg.RegisterEvent "Selection2",siOnSelectionChange
XSILoadPlugin = true
end function
function XSIUnloadPlugin( in_reg )
dim strPluginName
strPluginName = in_reg.Name
  Application.LogMessage strPluginName & " has been unloaded.",siVerbose
XSIUnloadPlugin = true
end function
function Selection2_OnEvent( in_ctxt )
if cstr(in_ctxt.GetAttribute("ChangeType")) = 1 then
exit function
end if
IgnoreCount = GetGlobal ("IgnoreThis")
if IgnoreCount > 0 then
SetGlobal "IgnoreThis", (IgnoreCount - 1)
else
logmessage "Hi 2 !"
end if
  Selection2_OnEvent = true
  end function
  end function


'''State becomes "False" when XSI loses its focus.'''
Code to be called from somewhere else.


'''State becomes "True" when XSI regains focus.'''
Be aware of what can trigger the unwanted event and use a '''''global ignore variable'''''.


Exchanging data between XSI and other programs is rather difficult.
for i=1 to 5
 
SetGlobal "IgnoreThis", GetGlobal ("IgnoreThis") + 1
Instead, whenever "True" is detected XSI could look into an exchange folder or exchange file*.
SelectObj "cylinder", , True
next
' Don't use that variable where you want to trigger the event intentionally.
SelectObj "cylinder", , True


: *OniSplit GUI could save a vbs script to file and then it gets executed by XSI


:: Application.ExecuteScript( FileName, [Language], [ProcName], [Params] )
===Directories===
logmessage XSIUtils.ResolvePath("$XSI_USERHOME/")
' directory to addons and exported resources
logmessage XSIUtils.ResolvePath("$XSI_HOME/")
' directory to a few imported core files that must be modified (Model.vbs, ModStartup.js, ...)
' example:
' INFO : C:\Users\Paradox-01\Autodesk\Softimage_2015\
' INFO : C:\Program Files\Autodesk\Softimage 2015\
' INFO : C:\Users\Paradox-01\Autodesk\Softimage_Mod_Tool_7.5\
' INFO : C:\Softimage\Softimage_Mod_Tool_7.5\


' this can be useful for default locations like when selecting a folder
DesktopPath = CreateObject("WScript.Shell").SpecialFolders("Desktop")
logmessage DesktopPath


Full example (FillFile would have to be done by the GUI)


  Dim fso, wText, bInteractive, TestFile
===Message box===
  TestFile="C:\Oni\AE\Tools\Simple_OniSplit_GUI\XSI_exchange\test.vbs"
  ' okay-only
msgbox "message", 0, "title"
 
' okay and cancel
  MyVar = msgbox ("message", 1, "title")
   
   
  Main()
  if MyVar = 1 then
logmessage "OK button clicked"
logmessage MyVar ' = 1
else
logmessage "Cancel button clicked"
logmessage MyVar ' = 2
end if
 
 
===Input box===
MyVar = inputbox ("message", "title" , "pre-entered content")
   
   
  '------------------------------------------------------------------------------
  if MyVar = false then
  ' NAME: FillFile
logmessage "Cancel button clicked"
'
  else
' INPUT:
logmessage "OK button clicked"
  '
logmessage MyVar
' DESCRIPTION: Fill the test file
  end if
'------------------------------------------------------------------------------
 
sub FillFile (in_file)
 
  wText.WriteLine "Main()"
===Dealing with different decimal marks===
  wText.WriteLine ""
Decimal sign is either period or comma.
   
 
  wText.WriteLine "sub log_some_messages(an_int, a_string)"
Detect the used sign:
  wText.WriteLine "logmessage ""the int : "" & an_int"
  logmessage Mid(FormatNumber(0.1, 1, true, false, -2), 2, 1)
  wText.WriteLine "logmessage ""the string : "" & a_string"
 
  wText.WriteLine "end sub"
OniSplit always uses the period sign but XSI uses the system used one, which is language-specific.
  wText.WriteLine ""
 
When xml files are loaded into XSI, the OniSplit formatted values need to be converted if necessary. Example:
  wText.WriteLine "sub main()"
 
  wText.WriteLine "CreatePrim ""Sphere"", ""NurbsSurface"""
if Mid(FormatNumber(0.1, 1, true, false, -2), 2, 1) = "," then
  wText.WriteLine "end sub"
    posX = cdbl(replace(posX, ".", ","))
  wText.Close
    posY = cdbl(replace(posY, ".", ","))
end sub
    posZ = cdbl(replace(posZ, ".", ","))
  end if
sub main()
 
  Set fso = CreateObject("Scripting.FileSystemObject")
Actually you only the replacement function because it will skip the operation if the sign to replace is not found.
  Set wText = fso.CreateTextFile( TestFile, 1)
 
When xml files are written, comma signs have to be replaced again.
  FillFile TestFile
  ExecuteScript TestFile
  dim aParams
  aParams = Array(123456789, "toto")
  ExecuteScript TestFile,,"log_some_messages", aParams
  end sub


====OnValueChange====
posX = replace(posX, ",", ".")
  ' this event is fired 4 times (2 local, 2 global)
posY = replace(posY, ",", ".")
  ' everytime when created, translated, rotated, or scaled
posZ = replace(posZ, ",", ".")
' we only want one global
 
 
===Check executable version===
  ' taking OniSplit as example
Set objFSO = CreateObject("Scripting.FileSystemObject")
  logmessage objFSO.GetFileVersion("F:\Program Files (x86)\Oni\Edition\install\onisplit.exe")
   
   
  firstValue = false
  ' result looks like this:
  function siOnValueChangeEventTest_OnEvent( in_ctxt )
  ' INFO : 0.9.59.0
 
if instr(cstr(in_ctxt.GetAttribute("Object")), ".kine.global") > 0 then
 
  if firstValue = false then
===Build an vbs executable===
[[Image:VbsEdit_for_scripting_and_compiling.png|thumb]]
' add more exit conditions here
Executable, app(lication), program. Whatever you call it, sometimes it might be necessary to compile the script into an actual program.
' e.g. selection mode
' selection count
' if obj is not an Oni obj or camera
    if selection.count > 0 and not replace(cstr(in_ctxt.GetAttribute("Object")),".kine.global", "") = "Camera_Interest" then
        logmessage "Object at: " & selection(0).posx.value & " " & selection(0).posy.value & " " & selection(0).posz.value
    end if
    if replace(cstr(in_ctxt.GetAttribute("Object")),".kine.global", "") = "Camera_Interest" then
        logmessage GetValue("Camera_Interest.kine.global.posx") & " " & _
          GetValue("Camera_Interest.kine.global.posy") & " " & _
          GetValue("Camera_Interest.kine.global.posz")
  logmessage "Obj is cam"
    end if
    firstValue = true
  else
    firstValue = false
  end if
end if
end function


' INFO : Object at: -22,0187049984705 6,63004918144234 5,08830153431981
Even though vbs is a script language and not a programming language, it can be done.
' INFO : Obj is cam


This could be used to track camera and sound spheres positions. They values could be passed as command line argument to GUI.
VbsEdit is an editor to fulfill such task with ease.
 
: Just goto ''File > Convert into Executable''. Choose output path, 32/64-bit version and hit OK.




===Suppress events in batch processing===
===OS bitness===
Events that get triggered by code inside functions don't delay the function for processing the event.
if GetObject("winmgmts:root\cimv2:Win32_Processor='cpu0'").AddressWidth = 64 then
logmessage "64"
else
logmessage "32"
end if


The events are precessed after the function finished.
'''faster'''
Set WshShell = CreateObject("WScript.Shell")
if instr(WshShell.RegRead("HKLM\HARDWARE\DESCRIPTION\System\CentralProcessor\0\Identifier"), "64") > 0 then
logmessage "64"
else
logmessage "32"
end if


This can pose a serious problem with batch processing where you might create and select each object several times.


===XSI/Softimage bitness, version and license===
There are three possibilities to detect the program's bitness:
logmessage Platform
logmessage XSIUtils.ResolvePath("$XSI_CPU/")
logmessage XSIUtils.Is64BitOS
' output for 32-bit installation
' INFO : Win32
' INFO : nt-x86\
' INFO : False
' output for 64-bit installation
' INFO : Win64
' INFO : nt-x86-64\
' INFO : True


====Negative-example====
function XSILoadPlugin( in_reg )
in_reg.Author = ""
in_reg.Name = "Sel Plug-in"
in_reg.Major = 1
in_reg.Minor = 0
in_reg.RegisterEvent "Selection",siOnSelectionChange
XSILoadPlugin = true
end function
function XSIUnloadPlugin( in_reg )
dim strPluginName
strPluginName = in_reg.Name
Application.LogMessage strPluginName & " has been unloaded.",siVerbose
XSIUnloadPlugin = true
end function
function Selection_OnEvent( in_ctxt )
' get select event, ignore unselect events (0)
if cstr(in_ctxt.GetAttribute("ChangeType")) = 1 then
exit function
end if
if XSIUtils.Environment("IgnoreMe") = "true" then
exit function
else
logmessage "hi !"
end if
Selection_OnEvent = true
end function


Code to be called from somewhere else.
For program's version:
logmessage version
' examples:
' INFO : 13.0.114.0
' INFO : 7.5.203.0


  XSIUtils.Environment.Setitem "IgnoreMe", "true"
For program's license:
  SelectObj "cylinder", , True
logmessage license
  XSIUtils.Environment.Setitem "IgnoreMe", "false"
  ' examples:
  ' INFO : Softimage
  ' INFO : Mod Tool


The selection event outputs "hi !" despite "IgnoreMe" is set to "true" at the beginning.
DAE files saved with XSI/Softimage contain license information.


That's because the event becomes processed after the function finished after "IgnoreMe" was set to "false".


===Read registry===
This reads the registry with forced 64/32-bit path (RegType). In this example Oni's install location gets revealed.


====Positive-example====
Set WshShell = CreateObject("WScript.Shell")
  function XSILoadPlugin( in_reg )
  if instr(WshShell.RegRead("HKLM\HARDWARE\DESCRIPTION\System\CentralProcessor\0\Identifier"), "64") > 0 then
  in_reg.Author = ""
  OS_bitness = 64
  in_reg.Name = "Sel2 Plug-in"
else
in_reg.Major = 1
  OS_bitness = 32
  in_reg.Minor = 0
end if
  in_reg.RegisterEvent "Selection2",siOnSelectionChange
  XSILoadPlugin = true
Const HKEY_LOCAL_MACHINE = &H80000002
  end function
  function XSIUnloadPlugin( in_reg )
sPath = ReadRegStr (HKEY_LOCAL_MACHINE, _
dim strPluginName
  "SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\{B67333BB-1CF9-4EFD-A40B-E25B5CB4C8A7}}_is1", _
strPluginName = in_reg.Name
  "InstallLocation", _
Application.LogMessage strPluginName & " has been unloaded.",siVerbose
  OS_bitness)
XSIUnloadPlugin = true
  end function
logmessage sPath
function Selection2_OnEvent( in_ctxt )
if cstr(in_ctxt.GetAttribute("ChangeType")) = 1 then
exit function
   
end if
  Function ReadRegStr (RootKey, Key, Value, RegType)
IgnoreCount = GetGlobal ("IgnoreThis")
  Dim oCtx, oLocator, oReg, oInParams, oOutParams
if IgnoreCount > 0 then
SetGlobal "IgnoreThis", (IgnoreCount - 1)
  Set oCtx = CreateObject("WbemScripting.SWbemNamedValueSet")
else
  oCtx.Add "__ProviderArchitecture", RegType
logmessage "Hi 2 !"
   
end if
  Set oLocator = CreateObject("Wbemscripting.SWbemLocator")
Selection2_OnEvent = true
  Set oReg = oLocator.ConnectServer("", "root\default", "", "", , , , oCtx).Get("StdRegProv")
  end function
  Set oInParams = oReg.Methods_("GetStringValue").InParameters
  oInParams.hDefKey = RootKey
  oInParams.sSubKeyName = Key
  oInParams.sValueName = Value
  Set oOutParams = oReg.ExecMethod_("GetStringValue", oInParams, , oCtx)
  ReadRegStr = oOutParams.sValue
  End Function


Code to be called from somewhere else.


Be aware of what can trigger the unwanted event and use a '''''global ignore variable'''''.
===Run other programs===
'''via XSI System'''


  for i=1 to 5
  'relative pathes don't seem to work with this method
SetGlobal "IgnoreThis", GetGlobal ("IgnoreThis") + 1
OniSplitLocation = "C:\Softimage\Softimage_Mod_Tool_7.5\OniXSI_resources\OniSplit.exe"
SelectObj "cylinder", , True
inputFile =  "M3GMU_security_tv_wall_0.oni"
  next
inputPath  = "C:\Softimage\Softimage_Mod_Tool_7.5\OniXSI_resources\test a" & "\" & inputFile
   
outputPath = "C:\Softimage\Softimage_Mod_Tool_7.5\OniXSI_resources\test a"
  ' Don't use that variable where you want to trigger the event intentionally.
  ApplicationParam  = "-extract:xml " & """" & outputPath & """" & " " & """" & inputPath & """"
SelectObj "cylinder", , True
  appResult = System( OniSplitLocation & " " & ApplicationParam )
  Select Case appResult
    Case 0 LogMessage "Ok."
    Case Else LogMessage "Error."
End Select


 
'''Via CMD'''
===Directories===
  ' relative path
logmessage XSIUtils.ResolvePath("$XSI_USERHOME/")
' directory to addons and exported resources
logmessage XSIUtils.ResolvePath("$XSI_HOME/")
  ' directory to a few imported core files that must be modified (Model.vbs, ModStartup.js, ...)
   
   
  ' example:
  ' the "GameDataFolder" isn't inside the "install" folder
' INFO : C:\Users\Paradox-01\Autodesk\Softimage_2015\
  ' so we will use ..\ to go one folder backwards
  ' INFO : C:\Program Files\Autodesk\Softimage 2015\
   
   
  ' INFO : C:\Users\Paradox-01\Autodesk\Softimage_Mod_Tool_7.5\
  ' additional quote signs tells the program where the
  ' INFO : C:\Softimage\Softimage_Mod_Tool_7.5\
  ' paths strings start and end in case the path contains spaces
 
' this can be useful for default locations like when selecting a folder
DesktopPath = CreateObject("WScript.Shell").SpecialFolders("Desktop")
logmessage DesktopPath
 
 
===Message box===
' okay-only
msgbox "message", 0, "title"
 
' okay and cancel
MyVar = msgbox ("message", 1, "title")
   
   
  if MyVar = 1 then
  ' if you are going to use the xml file right after its extraction (which is likely)
logmessage "OK button clicked"
' then the "/wait" argument inside the onisplit_action string is important
logmessage MyVar ' = 1
  ' without it the code would continue and might try to read the not existing xml file and produce an error
  else
logmessage "Cancel button clicked"
logmessage MyVar ' = 2
end if
 
 
===Input box===
MyVar = inputbox ("message", "title" , "pre-entered content")
   
   
  if MyVar = false then
  onisplit_location = "F:\Program Files (x86)\Oni\Edition\install"
logmessage "Cancel button clicked"
input_folder = """..\GameDataFolder\level19_Final\ONLVcompound.oni"""
  else
output_folder = """..\GameDataFolder"""
logmessage "OK button clicked"
  onisplit_action = "cmd /C start /wait OniSplit.exe -extract:xml " & output_folder & " " & input_folder
logmessage MyVar
logmessage "relative path: " & onisplit_action
  end if
' expected logmessage:
 
' INFO : relative path: cmd /C start OniSplit.exe -extract:xml "..\GameDataFolder" "..\GameDataFolder\level19_Final\ONLVcompound.oni"
 
  XSIUtils.LaunchProcess onisplit_action, 1, onisplit_location
===dealing with different decimal marks===
Decimal sign is either period or comma.
 
' absolute path
Detect the used sign:
  logmessage Mid(FormatNumber(0.1, 1, true, false, -2), 2, 1)
'adapt paths so it works on your computer
 
onisplit_location = "F:\Program Files (x86)\Oni\Edition\install"
OniSplit always uses the period sign but XSI uses the system used one, which is language-specific.
input_folder = """F:\Program Files (x86)\Oni\Edition\GameDataFolder\level19_Final\ONLVcompound.oni"""
output_folder = """F:\Program Files (x86)\Oni\Edition\GameDataFolder"""
onisplit_action = "cmd /C start /wait OniSplit.exe -extract:xml " & output_folder & " " & input_folder
logmessage "absolute path: " & onisplit_action
' expected logmessage:
  ' <small>INFO : absolute path: cmd /C start OniSplit.exe -extract:xml "F:\Program Files (x86)\Oni\Edition\GameDataFolder" "F:\Program Files (x86)\Oni\Edition\GameDataFolder\level19_Final\ONLVcompound.oni"</small>
XSIUtils.LaunchProcess onisplit_action, 1, onisplit_location
' you can also lunch bat files
onibat = "cmd /C start run_wind.bat"
onilocation = "F:\Program Files (x86)\Oni\Edition"
XSIUtils.LaunchProcess onibat, 0, onilocation


When xml files are loaded into XSI, the OniSplit formatted values need to be converted if necessary. Example:


  if Mid(FormatNumber(0.1, 1, true, false, -2), 2, 1) = "," then
'''Via winmgmts'''
    posX = cdbl(replace(posX, ".", ","))
    posY = cdbl(replace(posY, ".", ","))
' slightly modified code from [https://devblogs.microsoft.com/scripting/how-can-i-start-a-process-and-then-wait-for-the-process-to-end-before-terminating-the-script/ that site]
    posZ = cdbl(replace(posZ, ".", ","))
  ' ''logmessage "onisplit finished."'' will be executed after the conversion finished, there should be also an delay of 3 seconds to support very slow computers
  end if
' if you are going to use this method consider to extent the code to check if input file and output directory exist
osp_loca = "C:\OniAE\Edition\install\OniSplit.exe"
osp_action = "-extract:xml"
osp_output = """C:\OniAE\Edition\GameDataFolder"""
osp_input = """C:\OniAE\Edition\GameDataFolder\level1_Final\AKEVEnvWarehouse.oni"""
osp_total = osp_loca & " " & osp_action & " " & osp_output & " " & osp_input
logmessage osp_total
strComputer = "."
Set objWMIService = GetObject("winmgmts:\\" & strComputer & "\root\cimv2:Win32_Process")
objWMIService.Create osp_total, null, null, intProcessID
Set objWMIService = GetObject("winmgmts:\\" & strComputer & "\root\cimv2")
' wait 3 second to find event - should be enough time for single actions on a slow computer
Set colMonitoredProcesses = objWMIService.ExecNotificationQuery _
    ("Select * From __InstanceDeletionEvent Within 3 Where TargetInstance ISA 'Win32_Process'")
   
Do Until i = 1
    Set objLatestProcess = colMonitoredProcesses.NextEvent
    If objLatestProcess.TargetInstance.ProcessID = intProcessID Then
        i = 1
    End If
Loop
logmessage "onisplit finished."
' now you can work with the extracted xml file


Actually you only the replacement function because it will skip the operation if the sign to replace is not found.


When xml files are written, comma signs have to be replaced again.
===Detect a running program===
detectProgram = "Simple_OniSplit_GUI.exe"
programIsActive = false
sComputerName = "."
Set objWMIService = GetObject("winmgmts:\\" & sComputerName & "\root\cimv2")
sQuery = "SELECT * FROM Win32_Process"
Set objItems = objWMIService.ExecQuery(sQuery)
For Each objItem In objItems
    if objItem.name = detectProgram then
        programIsActive = true
        exit for
    end if
Next
logmessage programIsActive


posX = replace(posX, ",", ".")
outputs either True or False
posY = replace(posY, ",", ".")
posZ = replace(posZ, ",", ".")


The code above triggers a bug. When Mod Tool gets minimized you can't bring it back to front.


===Check executable version===
ExecuteScript doesn't help.
' taking OniSplit as example
Set objFSO = CreateObject("Scripting.FileSystemObject")
logmessage objFSO.GetFileVersion("F:\Program Files (x86)\Oni\Edition\install\onisplit.exe")
' result looks like this:
' INFO : 0.9.59.0


===Taking a viewport screenshot===
SetDisplayMode "Camera", "texturedecal"
DeselectAll
cf = ActiveProject.Properties.Item("Play Control").Parameters.Item("Current").Value
set oViewportCapture = Dictionary.GetObject("ViewportCapture")
oViewportCapture.NestedObjects.Item("Start Frame").Value = cf
oViewportCapture.NestedObjects.Item("End Frame").Value = cf
oViewportCapture.NestedObjects.Item("OpenGL Anti-Aliasing").Value = 4
oViewportCapture.NestedObjects.Item("File Name").Value = "C:\Oni\AE\Tools\Simple_OniSplit_GUI\OutputFolder\test.jpg"
CaptureViewport  2, false


===Build an vbs executable===
command-line access via:
[[Image:VbsEdit_for_scripting_and_compiling.png|thumb]]
C:\Softimage\Softimage_Mod_Tool_7.5\Application\bin\flip.exe
Executable, app(lication), program. Whatever you call it, sometimes it might be necessary to compile the script into an actual program.


Even though vbs is a script language and not a programming language, it can be done.
For CMD options use "true" and Help > Command Line Options
CaptureViewport  2, true


VbsEdit is an editor to fulfill such task with ease.
It might be possible to further automate html creation with this.


: Just goto ''File > Convert into Executable''. Choose output path, 32/64-bit version and hit OK.
When screenshots are big enough the info text doesn't overlay object and can be cut away in further image processing.


==Write file==
===Export DAE===
Before you go crazy, yes, the command "CreateExportCrosswalkOptions" doesn't get logged in the script history.


===OS bitness===
set oProps = ActiveProject.ActiveScene.Root.Properties
  if GetObject("winmgmts:root\cimv2:Win32_Processor='cpu0'").AddressWidth = 64 then
  if typename (oProps.find("ExportCrosswalkOptions")) = "Nothing" then
logmessage "64"
  CreateExportCrosswalkOptions , "ExportCrosswalkOptions"
else
  logmessage "32"
  end if
  end if
' sets the extension to dae
SetValue "ExportCrosswalkOptions.Format", 1
' set export path and file name
SetValue "ExportCrosswalkOptions.Filename", CreateObject("WScript.Shell").SpecialFolders("Desktop") & "\export_test.dae"
' selection only
SetValue "ExportCrosswalkOptions.ExportSelectionOnly", True
' export
ExportCrosswalk "ExportCrosswalkOptions"


'''faster'''
Set WshShell = CreateObject("WScript.Shell")
if instr(WshShell.RegRead("HKLM\HARDWARE\DESCRIPTION\System\CentralProcessor\0\Identifier"), "64") > 0 then
logmessage "64"
else
logmessage "32"
end if


===Export FBX===
FBXExportLights (false)
FBXExportSelection (true)
' mark FBXExport and hit F1 to get more options
FBXExport (CreateObject("WScript.Shell").SpecialFolders("Desktop") & "\export_test.fbx" )


===XSI/Softimage bitness, version and license===
There are three possibilities to detect the program's bitness:
logmessage Platform
logmessage XSIUtils.ResolvePath("$XSI_CPU/")
logmessage XSIUtils.Is64BitOS
' output for 32-bit installation
' INFO : Win32
' INFO : nt-x86\
' INFO : False
' output for 64-bit installation
' INFO : Win64
' INFO : nt-x86-64\
' INFO : True


===Write text file===
txt_location = "C:\Softimage\Softimage_Mod_Tool_7.5\test.txt"
Set fso = CreateObject ("Scripting.FileSystemObject")
Set wText = fso.CreateTextFile (txt_location, 1)
wText.WriteLine "I'm a test file."
wText.WriteLine "Yo!"
wText.Close


For program's version:
logmessage version
' examples:
' INFO : 13.0.114.0
' INFO : 7.5.203.0


For program's license:
==Read file==
  logmessage license
===Import DAE===
' examples:
  CopyPaste, filePath, parentObject, 2
  ' INFO : Softimage
 
' INFO : Mod Tool
'use scene object if you don't want to group the imported object under a parent, e.g.:
  CopyPaste, filePath, ActiveProject.ActiveScene, 2
 


DAE files saved with XSI/Softimage contain license information.
===Import DAE (and get name)===
Sometimes you want to get the name of the object you just imported.


In that case you use "ImportModel" instead of "CopyPaste"


===Read registry===
ImportModel filePath, [parentObject], , , "0"
This reads the registry with forced 64/32-bit path (RegType). In this example Oni's install location gets revealed.
logmessage selection(0).parent
logmessage selection(0) 'this gets root object (file name)
logmessage selection(0).children(0) 'this gets first object of file


  Set WshShell = CreateObject("WScript.Shell")
If you want to remove the null object and select the new parent you add these lines:
  if instr(WshShell.RegRead("HKLM\HARDWARE\DESCRIPTION\System\CentralProcessor\0\Identifier"), "64") > 0 then
  set nullObject = selection(0)
OS_bitness = 64
  set newParent = selection(0).children(0)
  else
CutObj newParent
OS_bitness = 32
DeleteObj nullObject
end if
  SelectObj newParent
 
  Const HKEY_LOCAL_MACHINE = &H80000002
 
===Read text file===
  Set objFileToRead = CreateObject("Scripting.FileSystemObject").OpenTextFile("C:\Softimage\Softimage_Mod_Tool_7.5\test.txt", 1)
   
   
  sPath = ReadRegStr (HKEY_LOCAL_MACHINE, _
  do while not objFileToRead.AtEndOfStream
"SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\{B67333BB-1CF9-4EFD-A40B-E25B5CB4C8A7}}_is1", _
    strLine = objFileToRead.ReadLine()
"InstallLocation", _
    logmessage strLine
OS_bitness)
loop
' INFO : I'm a test file.
  logmessage sPath
  ' INFO : Yo!
   
   
objFileToRead.Close
Set objFileToRead = Nothing
===Read binary file===
scan_AKEV_file_table
   
   
sub scan_AKEV_file_table
' ##############################################
OniInputFile =  "H:\Oni\AE\GameDataFolder\level1_Final\AKEVEnvWarehouse.oni"
' ##############################################
   
Set OniInputFileStream = CreateObject("ADODB.Stream")
OniInputFileStream.Type = 1
OniInputFileStream.Open
OniInputFileStream.LoadFromFile OniInputFile
   
   
Function ReadRegStr (RootKey, Key, Value, RegType)
' ### read AKEV textures table offset and size
  Dim oCtx, oLocator, oReg, oInParams, oOutParams
ByteNum = 4
' ##############################################
TOffset = cLng("&H" & "28")
' ##############################################
OniInputFileStream.Position = TOffset
BArr1 = OniInputFileStream.Read(ByteNum)
   
   
  Set oCtx = CreateObject("WbemScripting.SWbemNamedValueSet")
ByteNum = 4
  oCtx.Add "__ProviderArchitecture", RegType
' ##############################################
TSize = cLng ("&H" & "2C")
' ##############################################
OniInputFileStream.Position = TSize
BArr2 = OniInputFileStream.Read(ByteNum)
   
   
  Set oLocator = CreateObject("Wbemscripting.SWbemLocator")
  Set oReg = oLocator.ConnectServer("", "root\default", "", "", , , , oCtx).Get("StdRegProv")
   
   
  Set oInParams = oReg.Methods_("GetStringValue").InParameters
' ### get AKEV textures table offset and size
  oInParams.hDefKey = RootKey
TOffsetHex = SimpleBinaryToString(BArr1)
  oInParams.sSubKeyName = Key
for i = ubound(TOffsetHex ) - 1 to 0 step -1
  oInParams.sValueName = Value
newhex = newhex & hex(Asc(TOffsetHex(i)))
next
logmessage newhex
logmessage "name table offset: " & cLng("&H" & newhex)
TOffsetInt = cLng("&H" & newhex)
newhex = ""
TSizeHex = SimpleBinaryToString(BArr2)
for i = ubound(TSizeHex) - 1 to 0 step -1
newhex = newhex & hex(Asc(TSizeHex(i)))
next
logmessage newhex
logmessage "name table size: " & cLng("&H" & newhex)
TSizeInt = cLng("&H" & newhex)
  logmessage "------------------------------"
 
   
   
  Set oOutParams = oReg.ExecMethod_("GetStringValue", oInParams, , oCtx)
' ### read table content
ByteNum = TSizeInt
  ReadRegStr = oOutParams.sValue
OniInputFileStream.Position = TOffsetInt
  End Function
BArr3 = OniInputFileStream.Read(ByteNum)
TContent = SimpleBinaryToString(BArr3)
' ### name grapper
NG = ""
for each n in TContent
if not Asc(n) = 0 then
NG = NG & n
else
'if instr(NG, "TXMP") = 1 then
' write TXMP to array ?
logmessage NG
'end if
NG = ""
end if
next
end sub
Function SimpleBinaryToString(Binary)
ReDim tmpArr(LenB(Binary) - 1)
For I = 1 To LenB(Binary)
S = Chr(AscB(MidB(Binary, I, 1)))
tmpArr(I - 1) = S
Next
SimpleBinaryToString = tmpArr
  End Function


Output:
' INFO : 0E40
' INFO : name table offset: 3648
' INFO : 0A4A
' INFO : name table size: 2634
' INFO : ------------------------------
' INFO : AKEVEnvWarehouse
' INFO : AGDBEnvWarehouse
' INFO : TXMP_DOOR_FRAME
' INFO : TXMPNONE
' INFO : TXMPSUMI_1
' INFO : TXMPTC_CONTROL_01
' [...]
' INFO : TXMPWH_DCTRBND


===Run other programs===
'''via XSI System'''
'relative pathes don't seem to work with this method
OniSplitLocation = "C:\Softimage\Softimage_Mod_Tool_7.5\OniXSI_resources\OniSplit.exe"
inputFile =  "M3GMU_security_tv_wall_0.oni"
inputPath  = "C:\Softimage\Softimage_Mod_Tool_7.5\OniXSI_resources\test a" & "\" & inputFile
outputPath = "C:\Softimage\Softimage_Mod_Tool_7.5\OniXSI_resources\test a"
ApplicationParam  = "-extract:xml " & """" & outputPath & """" & " " & """" & inputPath & """"
appResult = System( OniSplitLocation & " " & ApplicationParam )
Select Case appResult
    Case 0 LogMessage "Ok."
    Case Else LogMessage "Error."
End Select


'''vis CMD'''
====AKEV AGQG====
  ' relative path
  read_AGQG_binary
   
   
  ' the "GameDataFolder" isn't inside the "install" folder
  sub read_AGQG_binary
' so we will use ..\ to go one folder backwards
OniInputFile =  "C:\Oni\AE\GameDataFolder\L3\AKEVlab.oni"
' ##############################################
   
Set OniInputFileStream = CreateObject("ADODB.Stream")
OniInputFileStream.Type = 1
OniInputFileStream.Open
OniInputFileStream.LoadFromFile OniInputFile
   
   
' additional quote signs tells the program where the
data_table_offset = "&H20"
' paths strings start and end in case the path contains spaces
AGQG_table_offset = "&H94"
AGQG_table_size  = "&H9C"
   
   
' if you are going to use the xml file right after its extraction (which is likely)
' then the "/wait" argument inside the onisplit_action string is important
' without it the code would continue and might try to read the not existing xml file and produce an error
   
   
onisplit_location = "F:\Program Files (x86)\Oni\Edition\install"
ByteNum = 4
input_folder = """..\GameDataFolder\level19_Final\ONLVcompound.oni"""
OniInputFileStream.Position = clng(data_table_offset)
output_folder = """..\GameDataFolder"""
BArr0 = OniInputFileStream.Read(ByteNum)
onisplit_action = "cmd /C start /wait OniSplit.exe -extract:xml " & output_folder & " " & input_folder
logmessage "relative path: " & onisplit_action
' expected logmessage:
' INFO : relative path: cmd /C start OniSplit.exe -extract:xml "..\GameDataFolder" "..\GameDataFolder\level19_Final\ONLVcompound.oni"
XSIUtils.LaunchProcess onisplit_action, 1, onisplit_location
   
   
ByteNum = 4
OniInputFileStream.Position = clng(AGQG_table_offset)
BArr1 = OniInputFileStream.Read(ByteNum)
   
   
' absolute path
ByteNum = 4
OniInputFileStream.Position = clng(AGQG_table_size)
BArr2 = OniInputFileStream.Read(ByteNum)
   
   
'adapt paths so it works on your computer
newhex = ""
onisplit_location = "F:\Program Files (x86)\Oni\Edition\install"
data_table_offset_hex = SimpleBinaryToString(BArr0)
input_folder = """F:\Program Files (x86)\Oni\Edition\GameDataFolder\level19_Final\ONLVcompound.oni"""
for i = ubound(data_table_offset_hex) - 1 to 0 step -1
output_folder = """F:\Program Files (x86)\Oni\Edition\GameDataFolder"""
h = hex(Asc(data_table_offset_hex(i)))
onisplit_action = "cmd /C start /wait OniSplit.exe -extract:xml " & output_folder & " " & input_folder
if len(h) = 1 then
logmessage "absolute path: " & onisplit_action
h = "0" & h
' expected logmessage:
end if
' <small>INFO : absolute path: cmd /C start OniSplit.exe -extract:xml "F:\Program Files (x86)\Oni\Edition\GameDataFolder" "F:\Program Files (x86)\Oni\Edition\GameDataFolder\level19_Final\ONLVcompound.oni"</small>
newhex = newhex & h
XSIUtils.LaunchProcess onisplit_action, 1, onisplit_location
next
logmessage newhex
logmessage "data table offset: " & cLng("&H" & newhex)
data_table_offset_int = cLng("&H" & newhex)
   
   
newhex = ""
AGQG_offset_hex = SimpleBinaryToString(BArr1)
for i = ubound(AGQG_offset_hex) - 1 to 0 step -1
h = hex(Asc(AGQG_offset_hex(i)))
if len(h) = 1 then
h = "0" & h
end if
newhex = newhex & h
next
logmessage newhex
logmessage "AGQG table offset: " & cLng("&H" & newhex)
AGQG_offset_int = cLng("&H" & newhex)
newhex = ""
AGQG_size_hex = SimpleBinaryToString(BArr2)
for i = ubound(AGQG_size_hex) - 1 to 0 step -1
h = hex(Asc(AGQG_size_hex(i)))
if len(h) = 1 then
h = "0" & h
end if
newhex = newhex & h
next
logmessage newhex
logmessage "AGQG table size: " & cLng("&H" & newhex)
AGQG_size_int = cLng("&H" & newhex)
  logmessage "------------------------------"
  AGQG_start = data_table_offset_int + AGQG_offset_int - 8
  AGQG_end  = data_table_offset_int + AGQG_offset_int + AGQG_size_int - 8
  logmessage "AGQG_start: " & AGQG_start
 
' AGQG array size
  ByteNum = 4
OniInputFileStream.Position = AGQG_start + 28
BArr3 = OniInputFileStream.Read(ByteNum)
TContent = SimpleBinaryToString(BArr3)
  logmessage "------------------------------"
newhex = 0
for i = ubound(TContent) to 0 step -1
h = hex(Asc(TContent(i)))
if len(h) = 1 then
h = "0" & h
end if
newhex = newhex & h
next
AGQG_array_size = clng("&H" & newhex)
logmessage "AGQG array size: " & clng("&H" & newhex)
' reduce number by header space
ByteNum = AGQG_size_int - 31
' skip bytes used by header
OniInputFileStream.Position = AGQG_start + 32
BArr4 = OniInputFileStream.Read(ByteNum)
TContent2 = SimpleBinaryToString(BArr4)
c = -1
loop_count = 1
h = ""
newhex = ""
color = 0
logmessage "----------"
logmessage "element: 1"
for i = 0 to ubound(TContent2) - 1
c = c + 1
if c = 56 then
c = 0
loop_count = loop_count + 1
logmessage "----------"
logmessage "element: " & loop_count
end if
h = hex(Asc(TContent2(i)))
if len(h) = 1 then
h = "0" & h
end if
newhex = newhex & h
   
   
' you can also lunch bat files
if i mod 56 = 32 then
color = 1
onibat = "cmd /C start run_wind.bat"
end if
onilocation = "F:\Program Files (x86)\Oni\Edition"
if i mod 56 = 48 then
XSIUtils.LaunchProcess onibat, 0, onilocation
color = 0
 
end if
 
if i mod 56 = 52 then
'''via winmgmts'''
objid = 1
end if
' slightly modified code from [http://blogs.technet.com/b/heyscriptingguy/archive/2006/12/08/how-can-i-start-a-process-and-then-wait-for-the-process-to-end-before-terminating-the-script.aspx that site]
if i mod 56 = 0 then
' ''logmessage "onisplit finished."'' will be executed after the conversion finished, there should be also an delay of 3 seconds to support very slow computers
objid = 0
' if you are going to use this method consider to extent the code to check if input file and output directory exist
end if
osp_loca = "C:\OniAE\Edition\install\OniSplit.exe"
osp_action = "-extract:xml"
osp_output = """C:\OniAE\Edition\GameDataFolder"""
osp_input = """C:\OniAE\Edition\GameDataFolder\level1_Final\AKEVEnvWarehouse.oni"""
osp_total = osp_loca & " " & osp_action & " " & osp_output & " " & osp_input
logmessage osp_total
   
   
strComputer = "."
if len(newhex) = 8 then
Set objWMIService = GetObject("winmgmts:\\" & strComputer & "\root\cimv2:Win32_Process")
if color = 1 then
objWMIService.Create osp_total, null, null, intProcessID
logmessage newhex & " (color: " & clng(("&H" & left(newhex, 2))) _
Set objWMIService = GetObject("winmgmts:\\" & strComputer & "\root\cimv2")
& " " & clng("&H" & mid(newhex, 3, 2)) _
& " " & clng("&H" & mid(newhex, 5, 2)) _
& " " & clng("&H" & mid(newhex, 7, 2)) & ")"
elseif objid = 1 then
if newhex = "FFFFFFFF" then
logmessage newhex & " (object id: -1)"
else
logmessage newhex
end if
else
logmessage newhex
end if
newhex = ""
end if
next
   
   
  ' wait 3 second to find event - should be enough time for single actions on a slow computer
  end sub
Set colMonitoredProcesses = objWMIService.ExecNotificationQuery _
    ("Select * From __InstanceDeletionEvent Within 3 Where TargetInstance ISA 'Win32_Process'")
   
   
  Do Until i = 1
  Function SimpleBinaryToString(Binary)
    Set objLatestProcess = colMonitoredProcesses.NextEvent
ReDim tmpArr(LenB(Binary) - 1)
    If objLatestProcess.TargetInstance.ProcessID = intProcessID Then
For I = 1 To LenB(Binary)
        i = 1
S = Chr(AscB(MidB(Binary, I, 1)))
    End If
tmpArr(I - 1) = S
Loop
'logmessage "hex = " & hex(AscB(S))
  logmessage "onisplit finished."
Next
' now you can work with the extracted xml file
SimpleBinaryToString = tmpArr
  End Function
 


==Modify file==
===Binary===
[[Image:Before_and_after_binary_patching_with_vbs.png|thumb|400px|Before and after patching.]]
Change FilePath and in case of binary patching use function "StringToByteArray".


===Detect a running program===
FilePath =  "C:\path_to\AKEVEnvWarehouse.oni"
  detectProgram = "Simple_OniSplit_GUI.exe"
   
  programIsActive = false
  ' ### create stream objects
  sComputerName = "."
  Set InputStream = CreateObject("ADODB.Stream")
  Set objWMIService = GetObject("winmgmts:\\" & sComputerName & "\root\cimv2")
  InputStream.Type = 1
  sQuery = "SELECT * FROM Win32_Process"
InputStream.Open
  Set objItems = objWMIService.ExecQuery(sQuery)
  Set OutputStream = CreateObject("ADODB.Stream")
  For Each objItem In objItems
  OutputStream.Type = 1
    if objItem.name = detectProgram then
OutputStream.Open
        programIsActive = true
        exit for
' ### load input stream from file
    end if
  InputStream.LoadFromFile FilePath
  Next
   
  logmessage programIsActive
' ### copy first 16 signs of input stream to output stream
 
OutputStream.Write InputStream.Read(16)
outputs either True or False
 
' ### apply patch
The code above triggers a bug. When Mod Tool gets minimized you can't bring it back to front.
' # ASCII patching
 
patch_data = "ABCD"
ExecuteScript doesn't help.
  patch_data_length = len(patch_data)
 
  '  patch_data_length = 4
===Taking a viewport screenshot===
  InputStream.Position = InputStream.Position + patch_data_length
  SetDisplayMode "Camera", "texturedecal"
OutputStream.Write CreateObject("System.Text.ASCIIEncoding").GetBytes_4(patch_data)
  DeselectAll
  ' # binary patching
  cf = ActiveProject.Properties.Item("Play Control").Parameters.Item("Current").Value
'OutputStream.Write StringToByteArray("41424344")
  set oViewportCapture = Dictionary.GetObject("ViewportCapture")
   
  oViewportCapture.NestedObjects.Item("Start Frame").Value = cf
' ### re-add data that was cut off
  oViewportCapture.NestedObjects.Item("End Frame").Value = cf
OutputStream.Write InputStream.Read
  oViewportCapture.NestedObjects.Item("OpenGL Anti-Aliasing").Value = 4
   
  oViewportCapture.NestedObjects.Item("File Name").Value = "C:\Oni\AE\Tools\Simple_OniSplit_GUI\OutputFolder\test.jpg"
' ### unloader
  CaptureViewport  2, false
InputStream.Close
 
Set InputStream = Nothing
command-line access via:
  ' ### modes: 2 = overwrite; 1 = dontoverwrite
  C:\Softimage\Softimage_Mod_Tool_7.5\Application\bin\flip.exe
  ' test: save to new file
  ' FilePath2 = "C:\path_to\AKEVEnvWarehouseB.oni"
  OutputStream.SaveToFile FilePath, 2
OutputStream.Close
  Set OutputStream = Nothing


For CMD options use "true" and Help > Command Line Options
CaptureViewport  2, true


It might be possible to further automate html creation with this.
==Conversions==
 
===String -> byte array===
When screenshots are big enough the info text doesn't overlay object and can be cut away in further image processing.
function StringToByteArray(ThisString)
 
for i = 1 To Len(ThisString) Step 2
==Write file==
str = str & Chr("&h" & Mid(ThisString, i, 2))
===Export DAE===
next
Before you go crazy, yes, the command "CreateExportCrosswalkOptions" doesn't get logged in the script history.
 
Set stream = CreateObject("ADODB.Stream")
set oProps = ActiveProject.ActiveScene.Root.Properties
With stream
if typename (oProps.find("ExportCrosswalkOptions")) = "Nothing" then
.Open
  CreateExportCrosswalkOptions , "ExportCrosswalkOptions"
.CharSet = "Windows-1252"
  end if
.Type = 2
' ### 2 = text
.WriteText str
.Position = 0
.Type = 1
' ### 1 = binary
StringToByteArray = .Read
.Close
  End With
  end function
   
   
  ' sets the extension to dae
  ' ### usage
  SetValue "ExportCrosswalkOptions.Format", 1
  ByteArray = StringToByteArray(ThisString)
' set export path and file name
 
  SetValue "ExportCrosswalkOptions.Filename", CreateObject("WScript.Shell").SpecialFolders("Desktop") & "\export_test.dae"
 
' selection only
===Byte array -> string===
SetValue "ExportCrosswalkOptions.ExportSelectionOnly", True
  Function ByteArrayToString(Binary)
' export
  'Antonin Foller, https://www.motobit.com/
ExportCrosswalk "ExportCrosswalkOptions"
  'Optimized version of a simple BinaryToString algorithm.
 
 
 
  Dim cl1, cl2, cl3, pl1, pl2, pl3
===Export FBX===
  Dim L
FBXExportLights (false)
  cl1 = 1
FBXExportSelection (true)
  cl2 = 1
' mark FBXExport and hit F1 to get more options
  cl3 = 1
FBXExport (CreateObject("WScript.Shell").SpecialFolders("Desktop") & "\export_test.fbx" )
  L = LenB(Binary)
 
 
 
  Do While cl1<=L
==Read file==
    pl3 = pl3 & Chr(AscB(MidB(Binary,cl1,1)))
===Import DAE===
    cl1 = cl1 + 1
  CopyPaste, filePath, parentObject, 2
    cl3 = cl3 + 1
 
    If cl3>300 Then
'use scene object if you don't want to group the imported object under a parent, e.g.:
      pl2 = pl2 & pl3
  CopyPaste, filePath, ActiveProject.ActiveScene, 2
      pl3 = ""
      cl3 = 1
      cl2 = cl2 + 1
      If cl2>200 Then
        pl1 = pl1 & pl2
        pl2 = ""
        cl2 = 1
      End If
    End If
  Loop
  BinaryToString = pl1 & pl2 & pl3
  End Function
' ### usage
  MyString = ByteArrayToString(ByteArray)




===import DAE (and get name)===
==Math==
Sometimes you want to get the name of the object you just imported.
===Euler rotation -> matrix===
 
  function cosn (n)
In that case you use "ImportModel" instead of "CopyPaste"
cosn = cos(XSIMath.DegreesToRadians(n))
 
  end function
  ImportModel filePath, [parentObject], , , "0"
  function sinn (n)
logmessage selection(0).parent
sinn = sin(XSIMath.DegreesToRadians(n))
logmessage selection(0) 'this gets root object (file name)
  end function
  logmessage selection(0).children(0) 'this gets first object of file
 
If you want to remove the null object and select the new parent you add these lines:
  set nullObject = selection(0)
set newParent = selection(0).children(0)
  CutObj newParent
DeleteObj nullObject
SelectObj newParent
 
 
===Binary===
scan_AKEV_file_table
   
   
  sub scan_AKEV_file_table
  ' ################
' ##############################################
  logmessage "input"
OniInputFile = "H:\Oni\AE\GameDataFolder\level1_Final\AKEVEnvWarehouse.oni"
x = 60 : logmessage x
' ##############################################
y = 60 : logmessage y
   
z = 60 : logmessage z
Set OniInputFileStream = CreateObject("ADODB.Stream")
OniInputFileStream.Type = 1
OniInputFileStream.Open
OniInputFileStream.LoadFromFile OniInputFile
   
   
' ### read AKEV textures table offset and size
logmessage "##################"
ByteNum = 4
logmessage "converted"
' ##############################################
TOffset = cLng("&H" & "28")
' ##############################################
OniInputFileStream.Position = TOffset
BArr1 = OniInputFileStream.Read(ByteNum)
   
   
ByteNum = 4
set RotMatX = XSIMath.CreateMatrix3(1, 0, 0, 0, cosn(x), sinn(x), 0, -sinn(x), cosn(x))
' ##############################################
set RotMatY = XSIMath.CreateMatrix3(cosn(y), 0, -sinn(y), 0, 1, 0, sinn(y), 0, cosn(y))
TSize = cLng ("&H" & "2C")
set RotMatZ = XSIMath.CreateMatrix3(cosn(z), sinn(z), 0, -sinn(z), cosn(z), 0, 0, 0, 1)
' ##############################################
OniInputFileStream.Position = TSize
BArr2 = OniInputFileStream.Read(ByteNum)
   
   
RotMatZ.MulInPlace RotMatY
RotMatZ.MulInPlace RotMatX
   
   
' ### get AKEV textures table offset and size
for i=0 to 2
TOffsetHex = SimpleBinaryToString(BArr1)
  for j=0 to 2
  for i = ubound(TOffsetHex ) - 1 to 0 step -1
  logmessage RotMatZ (i, j)
  newhex = newhex & hex(Asc(TOffsetHex(i)))
  next
  next
logmessage newhex
next
logmessage "name table offset: " & cLng("&H" & newhex)
TOffsetInt = cLng("&H" & newhex)
' INFO : input
newhex = ""
' INFO : 60
' INFO : 60
TSizeHex = SimpleBinaryToString(BArr2)
' INFO : 60
for i = ubound(TSizeHex) - 1 to 0 step -1
' INFO : ##################
newhex = newhex & hex(Asc(TSizeHex(i)))
' INFO : converted
next
' INFO : 0,25
logmessage newhex
' INFO : 0,808012701892219
logmessage "name table size: " & cLng("&H" & newhex)
' INFO : 0,53349364905389
TSizeInt = cLng("&H" & newhex)  
' INFO : -0,433012701892219
' INFO : -0,399519052838329
  logmessage "------------------------------"
' INFO : 0,808012701892219
 
' INFO : 0,866025403784439
   
' INFO : -0,433012701892219
' ### read table content
' INFO : 0,25
ByteNum = TSizeInt
 
OniInputFileStream.Position = TOffsetInt
 
BArr3 = OniInputFileStream.Read(ByteNum)
===Matrix -> Euler rotation===
TContent = SimpleBinaryToString(BArr3)
Function Atan2(y, x)
  If x > 0 Then
' ### name grapper
    Atan2 = Atn(y / x)
NG = ""
  ElseIf x < 0 Then
for each n in TContent
    Atan2 = Sgn(y) * (XSIMath.PI - Atn(Abs(y / x)))
if not Asc(n) = 0 then
  ElseIf y = 0 Then
NG = NG & n
    Atan2 = 0
else
  Else
'if instr(NG, "TXMP") = 1 then
    Atan2 = Sgn(y) * XSIMath.PI / 2
' write TXMP to array ?
  End If
logmessage NG
End Function
'end if
NG = ""
   
end if
function ToEuler(M00, M10, M20, M21, M22)
next
            a = M00
end sub
            b = M10
            dim c, s, r
            if b = 0 then
                c = Sgn(a)
                s = 0
                r = Abs(a)
   
   
Function SimpleBinaryToString(Binary)
            elseif a = 0 then
ReDim tmpArr(LenB(Binary) - 1)
                c = 0
For I = 1 To LenB(Binary)
                s = Sgn(b)
S = Chr(AscB(MidB(Binary, I, 1)))
                r = Abs(b)
tmpArr(I - 1) = S
               
Next
            elseif Abs(b) > Abs(a) then
SimpleBinaryToString = tmpArr
                t = a / b
  End Function
                u = Sgn(b) * Sqr(1 + t * t)
 
                s = 1 / u
Output:
                c = s * t
' INFO : 0E40
                r = b * u
' INFO : name table offset: 3648
   
' INFO : 0A4A
            else
' INFO : name table size: 2634
                t = b / a
' INFO : ------------------------------
                u = Sgn(a) * Sqr(1 + t * t)
' INFO : AKEVEnvWarehouse
                c = 1 / u
' INFO : AGDBEnvWarehouse
                s = c * t
' INFO : TXMP_DOOR_FRAME
                r = a * u
' INFO : TXMPNONE
' INFO : TXMPSUMI_1
' INFO : TXMPTC_CONTROL_01
' [...]
' INFO : TXMPWH_DCTRBND
 
 
 
==Modify file==
===Binary===
[[Image:Before_and_after_binary_patching_with_vbs.png|thumb|400px|Before and after patching.]]
Change FilePath and in case of binary patching use function "StringToByteArray".
 
FilePath = "C:\path_to\AKEVEnvWarehouse.oni"
   
   
' ### create stream objects
    end if
Set InputStream = CreateObject("ADODB.Stream")
InputStream.Type = 1
InputStream.Open
Set OutputStream = CreateObject("ADODB.Stream")
OutputStream.Type = 1
OutputStream.Open
   
   
' ### load input stream from file
            Z = -Atan2(s, c)
InputStream.LoadFromFile FilePath
            Y = Atan2(M20, r)
            X = -Atan2(M21, M22)
   
   
' ### copy first 16 signs of input stream to output stream
    X = XSIMath.RadiansToDegrees(X)
OutputStream.Write InputStream.Read(16)
    Y = XSIMath.RadiansToDegrees(Y)
    Z = XSIMath.RadiansToDegrees(Z)
    ToEuler = array(X, Y, Z)
end function
   
   
  ' ### apply patch
  ' ################################
' # ASCII patching
  set RotMat = XSIMath.CreateMatrix3( _
  patch_data = "ABCD"
0.25, 0.808012701892219, 0.53349364905389, _
patch_data_length = len(patch_data)
-0.433012701892219, -0.399519052838329, 0.808012701892219, _
'  patch_data_length = 4
0.866025403784439, -0.433012701892219, 0.25 )
InputStream.Position = InputStream.Position + patch_data_length
OutputStream.Write CreateObject("System.Text.ASCIIEncoding").GetBytes_4(patch_data)
' # binary patching
'OutputStream.Write StringToByteArray("41424344")
   
   
  ' ### re-add data that was cut off
  OutputStream.Write InputStream.Read
  ' convert matrix to euler rotation and store values to array
   
  ReXYZ = ToEuler(RotMat(0,0), RotMat(1,0), RotMat(2,0), RotMat(2,1), RotMat(2,2))
  ' ### unloader
  InputStream.Close
  logmessage "reconverted"
  Set InputStream = Nothing
  logmessage ReXYZ(0)
  ' ### modes: 2 = overwrite; 1 = dontoverwrite
  logmessage ReXYZ(1)
  ' test: save to new file
  logmessage ReXYZ(2)
  ' FilePath2 = "C:\path_to\AKEVEnvWarehouseB.oni"
  OutputStream.SaveToFile FilePath, 2
  ' INFO : 60
OutputStream.Close
  ' INFO : 60
Set OutputStream = Nothing
  ' INFO : 60




==Conversions==
===Euler rotation -> quaternion===
===String -> byte array===
  dim x, y, z, dRotation, qRotation
  function StringToByteArray(ThisString)
x = 90
for i = 1 To Len(ThisString) Step 2
y = 0
str = str & Chr("&h" & Mid(ThisString, i, 2))
z = 0
next
   
   
Set stream = CreateObject("ADODB.Stream")
set dRotation = XSIMath.CreateRotation(XSIMath.DegreesToRadians(x), XSIMath.DegreesToRadians(y), XSIMath.DegreesToRadians(z))
With stream
set qRotation = XSIMath.CreateQuaternion()
.Open
.CharSet = "Windows-1252"
.Type = 2
' ### 2 = text
.WriteText str
.Position = 0
.Type = 1
' ### 1 = binary
StringToByteArray = .Read
.Close
End With
end function
   
   
  ' ### usage
dRotation.GetQuaternion (qRotation)
  ByteArray = StringToByteArray(ThisString)
LogMessage qRotation.W
 
LogMessage qRotation.X
LogMessage qRotation.Y
LogMessage qRotation.Z
' INFO : 0,707106781186548
' INFO : 0,707106781186547
' INFO : 0
' INFO : 0
' to calculate oni quaternions from euler rotations use this setup:
' LogMessage qRotation.X
' LogMessage qRotation.Y
  ' LogMessage qRotation.Z
  ' LogMessage qRotation.W * -1
 


===Byte array -> string===
===Quaternion -> Euler rotation===
  Function ByteArrayToString(Binary)
  dim qW, qX, qY, qZ, qRotation, x, y, z
  'Antonin Foller, http://www.motobit.com
  'Optimized version of a simple BinaryToString algorithm.
qW = 0.707106781186548
 
qX = 0.707106781186547
  Dim cl1, cl2, cl3, pl1, pl2, pl3
qY = 0
  Dim L
qZ = 0
  cl1 = 1
  cl2 = 1
set qRotation = XSIMath.CreateQuaternion (qW, qX , qY, qZ)
  cl3 = 1
  L = LenB(Binary)
 
  Do While cl1<=L
    pl3 = pl3 & Chr(AscB(MidB(Binary,cl1,1)))
    cl1 = cl1 + 1
    cl3 = cl3 + 1
    If cl3>300 Then
      pl2 = pl2 & pl3
      pl3 = ""
      cl3 = 1
      cl2 = cl2 + 1
      If cl2>200 Then
        pl1 = pl1 & pl2
        pl2 = ""
        cl2 = 1
      End If
    End If
  Loop
  BinaryToString = pl1 & pl2 & pl3
End Function
   
   
  ' ### usage
qRotation.GetXYZAngleValues x, y, z
  MyString = ByteArrayToString(ByteArray)
logmessage XSIMath.RadiansToDegrees(x)
logmessage XSIMath.RadiansToDegrees(y)
logmessage XSIMath.RadiansToDegrees(z)
' INFO : 89,9999999999999
' INFO : 0
' INFO : 0
  ' to calculate euler rotations from oni quaternions use this setup:
'qX = ...
'qY = ...
'qZ = ...
'qW = ... * -1
  'set qRotation = XSIMath.CreateQuaternion (qW, qX, qY, qZ)




==Math==
==Check selection mode==
===Euler rotation -> matrix===
  checkfilter
  function cosn (n)
  'use sub to make use of the exit command
cosn = cos(XSIMath.DegreesToRadians(n))
end function
function sinn (n)
sinn = sin(XSIMath.DegreesToRadians(n))
  end function
   
   
  ' ################
  sub checkfilter
logmessage "input"
Select Case Selection.Filter.Name
x = 60 : logmessage x
'caution: case-sensitive
y = 60 : logmessage y
z = 60 : logmessage z
   
   
logmessage "##################"
Case "object"
logmessage "converted"
logmessage "object mode"
Case "Edge"
logmessage "edge mode"
Case "Vertex"
logmessage "point mode"
Case "Polygon"
logmessage "polygon mode"  
Case Else
logmessage "unknown mode"
exit sub
  End Select
end sub
 
==3D mesh==
===General mesh information===
logmessage selection.count
   
   
  set RotMatX = XSIMath.CreateMatrix3(1, 0, 0, 0, cosn(x), sinn(x), 0, -sinn(x), cosn(x))
  logmessage selection(0).Name
  set RotMatY = XSIMath.CreateMatrix3(cosn(y), 0, -sinn(y), 0, 1, 0, sinn(y), 0, cosn(y))
  set RotMatZ = XSIMath.CreateMatrix3(cosn(z), sinn(z), 0, -sinn(z), cosn(z), 0, 0, 0, 1)
logmessage selection(0).Materials(0).Name
logmessage selection(0).Materials(0).Library.name
logmessage selection(0).Materials(0).shaders(0).name
  logmessage selection(0).Materials(0).CurrentImageClip.source.filename.value
  logmessage selection(0).Materials(0).CurrentImageClip.source.Parameters("XRes").Value
logmessage selection(0).Material.CurrentImageClip.source.Parameters("YRes").Value
   
   
  RotMatZ.MulInPlace RotMatY
  logmessage selection(0).Material.CurrentUV.name
RotMatZ.MulInPlace RotMatX
   
   
  for i=0 to 2
  logmessage selection(0).activeprimitive.geometry.clusters(0).name
for j=0 to 2
' look for UV cluster names
logmessage RotMatZ (i, j)
' xsi-generated: "Texture_Coordinates_AUTO"
next
  ' onisplit-generated: "NodeProperties"
  next
   
   
  ' INFO : input
  logmessage selection(0).sclx.value
  ' INFO : 60
  logmessage selection(0).scly.value
  ' INFO : 60
  logmessage selection(0).sclz.value
  ' INFO : 60
   
  ' INFO : ##################
  logmessage selection(0).rotx.value
' INFO : converted
  logmessage selection(0).roty.value
' INFO : 0,25
  logmessage selection(0).rotz.value
  ' INFO : 0,808012701892219
   
  ' INFO : 0,53349364905389
  logmessage selection(0).posx.value
  ' INFO : -0,433012701892219
  logmessage selection(0).posy.value
  ' INFO : -0,399519052838329
  logmessage selection(0).posz.value
  ' INFO : 0,808012701892219
   
  ' INFO : 0,866025403784439
  logmessage selection(0).rotorder.value
  ' INFO : -0,433012701892219
  ' INFO : 0,25




===Matrix -> Euler rotation===
===Materials and textures===
  Function Atan2(y, x)
====Get all targets of an image clip====
  If x > 0 Then
  set imgClip = GetValue("Clips._marker_blackness_tga")
    Atan2 = Atn(y / x)
set imgClipTargets = imgClip.GetShaderParameterTargets
  ElseIf x < 0 Then
 
    Atan2 = Sgn(y) * (XSIMath.PI - Atn(Abs(y / x)))
logmessage imgClipTargets.count
  ElseIf y = 0 Then
for each t in imgClipTargets
    Atan2 = 0
logmessage t
  Else
next
    Atan2 = Sgn(y) * XSIMath.PI / 2
 
  End If
 
  End Function
====Get all material libraries and materials====
for each ml in Application.ActiveProject.ActiveScene.MaterialLibraries
logmessage ml
for each m in ml.items
logmessage m.name ' (material)
next
logmessage "--------------------------"
  next
   
   
' INFO : Sources.Materials.DefaultLib
' INFO : Scene_Material
' INFO : sosMatBarrier
' INFO : sosMatBlackness
' INFO : sosMatDanger
' INFO : sosMatGhost
' INFO : sosMatImpassable
' INFO : sosMatStairs
' INFO : --------------------------
' INFO : Sources.Materials.MaterialLibrary
' INFO : AIR_STAIRWALL_LOB1
' INFO : AIR_WAITSEAT3
' INFO : AIR_WAITSEAT2
' INFO : COLLISION
' INFO : --------------------------
====Check an object's main material for TwoSided-ness====
' test and toggles an object's main material for TwoSided-ness
' this is also a prerequired test for transparency
' the difficulty is to get the TextureObject (often named Image)
' the magic happens at FindShaders, I often fail to find such trivial stuff
' imo the xsi is terrible incomplete/unintuitive
' e.g. look at "Find (ShaderCollection)" in the help
' it will give you information about meshes such as cubes ...
   
   
  function ToEuler(M00, M10, M20, M21, M22)
  matLib = selection(0).Materials(0).Library.name
            a = M00
            b = M10
            dim c, s, r
   
   
            if b = 0 then
set mat = selection(0).Material
                c = Sgn(a)
materialName = mat.name
                s = 0
                r = Abs(a)
   
   
            elseif a = 0 then
' let us see if there is an Image TextureObject
                c = 0
set shaders = mat.FindShaders(siShaderFilter)
                s = Sgn(b)
textureObj = "Image"
                r = Abs(b)
               
            elseif Abs(b) > Abs(a) then
                t = a / b
                u = Sgn(b) * Sqr(1 + t * t)
                s = 1 / u
                c = s * t
                r = b * u
   
   
            else
'if typename(shaders(textureObj)) = "Texture" then ' if not it is Nothing
                t = b / a
' logmessage "material has texture object ""Image"""
                u = Sgn(a) * Sqr(1 + t * t)
'end if
                c = 1 / u
                s = c * t
                r = a * u
   
   
    end if
Set list = CreateObject("System.Collections.ArrayList")
for each n in shaders
list.Add n.name
next
   
   
            Z = -Atan2(s, c)
foundShaderParameterTransparency = false
            Y = Atan2(M20, r)
'foundUniqueShaderName = false
            X = -Atan2(M21, M22)
shaderName = ""
if list.Contains(textureObj) = true then
set oColorShareShader = GetValue("Sources.Materials." & matLib & "." & mat.name & "." & textureObj)
set oTargets = oColorShareShader.GetShaderParameterTargets("")
   
   
    X = XSIMath.RadiansToDegrees(X)
scriptObjArray = split(oTargets(0), ".")
    Y = XSIMath.RadiansToDegrees(Y)
'logmessage scriptObjArray(0) ' Sources (fixed name? Could be considered a folder.)
    Z = XSIMath.RadiansToDegrees(Z)
'logmessage scriptObjArray(1) ' Materials (fixed name? Could be considered a folder.)
'logmessage scriptObjArray(2) ' MaterialsLib (usually each object has its own MaterialsLib)
'logmessage scriptObjArray(3) ' Material
'logmessage scriptObjArray(4) ' Shader e.g. Phong
shaderName = scriptObjArray(4)
for each t in oTargets
logmessage t
if t.name = "transparency" then
foundShaderParameterTransparency = true
exit for
end if
next
end if
   
   
    ToEuler = array(X, Y, Z)
if foundShaderParameterTransparency = false then
  end function
logmessage "material is not TwoSided, lets reverse now"
   
SIConnectShaderToCnxPoint "Sources.Materials." & matLib & "." & materialName & ".Image", "Sources.Materials." & matLib & "." & materialName & "." & shaderName & ".transparency", False
  ' ################################
else
  set RotMat = XSIMath.CreateMatrix3( _
logmessage "material is TwoSided, lets reverse now"
0.25, 0.808012701892219, 0.53349364905389, _
RemoveAllShadersFromCnxPoint "Sources.Materials." & matLib & "." & materialName & "." & shaderName & ".transparency", siShaderCnxPointBasePorts
-0.433012701892219, -0.399519052838329, 0.808012701892219, _
  end if
0.866025403784439, -0.433012701892219, 0.25 )
 
Output example:
  ' INFO : Sources.Materials.DefaultLib.Material.Phong.diffuse
  ' INFO : material is not TwoSided, lets reverse now
  SIConnectShaderToCnxPoint "Sources.Materials.DefaultLib.Material.Image", "Sources.Materials.DefaultLib.Material.Phong.transparency", False
   
   
  ' INFO : Sources.Materials.DefaultLib.Material.Phong.diffuse
  ' convert matrix to euler rotation and store values to array
  ' INFO : Sources.Materials.DefaultLib.Material.Phong.transparency
ReXYZ = ToEuler(RotMat(0,0), RotMat(1,0), RotMat(2,0), RotMat(2,1), RotMat(2,2))
  ' INFO : material is TwoSided, lets reverse now
  RemoveAllShadersFromCnxPoint "Sources.Materials.DefaultLib.Material.Phong.transparency", siShaderCnxPointBasePorts
logmessage "reconverted"
logmessage ReXYZ(0)
logmessage ReXYZ(1)
logmessage ReXYZ(2)
  ' INFO : 60
  ' INFO : 60
  ' INFO : 60




===Euler rotation -> quaternion===
===Clusters===
  dim x, y, z, dRotation, qRotation
  'does a certain cluster type exist ?
  x = 90
'set cls = selection(0).activeprimitive.geometry.clusters.find( siPolygonCluster )
  y = 0
 
  z = 0
' more interesting is how many of that type exist
for each n in selection(0).activeprimitive.geometry.clusters
    logmessage "Cluster " & n.name & " is of type " & n.type
next
  ' "poly" = polygon cluster
  ' "sample" = UV cluster
 
Output example:
' INFO : Cluster Polygon4 is of type poly
' INFO : Cluster Polygon1 is of type poly
  ' INFO : Cluster Texture_Coordinates_AUTO is of type sample
 
 
====Bounding box values====
' this could be useful to create a bounding box for [[XML:OFGA|OFGA files]]
' let's get the bounding box of a simple cylinder
' the output values will be absolute positions
CreatePrim "Cylinder", "MeshSurface"
   
   
  set dRotation = XSIMath.CreateRotation(XSIMath.DegreesToRadians(x), XSIMath.DegreesToRadians(y), XSIMath.DegreesToRadians(z))  
  dim xmin, ymin, zmin, xmax, ymax, zmax
  set qRotation = XSIMath.CreateQuaternion()
dim list
'if you use SelectionList the objects will be treated as one single object
'set list = GetValue( "SelectionList" )
set list = GetValue( selection(0) )
  GetBBox list, TRUE, xmin, ymin, zmin, xmax, ymax, zmax
LogMessage "Lower Bound: " & xmin & " / " & ymin & " / " & zmin
LogMessage "Upper Bound: " & xmax & " / " & ymax & " / " & zmax
   
   
dRotation.GetQuaternion (qRotation)  
' expected output:
LogMessage qRotation.W
' INFO : Lower Bound: -1 / -2 / -1
LogMessage qRotation.X
' INFO : Upper Bound: 1 / 2 / 1
LogMessage qRotation.Y
 
LogMessage qRotation.Z
====Get the scaling, rotation and position of selected objects====
' INFO : 0,707106781186548
logmessage "mesh name: " & selection(0)
' INFO : 0,707106781186547
logmessage selection(0).sclx.value
' INFO : 0
logmessage selection(0).scly.value
' INFO : 0
logmessage selection(0).sclz.value
   
logmessage selection(0).rotx.value
  ' to calculate oni quaternions from euler rotations use this setup:
logmessage selection(0).roty.value
  ' LogMessage qRotation.X
logmessage selection(0).rotz.value
  ' LogMessage qRotation.Y
logmessage selection(0).posx.value
  ' LogMessage qRotation.Z
logmessage selection(0).posy.value
  ' LogMessage qRotation.W * -1
logmessage selection(0).posz.value
 
 
====Get scaling, rotation, and position of not selected objects====
' GetValue("NAME.kine.global.rotx")
' NAME must be the exact mesh name
' let's say you want the data of one character's pelvis
logmessage GetValue("pelvis.kine.global.sclx")
logmessage GetValue("pelvis.kine.global.scly")
logmessage GetValue("pelvis.kine.global.sclz")
logmessage GetValue("pelvis.kine.global.rotx")
logmessage GetValue("pelvis.kine.global.roty")
logmessage GetValue("pelvis.kine.global.rotz")
logmessage GetValue("pelvis.kine.global.posx")
logmessage GetValue("pelvis.kine.global.posy")
  logmessage GetValue("pelvis.kine.global.posz")
 
 
===Points===
====Get position of points (with selection mode point)====
  ' a point must be selected
  ' gets xyz position of first selected point of the first selected object
  logmessage Selection(0).SubComponent.ComponentCollection(0).position.x
  logmessage Selection(0).SubComponent.ComponentCollection(0).position.y
  logmessage Selection(0).SubComponent.ComponentCollection(0).position.z


====Get position of points (with selection mode object)====
' an object must be selected
' gets xyz position of point 0 of the first selected object
logmessage selection(0).activeprimitive.geometry.Points(0).Position.x
logmessage selection(0).activeprimitive.geometry.Points(0).Position.y
logmessage selection(0).activeprimitive.geometry.Points(0).Position.z


===Quaternion -> Euler rotation===
====Get and set position of points (without selection) right after object creation====
  dim qW, qX, qY, qZ, qRotation, x, y, z
' point positions are relative to the object's center
' to get the absolute point positions add center to point
  ' to set the absolute point positions subtract center from point
   
   
qW = 0.707106781186548
set oRoot = application.activeproject.activescene.root
qX = 0.707106781186547
set oObj = oRoot.addgeometry( "Cube", "MeshSurface", "test" )
qY = 0
qZ = 0
' to test our code move center to somewhere else
Translate oObj, 9, 11, 13, siRelative, siGlobal, siCtr, siXYZ, , , , , , , , , , 0
SaveKey oObj & ".kine.local.posx," & oObj & ".kine.local.posy," & oObj & ".kine.local.posz", 1, , , , True
FreezeObj oObj
set oGeometry = oObj.activeprimitive.geometry
aPositions = oGeometry.Points.PositionArray
' get old position
'                                        (xyz, point)
logmessage "old point 0 posx: " & aPositions(0, 0) + GetValue(oObj & ".kine.global.posx")
logmessage "old point 0 posy: " & aPositions(1, 0) + GetValue(oObj & ".kine.global.posy")
logmessage "old point 0 posz: " & aPositions(2, 0) + GetValue(oObj & ".kine.global.posz")
' set new position
aPositions(0, 0) = -7 - GetValue(oObj & ".kine.global.posx")
aPositions(1, 0) = -7 - GetValue(oObj & ".kine.global.posy")
aPositions(2, 0) = -7 - GetValue(oObj & ".kine.global.posz")
   
   
  set qRotation = XSIMath.CreateQuaternion (qW, qX , qY, qZ)
  ' update the array
oGeometry.Points.PositionArray = aPositions
' get new position
logmessage "new point 0 posx: " & aPositions(0, 0) + GetValue(oObj & ".kine.global.posx")
logmessage "new point 0 posy: " & aPositions(1, 0) + GetValue(oObj & ".kine.global.posy")
logmessage "new point 0 posz: " & aPositions(2, 0) + GetValue(oObj & ".kine.global.posz")
   
   
qRotation.GetXYZAngleValues x, y, z
' INFO : old point 0 posx: -4
logmessage XSIMath.RadiansToDegrees(x)
' INFO : old point 0 posy: -4
logmessage XSIMath.RadiansToDegrees(y)
' INFO : old point 0 posz: -4
logmessage XSIMath.RadiansToDegrees(z)
' INFO : 89,9999999999999
' INFO : 0
' INFO : 0
   
   
  ' to calculate euler rotations from oni quaternions use this setup:
  ' INFO : new point 0 posx: -7
'qX = ...
' INFO : new point 0 posy: -7
'qY = ...
  ' INFO : new point 0 posz: -7
'qZ = ...
'qW = ... * -1
  'set qRotation = XSIMath.CreateQuaternion (qW, qX, qY, qZ)




==Check selection mode==
====Get global point position====
  checkfilter
set oObj = selection(0)
  'use sub to make use of the exit command
set oTrans = oObj.Kinematics.Local.Transform
set oPoint0 = oObj.ActivePrimitive.Geometry.Points(0)
set oPoint7 = oObj.ActivePrimitive.Geometry.Points(7)
set oPos0 = oPoint0.Position
set oPos7 = oPoint7.Position
   
  ' scaling must be frozen to 1 before we can calculate the size from local values
ResetTransform selection(0), siCtr, siScl, siXYZ
   
   
  sub checkfilter
  logmessage "local p0: "& oPos0.X & " " & oPos0.Y & " " & oPos0.Z
Select Case Selection.Filter.Name
set oGlobalPos0 = XSIMath.MapObjectPositionToWorldSpace( oTrans, oPos0)
'caution: case-sensitive
logmessage "global p0: "& oGlobalPos0.X & " " & oGlobalPos0.Y & " " & oGlobalPos0.Z
   
   
Case "object"
logmessage "local p7: "& oPos7.X & " " & oPos7.Y & " " & oPos7.Z
logmessage "object mode"
set oGlobalPos7 = XSIMath.MapObjectPositionToWorldSpace( oTrans, oPos7)
Case "Edge"
logmessage "global p7: "& oGlobalPos7.X & " " & oGlobalPos7.Y & " " & oGlobalPos7.Z
logmessage "edge mode"
 
Case "Vertex"
logmessage "size: " & oPos7.X - oPos0.X & " " & _
logmessage "point mode"
oPos7.Y - oPos0.Y & " " & _
Case "Polygon"
oPos7.Z - oPos0.Z
logmessage "polygon mode"  
' with a rotation of: -3,8792 16,4039 -13,5017
Case Else
' INFO : local p0: -4 -4 -4
logmessage "unknown mode"
' INFO : local p7: 4 4 4
exit sub
' INFO : global p0: -5,74764582364017 -3,00250371537919 -2,43916767056426 ' TRGV start point
  End Select
' INFO : global p7: 5,74764582364017 3,00250371537919 2,43916767056426
  end sub
  ' INFO : size: 8 8 8
 


==Property Page==
===Edges===
===Detect a PPG===
...
' this check is used to decide to either build or open a PPG
===Polygons===
set oRoot = ActiveProject.ActiveScene.Root
...
if typename(oRoot.Properties("my_PPG")) = "Nothing" then
logmessage "couldn't find my_PPG"
else
logmessage "found my_PPG"
end if




===Disable PPG popups===
' let's say a big amount of objects will be created and each object will open a PPG
' in that case for user convenience those PPG popups should be disabled


' disable PPG popup
==Layers==
  Preferences.SetPreferenceValue "Interaction.autoinspect", false
===Check if object is member of layer===
  logmessage isMemberOfLayer(selection(0), "layerNameToTest")
   
   
  ' creates the cube mesh but no PPG will show up
  function isMemberOfLayer(obj, layerName)
CreatePrim "Cube", "MeshSurface"
dim list
set list = selectMembers ("Layers." & layerName, 0) ' 0 = for not changing the current selection
   
   
' enable PPG popup again
for each o in list
Preferences.SetPreferenceValue "Interaction.autoinspect", true
if o = obj then
isMemberOfLayer = "yes"
exit for
end if
next
end function




===Build a PPG===
===Get layer name of an object===
  ' general PPG setup
  logmessage RecursiveEnum (selection(0), false, false)
set oPSet = ActiveSceneRoot.AddProperty("CustomProperty", false, "my_PPG")
set oPPGLayout = oPSet.PPGLayout
   
   
  ' PPG content
  function RecursiveEnum( in_Comp, in_Type, in_FirstParentOnly )
' [...]
  dim list, elem, layerNameToCheck
  set list = EnumElements( in_Comp, in_Type )
  if TypeName(list) <> "Nothing" then
      for each elem in list
          if instr(elem, "Layers") = 1 and instr(elem, ".Members") > 1 then
          layerNameToCheck = replace(replace(elem,"Layers.", ""),".Members", "")
      if not layerNameToCheck = "" then
RecursiveEnum = layerNameToCheck
end if
      exit for
          end if
      next
  end if
end function
   
   
  ' open PPG
  ' INFO : Layer_Default
InspectObj oPSet




===PPG content===
==Property Page==
====Button====
===Detect a PPG===
If you need quote signs in the Logic section you write two signs: "" (Not shown in example.)
' this check is used to decide to either build or open a PPG
 
set oRoot = ActiveProject.ActiveScene.Root
  oPPGLayout.AddButton("btnFuncName", "click here to trigger afunction").setAttribute siUICX, 200
  if typename(oRoot.Properties("my_PPG")) = "Nothing" then
logmessage "couldn't find my_PPG"
oPPGLayout.Logic = " sub btnFuncName_OnClicked" & vbCrlf & _
  else
" btnFuncNameReal" & vbCrlf & _
  logmessage "found my_PPG"
" end sub"
  end if
   
function btnFuncNameReal
  logmessage "hello world"
  end function


New lines in Logic need
& vbCrlf & _
on the earlier line.


===Disable PPG popups===
' let's say a big amount of objects will be created and each object will open a PPG
' in that case for user convenience those PPG popups should be disabled


====Text input====
' disable PPG popup
  oPSet.AddParameter3 "ParamName", siString
  Preferences.SetPreferenceValue "Interaction.autoinspect", false
  oPPGLayout.AddItem "ParamName", "Caption"
   
' creates the cube mesh but no PPG will show up
CreatePrim "Cube", "MeshSurface"
' enable PPG popup again
Preferences.SetPreferenceValue "Interaction.autoinspect", true




====Integer input====
===Build a PPG===
  oPSet.AddParameter3 "ParamName", siInt2, , , , false, 0
  ' general PPG setup
  oPPGLayout.AddItem "ParamName", "Caption"
set oPSet = ActiveSceneRoot.AddProperty("CustomProperty", false, "my_PPG")
  set oPPGLayout = oPSet.PPGLayout
' PPG content
' [...]
' open PPG
InspectObj oPSet


If you try to set a value that is below the defined minimum, you will get this error text:
' ERROR : 2006-EDIT-SetValue - Unexpected failure.
' Syntax: PPGname.data, value
' SetValue "Turret.int1", "0"
' ERROR : Überlauf: 'setvalue' - [line ''N'']
German devs? I expected "overflow", not "Überlauf".


===PPG content===
====Button====
If you need quote signs in the Logic section you write two signs: "" (Not shown in example.)
oPPGLayout.AddButton("btnFuncName", "click here to trigger afunction").setAttribute siUICX, 200
oPPGLayout.Logic = " sub btnFuncName_OnClicked" & vbCrlf & _
" btnFuncNameReal" & vbCrlf & _
" end sub"
function btnFuncNameReal
logmessage "hello world"
end function


====Droplist====
New lines in Logic need
  oPSet.AddParameter3 "Team", siString, 0
  & vbCrlf & _
aListTeams = Array( "Konoko", 0, _
on the earlier line.
"TCTF", 1, _
"Syndicate", 2, _
"Neutral", 3, _
"SecurityGuard", 4, _
"RogueKonoko", 5, _
"Switzerland (is melee-immune)", 6, _
"SyndicateAccessory", 7 )
oPPGLayout.AddEnumControl "Team", aListTeams, "", siControlCombo
 


====Radio options====
oPSet.AddParameter3 "Team", siString, 0
aListTeams = Array( "Konoko", 0, _
"TCTF", 1, _
"Syndicate", 2, _
"Neutral", 3, _
"SecurityGuard", 4, _
"RogueKonoko", 5, _
"Switzerland (is melee-immune)", 6, _
"SyndicateAccessory", 7 )
oPPGLayout.AddEnumControl "Team", aListTeams, "", siControlRadio
====Checkbox====
' create checkbox and remove key symboles by setting parameter "Animatable" to false or 0
' CustomProperty.AddParameter3( ScriptName, ValueType, [DefaultValue], [Min], [Max], [Animatable], [ReadOnly] )
oPSet.AddParameter3 "Check1", siBool, , , , 0, 0
oPPGLayout.AddItem "Check1", "Checkbox_caption"


 
====Text input====
====Spacer====
oPSet.AddParameter3 "ParamName", siString
  ' AddSpacer( [Width], [Height] )
oPPGLayout.AddItem "ParamName", "Caption"
  oPPGLayout.AddSpacer 25
 
 
 
 
====Integer input====
==Softimage ICE==
oPSet.AddParameter3 "ParamName", siInt2, , , , false, 0
===Show a simple value in the viewport===
oPPGLayout.AddItem "ParamName", "Caption"
 
If you try to set a value that is below the defined minimum, you will get this error text:
' ERROR : 2006-EDIT-SetValue - Unexpected failure.
' Syntax: PPGname.data, value
' SetValue "Turret.int1", "0"
' ERROR : Überlauf: 'setvalue' - [line ''N'']
German devs? I expected "overflow", not "Überlauf".
 
 
====Droplist====
oPSet.AddParameter3 "Team", siString, 0
aListTeams = Array( "Konoko", 0, _
"TCTF", 1, _
"Syndicate", 2, _
"Neutral", 3, _
"SecurityGuard", 4, _
"RogueKonoko", 5, _
"Switzerland (is melee-immune)", 6, _
"SyndicateAccessory", 7 )
oPPGLayout.AddEnumControl "Team", aListTeams, "", siControlCombo
 
 
====Radio options====
oPSet.AddParameter3 "Team", siString, 0
aListTeams = Array( "Konoko", 0, _
"TCTF", 1, _
"Syndicate", 2, _
"Neutral", 3, _
"SecurityGuard", 4, _
"RogueKonoko", 5, _
"Switzerland (is melee-immune)", 6, _
"SyndicateAccessory", 7 )
oPPGLayout.AddEnumControl "Team", aListTeams, "", siControlRadio
 
 
====Checkbox====
' create checkbox and remove key symboles by setting parameter "Animatable" to false or 0
' CustomProperty.AddParameter3( ScriptName, ValueType, [DefaultValue], [Min], [Max], [Animatable], [ReadOnly] )
oPSet.AddParameter3 "Check1", siBool, , , , 0, 0
oPPGLayout.AddItem "Check1", "Checkbox_caption"
 
 
====Spacer====
  ' AddSpacer( [Width], [Height] )
  oPPGLayout.AddSpacer 25
 
 
==Softimage ICE==
===Show a simple value in the viewport===
[[Image:XSI_ModTool_ICE_workaround_displaying_a_flag.png|thumb|400px]]
 
  CreatePrim "Cube", "MeshSurface"
  CreatePrim "Cube", "MeshSurface"
   
   
2,112

edits