PDA

View Full Version : Recursive functions and MAXScript


Kreuss
11-27-2010, 09:37 PM
First of all, hello everybody!

I was wondering where to ask this, and decided to do it here.

So I have a recursive function like this:
fn recur range objRange spacer outStream = (
for obj in range do (
if (findItem objRange obj != 0) then (
format "%<bone name=\"%\">\n" spacer obj.name to:outStream
format "%<transform x=\"%\" y=\"%\" z=\"%\" qx=\"%\" qy=\"%\" qz=\"%\" qw=\"%\" />\n" (spacer+" ") obj.position.value.x obj.position.value.y obj.position.value.z obj.rotation.x obj.rotation.y obj.rotation.z obj.rotation.w to:outStream
)
range = obj.children
spacer = spacer + " "
recur range objRange spacer outStream
spacer = substring spacer 3 -1
if (findItem objRange obj != 0) then format "%</bone>\n" spacer to:outStream
)
)
It works in a script like this:
skArray = #()
defaultFrame = 0f --in case
oldSliderTime = currentTime
exportBones = #()
spacer = " "

outStreamBones = StringStream ""

fn recur range objRange spacer outStream = (
for obj in range do (
if (findItem objRange obj != 0) then (
format "%<bone name=\"%\">\n" spacer obj.name to:outStream
format "%<transform x=\"%\" y=\"%\" z=\"%\" qx=\"%\" qy=\"%\" qz=\"%\" qw=\"%\" />\n" (spacer+" ") obj.position.value.x obj.position.value.y obj.position.value.z obj.rotation.x obj.rotation.y obj.rotation.z obj.rotation.w to:outStream
)
range = obj.children
spacer = spacer + " "
recur range objRange spacer outStream
spacer = substring spacer 3 -1
if (findItem objRange obj != 0) then format "%</bone>\n" spacer to:outStream
)
)

for obj in objects do (
if obj.parent == undefined then (
if (ClassOf obj == Dummy) or (ClassOf obj == BoneGeometry) then append skArray obj
)
)

for obj in objects do append exportBones obj

format "<library>\n" to:outStreamBones
format " <addon plugin=\"crystalspace.skeletalanimation.loader\">\n" to:outStreamBones
format " <skeleton name=\"default_skeleton\">\n" to:outStreamBones

with redraw off
sliderTime = defaultFrame
recur skArray exportBones spacer outStreamBones
format " </skeleton>\n" to:outStreamBones
format " </addon>\n" to:outStreamBones
format "</library>\n" to:outStreamBones

sliderTime = oldSliderTime

seek outStreamBones 0
while not (eof outStreamBones) do format "%\n" (readline outStreamBones)
close outStreamBones
But somewhy It doesn't work in a more complicated one:
MacroScript CS3D_Char_Exporter
Category: "cs3d"
InternalCategory: "CrystalSpace"
ButtonText: "CS3D Char Exporter"
Tooltip: "Export Char to CS"
Icon:#("Maxscript",1)
(
rollout main "Export Char to CS" width:210 height:432
(
label lblCharDir "Export to directory:" pos:[0,0] width:130 height:19
label lblVersion "Ver." pos:[162,0] width:40 height:19
edittext edtCharDir "" pos:[-4,15] width:201 height:19
edittext edtCharFile "With filename:" pos:[0,35] width:197 height:19
checkbox chkDebug "Debug?" pos:[0,55] width:90 height:19 checked:true
edittext edtCharScale "Scale:" pos:[100,55] width:97 height:19
checkbox chkTDir "Copy textures to destination dir:" pos:[0,95] width:192 height:19 checked:true
edittext edtTDir "Relative textures dir:" pos:[0,115] width:197 height:19 enabled:true
checkbox chkNormals "Export normals (much longer!)" pos:[0,155] width:197 height:19
button btnExport "Export!" pos:[0,175] width:197 height:20

on main open do
(
global confFile = (GetDir #ui) + "\\" + "MacroScripts" + "\\" + "cs3dexp-conf-animesh.ini"
version = .01 as String
lblVersion.text = "V." + version

-- get default scale from custom property
customPropNumber = fileProperties.findProperty #custom "scale"
if (customPropNumber != 0) then CharScale = fileProperties.getPropertyValue #custom customPropNumber
else CharScale = 1

confFileOpen = openFile confFile
if (confFileOpen != undefined) then
(
if (not eof confFileOpen) then
(
CharDirIn = getINISetting (confFile) "Paths" "CharDirIni"
CharFileIn = getINISetting (confFile) "Paths" "CharFileIni"
TexDirIn = getINISetting (confFile) "Paths" "TexDirIni"
)
else
(
CharDirIn = ""
CharFileIn = ""
TexDirIn = ""
)
close confFileOpen
)
else
(
CharDirIn = "c:\\cs3d"
CharFileIn = "char"
TexDirIn = "tex"
)
edtCharDir.text = CharDirIn
edtCharFile.text = CharFileIn
edtCharScale.text = (CharScale as string)
edtTDir.text = TexDirIn
)
on btnExport pressed do
(
if (customPropNumber != 0) then (
fileProperties.deleteProperty #custom "scale"
fileProperties.addProperty #custom "scale" (edtCharScale.text as string)
)
format "edtCharScale.text - %, CharScale - %" edtCharScale.text CharScale

global CharFileName = filenameFromPath edtCharFile.text
global CharDirOut = (getFilenamePath edtCharDir.text) + (filenameFromPath edtCharDir.text)
global CharScaleOut = edtCharScale.text
global TexDirOut = (getFilenamePath edtTDir.text) + (filenameFromPath edtTDir.text)

-- parameters for scaling and relocation

setINISetting (confFile) "Paths" "CharDirIni" CharDirOut
setINISetting (confFile) "Paths" "CharFileIni" CharFileName
setINISetting (confFile) "Settings" "CharScaleIni" CharScaleOut
setINISetting (confFile) "Paths" "TexDirIni" TexDirOut

DOSCommand ("mkdir " + CharDirOut)
CharFileOut = createFile (CharDirOut + "\\" + CharFileName)
SkelFileOut = createFile (CharDirOut + "\\" + CharFileName + "-skel" )
MeshFileOut = createFile (CharDirOut + "\\" + CharFileName + "-mesh" )
outStreamMain = StringStream ""
outStreamAnim = StringStream ""
outStreamBones = StringStream ""

-------------
--Functions--
-------------

--------------------------
--Skeleton Export: Bones--
--------------------------
skArray = #()
defaultFrame = 0f --in case
oldSliderTime = currentTime
exportBones = #()
spacer = " "

outStreamBones = StringStream ""

fn recur range objRange spacer outStream = (
for obj in range do (
if (findItem objRange obj != 0) then (
format "%<bone name=\"%\">\n" spacer obj.name to:outStream
format "%<transform x=\"%\" y=\"%\" z=\"%\" qx=\"%\" qy=\"%\" qz=\"%\" qw=\"%\" />\n" (spacer+" ") obj.position.value.x obj.position.value.y obj.position.value.z obj.rotation.x obj.rotation.y obj.rotation.z obj.rotation.w to:outStream
)
range = obj.children
spacer = spacer + " "
recur range objRange spacer outStream
spacer = substring spacer 3 -1
if (findItem objRange obj != 0) then format "%</bone>\n" spacer to:outStream
)
)

for obj in objects do (
if obj.parent == undefined then (
if (ClassOf obj == Dummy) or (ClassOf obj == BoneGeometry) then append skArray obj
)
)

for obj in objects do append exportBones obj

--format "<library>\n" to:outStreamBones
format " <addon plugin=\"crystalspace.skeletalanimation.loader\">\n" to:outStreamBones
format " <skeleton name=\"default_skeleton\">\n" to:outStreamBones

with redraw off
sliderTime = defaultFrame
recur skArray exportBones spacer outStreamBones
format " </skeleton>\n" to:outStreamBones
format " </addon>\n" to:outStreamBones
format "</library>\n" to:outStreamBones

sliderTime = oldSliderTime

--seek outStreamBones 0
--while not (eof outStreamBones) do format "%\n" (readline outStreamBones)
--close outStreamBones
-------------------------------
--Skeleton Export: Animations--
-------------------------------
keys = #()
forceAllFrames = false
forceStartEndFrames = true
startFrame = 0f
endFrame = animationRange.End
outStreamAnim = StringStream ""

oldSliderTime = currentTime

for obj = 1 to objects.count do (
keysTmp = #()
keysTmp1 = #()
keysTmp2 = #()

if forceStartEndFrames then(
append keysTmp startFrame
append keysTmp endFrame
)

for i in objects[obj].position.controller.keys do append keysTmp i.time
for i in objects[obj].rotation.controller.keys do append keysTmp i.time

sort keysTmp

for i=1 to keysTmp.count do (
if (keysTmp[i] != keysTmp[i+1]) then append keysTmp1 keysTmp[i]
)

with redraw off
for i=1 to keysTmp1.count do (
sliderTime = keysTmp1[i]
keysTmp = #()
keysTmp[1] = keysTmp1[i]
keysTmp[2] = objects[obj].position.value.x --(in coordsys parent objects[obj].position.x)
keysTmp[3] = objects[obj].position.value.y
keysTmp[4] = objects[obj].position.value.z

keysTmp[5] = objects[obj].rotation.x
keysTmp[6] = objects[obj].rotation.y
keysTmp[7] = objects[obj].rotation.z
keysTmp[8] = objects[obj].rotation.w
keysTmp2[i] = keysTmp
)
keys[obj] = keysTmp2
)

format "<library>\n" to:outStreamAnim
format " <addon plugin=\"crystalspace.skeletalanimation.loader\">\n" to:outStreamAnim
format " <animationpacket name=\"default_rig_packet\">\n" to:outStreamAnim
format " <animation name=\"default_animation\">\n" to:outStreamAnim
for i=1 to keys.count do (
format " <channel bone=\"%\">\n" i to:outStreamAnim
for j=1 to keys[i].count do (
format " <key time=\"%\" x=\"%\" y=\"%\" z=\"%\" qx=\"%\" qy=\"%\" qz=\"%\" qw=\"%\" />\n" (keys[i][j][1].ticks/4800 as float) keys[i][j][2] keys[i][j][3] keys[i][j][4] keys[i][j][5] keys[i][j][6] keys[i][j][7] keys[i][j][8] to:outStreamAnim
)
format " </channel>\n\n" to:outStreamAnim
)
format " </animation>\n" to:outStreamAnim
format " </animationpacket>\n" to:outStreamAnim
format " </addon>\n" to:outStreamAnim
--format "</library>\n" to:outStreamAnim
sliderTime = oldSliderTime

--seek outStreamAnim 0
--while not (eof outStreamAnim) do format "%\n" (readline outStreamAnim)
--close outStreamAnim
--------------------
--Mesh File Export--
--------------------



--------------------
--Main File Export--
--------------------

format "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n" to:outStreamMain
format "<library>\n" to:outStreamMain
format " <plugins>\n" to:outStreamMain
format " <plugin name=\"skeletonfact\">crystalspace.mesh.loader.factory.skeleton\n" to:outStreamMain
format " <plugin name=\"animesh\">crystalspace.mesh.loader.animesh\n" to:outStreamMain
format " <plugin name=\"animeshfact\">crystalspace.mesh.loader.factory.animesh\n" to:outStreamMain
format " </plugins>\n" to:outStreamMain
format " <textures>\n" to:outStreamMain
format " </textures>\n" to:outStreamMain
format " <materials>\n" to:outStreamMain
format " </materials>\n" to:outStreamMain
format " <library>/%-skel\n" CharFileName to:outStreamMain
format " <library>/%-mesh\n" CharFileName to:outStreamMain
format "</library>\n" to:outStreamMain

seek outStreamMain 0
while not (eof outStreamMain) do format "%\n" (readline outStreamMain) to:CharFileOut
close outStreamMain
close CharFileOut

seek outStreamAnim 0
while not (eof outStreamAnim) do format "%\n" (readline outStreamAnim) to:SkelFileOut
close outStreamAnim
--close SkelFileOut

seek outStreamBones 0
while not (eof outStreamBones) do format "%\n" (readline outStreamBones) to:SkelFileOut
close outStreamBones
close SkelFileOut

close MeshFileOut

)
)
gw = newRolloutFloater "Export Char to CS" 210 432
addRollout main gw
)
Here is the error that I'm getting:
-- Error occurred during fileIn in <File:O:\prj\3ds\export.cs3d.animesh\main3-tmp.mcr>
-- Error occurred in anonymous codeblock; filename: O:\prj\3ds\export.cs3d.animesh\main3-tmp.mcr; position: 1501
>> MAXScript FileIn Exception: -- Compile error: No outer local variable references permitted here: recur
-- In line: recur r <<

I'm a bit at a loss... Since function itself is copy&pasted (even if I mistakenly posted here wrong versions of scripts). And last example #3 works Ok if I evaluate Example #2 before it...
I tried to move this function to "on main open" and other places but it seems it has no effect.
And I certainly have to use something like this, because I have no idea how "deep" skeleton tree will go...
Am I really screwed something up?

Kreuss
11-30-2010, 11:04 AM
Ok, seems I was able to fool 3ds by moving section that's between "Skeleton Export: Bones" and "Skeleton Export: Animations" to another file using fileIn.
Now everything's Ok. But questions still remain unanswered...

Edit: Looks like the mistake was a silly one. I needed to write line "global recur" for this script to work correctly...

CGTalk Moderation
11-30-2010, 11:04 AM
This thread has been automatically closed as it remained inactive for 12 months. If you wish to continue the discussion, please create a new thread in the appropriate forum.