macroScript spineGenerator category: "Aeron" tooltip: "Spine Generator" ButtonText: "Spine Generator" --contact me for any queries, bugs or requests Aeron Miles: aeronmiles@yahoo.co.uk --check out my blog: http://cgvector.wordpress.com/ --v1.0 ( -- BEGIN -- variables struct str_spineGenerator ( curve, geoSource, geoGenerated, nVerterbrae, isGenerated, axis, flipped, rotStart, rotEnd ) local dialogSpGn local dialogPos, dataInd, curveNames, geoNames local setDialogFocus, addCurveN, addGeo, removeData local deleteGeom, isGeneratable, generate, setAxis, rotateVerterbrae, collapseToMesh local WM_SETREDRAW, cmdPan_hwnd, disableCPRedraw, enableCPRedraw global g_spGnData global g_spGnCurrentObj if g_spGnData == undefined do ( g_spGnData = #( undefined ) ) if g_spGnData[1] == undefined do ( g_spGnCurrentObj = undefined ) try ( if g_spGnData.count > 1 and g_spGnData[1] == undefined do ( g_spGnData = #( undefined ) g_spGnCurrentObj = undefined ) ) catch() global g_spGnCheckDeleted, g_closeSpGn --callbacks callbacks.addScript #nodePreDelete "g_spGnCheckDeleted()" id:#spGng_checkDeleted callbacks.addScript #filePreOpen "g_closeSpGn()" id:#spGng_close --functions fn shapeFilt o = ( superClassOf o == shape ) fn geoFilt o = ( superClassOf o == GeometryClass ) fn g_spGnCheckDeleted = ( try ( for i = 1 to g_spGnData.count do ( if isDeleted g_spGnData[i].curve do ( deleteItem g_spGnData i ) ) ) catch() setDialogFocus( g_spGnCurrentObj ) ) fn g_closeSpGn = ( try( destroyDialog dialogSpGn ) catch() ) fn dialogPos = ( mPos = mouse.screenpos dPos = point2 0 0 if mPos.x <= 75 then (dPos.x = 75) else (dPos.x = mPos.x) if mPos.y <= 200 then (Pos.y = 200) else (dPos.y = mPos.y) dPos ) fn dataInd obj = ( if obj != undefined do ( index = 1 g_spGnCurrentObj = obj sDI = false for i = 1 to g_spGnData.count do ( if g_spGnData[i] != undefined and g_spGnData[i].curve != undefined and g_spGnData[i].curve.name == obj.name do ( sDI = true index = i ) ) if sDI == true then ( index ) else if g_spGnData[g_spGnData.count] != undefined and g_spGnData[g_spGnData.count].curve != undefined then ( index = g_spGnData.count + 1 ) else if sDI == false then ( index = g_spGnData.count ) ) ) fn curveNames = ( ind = dataInd( g_spGnCurrentObj ) if ind != undefined then ( for o in g_spGnData collect o.curve.name ) else ( #() ) ) fn geoNames = ( ind = dataInd(g_spGnCurrentObj) if ind != undefined then ( for o in g_spGnData[ind].geoSource collect o.name ) else ( #() ) ) fn setDialogFocus obj = ( ind = dataInd( g_spGnCurrentObj ) if obj != undefined then ( g_spGnCurrentObj = obj dialogSpGn.lbCurve.items = curveNames() dialogSpGn.lbGeom.items = geoNames() dialogSpGn.spnRotationStart.value = g_spGnData[ind].rotStart dialogSpGn.spnRotationEnd.value = g_spGnData[ind].rotEnd dialogSpGn.spnNoVerterbrae.value = g_spGnData[ind].nVerterbrae case of ( ( g_spGnData[ind].axis == "x" ): ( dialogSpGn.cbConstrainX.checked = true dialogSpGn.cbConstrainY.checked = false dialogSpGn.cbConstrainZ.checked = false ) ( g_spGnData[ind].axis == "y" ): ( dialogSpGn.cbConstrainX.checked = false dialogSpGn.cbConstrainY.checked = true dialogSpGn.cbConstrainZ.checked = false ) ( g_spGnData[ind].axis == "z" ): ( dialogSpGn.cbConstrainX.checked = false dialogSpGn.cbConstrainY.checked = false dialogSpGn.cbConstrainZ.checked = true ) ) if g_spGnData[ind].flipped == true then ( dialogSpGn.cbConstrainFlip.checked = true ) else ( dialogSpGn.cbConstrainFlip.checked = false ) ) else ( dialogSpGn.lbCurve.items = #() dialogSpGn.lbGeom.items = #() dialogSpGn.spnRotationStart.value = 0 dialogSpGn.spnRotationEnd.value = 0 dialogSpGn.cbConstrainX.checked = false dialogSpGn.cbConstrainY.checked = false dialogSpGn.cbConstrainZ.checked = true dialogSpGn.cbConstrainFlip.checked = false dialogSpGn.spnNoVerterbrae.value = 12 ) ) fn addCurveN curve = ( if curve != undefined do ( g_spGnCurrentObj = curve ind = dataInd( curve ) if ind != undefined do ( if g_spGnData[ind] == undefined then ( g_spGnData[ind] = str_spineGenerator curve:curve geoSource:#() geoGenerated:#() nVerterbrae:12 isGenerated:false axis:"z" flipped:false rotStart:0 rotEnd:0 ) else ( g_spGnData[ind].curve = curve ) ) ) ) fn addCurve curve = ( if curve.count > 1 then ( for i = 1 to curve.count do ( addCurveN( curve[i] ) ) )else ( addCurveN( curve[1] ) ) setDialogFocus( curve[1] ) ) fn addGeo geo = ( if geo != undefined do ( ind = dataInd( g_spGnCurrentObj ) if ind != undefined then ( if g_spGnData[ind] == undefined then ( g_spGnData[ind] = str_spineGenerator curve:undefined geoSource:geo geoGenerated:#() nVerterbrae:12 isGenerated:false axis:"z" flipped:false rotStart:0 rotEnd:0 ) else ( g_spGnData[ind].geoSource = geo ) ) else ( g_spGnData[1] = str_spineGenerator curve:undefined geoSource:geo geoGenerated:#() nVerterbrae:12 isGenerated:false axis:"z" flipped:false rotStart:0 rotEnd:0 ) ) setDialogFocus( g_spGnCurrentObj ) ) fn removeData = ( ind = dataInd( g_spGnCurrentObj ) if ind != undefined do ( deleteItem g_spGnData ind if g_spGnData.count > 0 then ( g_spGnCurrentObj = g_spGnData[1].curve setDialogFocus( g_spGnCurrentObj ) ) else ( g_spGnData[1] = undefined g_spGnCurrentObj = undefined setDialogFocus( g_spGnCurrentObj ) ) ) ) fn deleteGeom = ( try ( ind = dataInd( g_spGnCurrentObj ) try ( for i in g_spGnData[ind].geoGenerated do ( delete i ) ) catch() g_spGnData[Ind].geoGenerated = #() dialogSpGn.lbGeom.items = #() g_spGnData[Ind].isGenerated = false ) catch() ) fn isGeneratable = ( ind = dataInd( g_spGnCurrentObj ) if ind != undefined and g_spGnData[ind] != undefined and g_spGnData[ind].geoSource.count > 1 and g_spGnData[ind].curve != undefined then ( true ) else ( false ) ) fn disableCPRedraw = ( -- disable command panel flickering WM_SETREDRAW=0xB cmdPan_hwnd = if (windows.getChildHWND #max "Command Panel") == undefined then windows.getChildHWND 0 "Command Panel" else windows.getChildHWND #max "Command Panel" -- windows.sendmessage cmdPan_hwnd[1] WM_SETREDRAW 0 0 ) fn enableCPRedraw = ( windows.sendmessage cmdPan_hwnd[1] WM_SETREDRAW 1 0 -- rferesh command panel ) fn setAllDataAsCurrent = ( for i = 1 to g_spGnData.count do ( --( curve, geoSource, geoGenerated, nVerterbrae, isGenerated, axis, flipped, rotStart, rotEnd, instanced ) ind = dataInd( g_spGnCurrentObj ) g_spGnData[i].geoSource = g_spGnData[ind].geoSource g_spGnData[i].nVerterbrae = g_spGnData[ind].nVerterbrae case of ( ( g_spGnData[ind].axis == "x" ): g_spGnData[i].axis = "x" ( g_spGnData[ind].axis == "y" ): g_spGnData[i].axis = "y" ( g_spGnData[ind].axis == "z" ): g_spGnData[i].axis = "z" ) g_spGnData[i].flipped = g_spGnData[ind].flipped g_spGnData[i].rotStart = g_spGnData[ind].rotStart g_spGnData[i].rotEnd = g_spGnData[ind].rotEnd ) ) fn generate = with redraw off ( disableCPRedraw() local ind = dataInd( g_spGnCurrentObj ) if isGeneratable() do ( if g_spGnData[ind].isGenerated == true do ( deleteGeom() ) nI = g_spGnData[ind].geoSource.count - 1 g_spGnData[ind].nVerterbrae = dialogSpGn.spnNoVerterbrae.value nV = g_spGnData[ind].nVerterbrae nJ = floor (nV / nI) as integer remainderV = nV - nJ * nI fn createSpGeo ind i nI j nJ nV = ( -- create geometry geomJ = copy g_spGnData[ind].geoSource[i] geomJ.wirecolor = color 110 110 110 geomJ.name = g_spGnData[ind].geoSource[i].name + "_" + j as string append g_spGnData[ind].geoGenerated geomJ -- constrain geo to path and set position pc = path_constraint() pc.path = g_spGnData[ind].curve pc.allowUpsideDown = on pc.follow = true increment = (100 / (nV-1)) pc.percent = (((nJ * i) - nJ) * increment) + (j * increment) - increment geomJ.position.controller = pc geomJ.position.controller.axisFlip = g_spGnData[ind].flipped -- add morphers and set weights mm = morpher() mm.Autoload_of_targets = 1 WM3_MC_BuildFromNode mm 2 g_spGnData[ind].geoSource[i] WM3_MC_BuildFromNode mm 1 g_spGnData[ind].geoSource[i+1] w = ((j as float / nJ as float) * 100.0) WM3_MC_SetValue mm 2 (100.0 - w) WM3_MC_SetValue mm 1 w addmodifier geomJ mm ) for i = 1 to nI do ( for j = 1 to nJ do ( createSpGeo ind i nI j nJ nV ) ) for i = 1 to remainderV do ( jj = nJ + i createSpGeo ind nI nI jj nJ nV ) g_spGnData[ind].isGenerated = true setDialogFocus( g_spGnCurrentObj ) enableCPRedraw() setAxis() rotateVerterbrae() ) ) fn setAxis = ( ind = dataInd( g_spGnCurrentObj ) axis = g_spGnData[ind].axis if g_spGnData[ind].isGenerated == true do ( case of ( (axis == "x") : ( for i = 1 to g_spGnData[ind].geoGenerated.count do ( g_spGnData[ind].geoGenerated[i].pos.controller.axis = 0 ) ) (axis == "y") : ( for i = 1 to g_spGnData[ind].geoGenerated.count do ( g_spGnData[ind].geoGenerated[i].pos.controller.axis = 1 ) ) (axis == "z") : ( for i = 1 to g_spGnData[ind].geoGenerated.count do ( g_spGnData[ind].geoGenerated[i].pos.controller.axis = 2 ) ) ) ) ) fn rotateVerterbrae = ( ind = dataInd( g_spGnCurrentObj ) valStart = g_spGnData[ind].rotStart valEnd = g_spGnData[ind].rotEnd rotAngle = (valStart - valEnd) / g_spGnData[ind].geoGenerated.count n = 0 for i in g_spGnData[ind].geoGenerated do ( n += 1 -- Reset the object's transformation matrix so that it only includes position and scale information. Doing this clears out any previous object rotation. translateMat = transMatrix i.transform.pos scaleMat = scaleMatrix i.transform.scale i.transform = scaleMat * translateMat case of ( ( g_spGnData[ind].axis == "x" ) : in coordsys local rotate i (angleaxis (valStart + ((n * rotAngle) - rotAngle)) [1,0,0]) ( g_spGnData[ind].axis == "y" ) : in coordsys local rotate i (angleaxis (valStart + ((n * rotAngle) - rotAngle)) [0,1,0]) ( g_spGnData[ind].axis == "z" ) : in coordsys local rotate i (angleaxis (valStart + ((n * rotAngle) - rotAngle)) [0,0,1]) ) ) ) fn collapseToMesh = ( disableCPRedraw() try ( ind = dataInd( g_spGnCurrentObj ) baseMesh = convertToPoly(g_spGnData[ind].geoGenerated[1]) objTM = baseMesh.transform baseMesh.pos.controller = Position_XYZ () baseMesh.rotation.controller = Euler_XYZ () baseMesh.transform = objTM for i = 2 to g_spGnData[ind].geoGenerated.count do ( baseMesh.attach g_spGnData[ind].geoGenerated[i] baseMesh ) g_spGnData[ind].geoGenerated = #(baseMesh) resetxform baseMesh convertToPoly(baseMesh) ) catch() enableCPRedraw() ) rollout spGnHelp "Spine Generator Help" width:600 height:600 ( label info1 "Select curve/s to act as your spine constraint" label info2a "Pick the vertebrae geometry minimum of two selections. TIP: selections can be multiples of the same object." label info2b "NOTE: VERTEBRAE MUST HAVE SAME UNDERLYING TOPOLOGY TO ALLOW FOR THE MORHPER MODIFIER" label space1 "" label info4 "Set the desired parameters for the spine. TIP: can be edited after generation" label space2 "" label info6 "Use Generate Current Spine to create/update the currently selected spine" label info7a "Use Generate All Spines to create all the spines with the same parametes as the currently selected spine." label info7b "This includes the verterbrae geometry selection" label space3 "" label info8 "Collapse to Mesh converts the current spine to an Editable Poly" label info9 "Same as above but for all spines" hyperLink info10 "aeronmiles@yahoo.co.uk" align:#center color:[255,1,1] hoverColor:[255,1,1] visitedColor:[255,1,1] address:"mailto:aeronmiles@yahoo.co.uk" hyperLink info11 "cgvector.wordpress.com" align:#center color:[255,1,1] hoverColor:[255,1,1] visitedColor:[255,1,1] address:"http://cgvector.wordpress.com" ) --dialog try ( destroyDialog dialogSpGn ) catch() rollout dialogSpGn "Spine Generator" width:198 height:550 ( -- begin dialogSpGn button btnCurve "Add Selected Curves" pos:[10, 10] width:155 height:20 button btnCurveSelect "Select Current Curve" pos:[10, 30] width:155 height:20 button btnRemoveDataAll "x" pos:[170, 10] width:15 height:20 button btnRemoveData "x" pos:[170, 30] width:15 height:20 button btnHelp "?" pos:[170, 50] width:15 height:20 listbox lbCurve "Curves:" pos:[10, 55] width:180 height:8 button btnGeom "Pick Verterbrae For Selected" pos:[10, 190] width:155 height:20 button btnGeomAll "Pick Verterbrae For All" pos:[10, 210] width:155 height:20 button btnGeomSelect "Select" pos:[10, 2130] width:155 height:20 button btnGeomDelete "x" pos:[170, 190] width:15 height:20 button btnGeomDeleteAll "x" pos:[170, 210] width:15 height:20 listbox lbGeom "Geometry:" pos:[10, 235] width:180 height:8 spinner spnNoVerterbrae "No Vertebrae:" pos:[90,365] width:100 height:16 range:[2,999999999,12] type:#integer checkbox cbConstrainX "X" pos:[10,380] width:31 height:15 checkbox cbConstrainY "Y" pos:[40,380] width:31 height:15 checkbox cbConstrainZ "Z" pos:[70,380] width:31 height:15 checked: true checkbox cbConstrainFlip "Flip" pos:[100,380] width:35 height:15 spinner spnRotationStart "Rotation Start:" pos:[90,395] width:100 height:16 range:[-9999999,9999999, 0] spinner spnRotationEnd "Rotation End:" pos:[90,410] width:100 height:16 range:[-9999999,9999999, 0] button btnGenerateSpine "Generate Current Spine" pos:[5,430] width:190 height:25 button btnGenerateAllSpine "Generate All Spines" pos:[5,455] width:190 height:25 button btnCollapseToMesh "Collapse to Mesh" pos:[5,490] width:190 height:25 button btnCollapseAllToMesh "Collapse All to Meshes" pos:[5,515] width:190 height:25 on btnHelp pressed do ( spineHelpFloater = newRolloutFloater "Spine Generator Help" 600 300 addrollout spGnHelp spineHelpFloater ) on btnCurve pressed do ( addCurve( selection ) max select none ) on btnCurveSelect pressed do ( try( select g_spGnCurrentObj ) catch() ) on btnRemoveData pressed do ( deleteGeom() removeData() ) on btnRemoveDataAll pressed do ( while g_spGnData[1] != undefined do ( g_spGnCurrentObj = g_spGnData[1].curve deleteGeom() removeData() ) ) on lbCurve selected ind do ( obj = (getNodeByName dialogSpGn.lbCurve.selected) setDialogFocus( obj ) ) on btnGeom pressed do ( geo = pickObject count:#multiple filter:geoFilt addGeo( geo ) ind = dataInd( g_spGnCurrentObj ) try( if g_spGnData[ind].isGenerated == true do( generate() ) )catch() ) on btnGeomAll pressed do ( geo = pickObject count:#multiple filter:geoFilt for i = 1 to g_spGnData.count do ( g_spGnCurrentObj = g_spGnData[i].curve addGeo( geo ) try( if g_spGnData[ind].isGenerated == true do( generate() ) )catch() ) ) on btnGeomSelect pressed do ( try ( ind = dataInd( g_spGnCurrentObj ) select g_spGnData[ind].geoGenerated ) catch() ) on btnGeomDelete pressed do ( deleteGeom() ind = dataInd( g_spGnCurrentObj ) g_spGnData[Ind].geoSource = #() ) on btnGeomDeleteAll pressed do ( for i = 1 to g_spGnData.count do ( g_spGnCurrentObj = g_spGnData[i].curve deleteGeom() ind = dataInd( g_spGnCurrentObj ) g_spGnData[Ind].geoSource = #() ) ) on spnNoVerterbrae entered do ( ind = dataInd( g_spGnCurrentObj ) g_spGnData[ind].nVerterbrae = spnNoVerterbrae.value if g_spGnData[ind].isGenerated == true do ( generate() ) ) on spnRotationStart changed val do ( ind = dataInd( g_spGnCurrentObj ) g_spGnData[ind].rotStart = val rotateVerterbrae() ) on spnRotationEnd changed val do ( ind = dataInd( g_spGnCurrentObj ) g_spGnData[ind].rotEnd = val rotateVerterbrae() ) on btnGenerateSpine pressed do ( generate() ) on btnGenerateAllSpine pressed do ( setAllDataAsCurrent() for i = 1 to g_spGnData.count do ( g_spGnCurrentObj = g_spGnData[i].curve generate() ) ) on btnCollapseToMesh pressed do ( collapseToMesh() ) on btnCollapseAllToMesh pressed do ( for i = 1 to g_spGnData.count do ( g_spGnCurrentObj = g_spGnData[i].curve collapseToMesh() ) ) on cbConstrainX changed state do ( if state == false do ( cbConstrainX.checked = true ) cbConstrainY.checked = false cbConstrainZ.checked = false ind = dataInd( g_spGnCurrentObj ) g_spGnData[ind].axis = "x" if g_spGnData[ind].isGenerated == true do ( generate() ) ) on cbConstrainY changed state do ( if state == false do ( cbConstrainY.checked = true ) cbConstrainX.checked = false cbConstrainZ.checked = false ind = dataInd( g_spGnCurrentObj ) g_spGnData[ind].axis = "y" if g_spGnData[ind].isGenerated == true do ( generate() ) ) on cbConstrainZ changed state do ( if state == false do ( cbConstrainZ.checked = true ) cbConstrainX.checked = false cbConstrainY.checked = false ind = dataInd( g_spGnCurrentObj ) g_spGnData[ind].axis = "z" if g_spGnData[ind].isGenerated == true do ( generate() ) ) on cbConstrainFlip changed state do ( ind = dataInd( g_spGnCurrentObj ) if state == false then ( g_spGnData[ind].flipped = false ) else ( g_spGnData[ind].flipped = true ) if g_spGnData[ind].isGenerated == true do ( generate() ) ) -- initialize dialogSpGn on dialogSpGn open do ( if g_spGnData == undefined do ( g_spGnData = #( undefined ) ) g_spGnCheckDeleted() setDialogFocus( g_spGnCurrentObj ) ) on dialogSpGn close do ( callbacks.removeScripts #nodePreDelete id:#spGng_spGnCheckDeleted ) ) -- end dialogSpGn createdialog dialogSpGn pos: (dialogPos() - [75,200]) ) -- END