JurassicParkTrespasser/jp2_pc/Tools/MAXScript/Placementmanager.ms

796 lines
25 KiB
Plaintext

-- *******************************************************************************************
-- *
-- * Copyright © DreamWorks Interactive, 1997
-- *
-- * Contents:
-- * Implementation of PlacementManager.ms
-- * Bugs:
-- *
-- * To do:
-- *
-- * Notes:
-- *
-- *******************************************************************************************
-- [1]: Key Object Name <string>
-- [2]: Type; #Child or #Parent <name>, #unused
-- [3]: ChildIndices #(int, int, int, ...)
-- [4]: Parent Index <int>
-- [5]: Scale Offset <point3>
-- [6]: Initial Vector <point3>; (c.pos - p.pos) * (p.rotation) as matrix3
-- [7]: Offset Quaternion rotation
-- [8]: Children Scale <bool>
-- [9]: Initial Rotation <quat>
-- *******************************************************************************************
fn AvgScale scl = ((scl.x + scl.y + scl.z) * 0.33333333)
fn InstanceNum CName =
(
local DashPos = -1
for i = 1 to CName.count do
if CName[i] == "-" do
DashPos = i
if DashPos == -1 then
return undefined
else
(
Num = (substring CName (DashPos + 1) (CName.count - DashPos))
return Num
)
)
fn KeyName CName =
(
local DashPos = -1
for i = 1 to CName.count do
if CName[i] == "-" do
DashPos = i
if DashPos == -1 then
return CName
else
return (substring CName 1 (DashPos - 1))
)
fn Prune00s CName =
(
TempName = CName
if (substring TempName (TempName.count - 2) 3) == "-00" do
TempName = substring TempName 1 (TempName.count - 3)
return TempName
)
fn FindByName CName =
(
for o in objects do
if (findString o.name CName) != undefined do
return o
return undefined
)
fn Find00th CName =
(
SearchName = (CName + "-00")
for o in objects do
if o.name == SearchName do
return o
return undefined
)
fn RotChild p c InitialVec InitialRot =
(
ParentRot = p.rotation
cm = matrix3 1
NewRot = (rotate cm (inverse ParentRot))
c.rotation = ParentRot + InitialRot
NewVec = InitialVec * cm
c.pos = p.pos + NewVec
)
-- Places an object [o], relative to another objects pos [p] on normal [N] ad distance [m].
fn PlcObj p o N m = o.pos = p - (N) * m
-- returns the magnitude of a vector
fn MagV vec = (sqrt((vec.x)^2 + (vec.y)^2 + (vec.z)^2))
-- takes two non-normalized vectors and returns a quaternion rotation between them
fn QuatFromVec v1 v2 =
(
MagV1 = MagV v1
MagV2 = MagV v2
x = (cross v1 v2)
xN = normalize x
MagX = MagV x
theta = asin(MagX/(MagV1 * MagV2))
return (quat theta xN)
)
-- returns a normalized vector between two objects
fn GetNormalDirVec o1 o2 = normalize (o2.pos - o1.pos)
-- returns a non-normalized vector between two objects
fn GetDirVec o1 o2 = (o2.pos - o1.pos)
-- returns a ray from one object to another
fn CreateRay o1 o2 =
return (ray o1.pos (GetDirVec o1 o2))
-- Builds the name list and object definitions/offsets when adding/removing things from a hierarchy
fn BuildNameList i dta NameData tab ObjArray =
(
local tab2 = tab
local CData = dta[i]
tabstr = ""
for k = 1 to tab2 do tabstr = tabstr + " "
append NameData (tabstr + CData[1])
append ObjArray CData[9]
if CData[3].count != 0 do
for j = 1 to CData[3].count do
(
local i2 = CData[3][j]
BuildNameList i2 dta NameData (tab2 + 1) ObjArray
)
)
-- updates the offset pos/rot/scale from a parent object
fn UpdatePositions i dta =
(
local CData = dta[i]
-- format "CData[3].count = %\n" CData[3].count
if CData[3].count > 0 do
for j = 1 to CData[3].count do
(
-- format "j = %\n" j
local CurrentChild = CData[3][j]
local Parent = dta[CurrentChild][4]
if dta[CurrentChild][9] != #NoObject do
(
-- format "dta[CurrentChild][9] is valid...\n"
NewVec = (dta[CurrentChild][6] * (avgScale dta[CurrentChild][5]))
-- RotChild dta[Parent][9] dta[CurrentChild][9] (dta[CurrentChild][6]) dta[CurrentChild][7]
RotChild dta[Parent][9] dta[CurrentChild][9] NewVec dta[CurrentChild][7]
dta[CurrentChild][9].scale = dta[CurrentChild][5]
UpdatePositions CurrentChild dta
)
)
)
-- ******************************************************************************
-- * Update Selection
-- ******************************************************************************
-- i is index of Parent object data into RData#()
-- dta is RData#()
-- NParent is the current parent Object
fn UpdateSelection i dta NParent PScale SclChildren =
(
local debug = false
local ScaleChildren = SclChildren
ParentNum = InstanceNum NParent.name
local CData = dta[i]
-- format "CData[3].count = %\n" CData[3].count
if CData[3].count > 0 do
for j = 1 to CData[3].count do
(
local CurrentChild = CData[3][j]
NewChildName = (dta[CurrentChild][1] + "-" + ParentNum)
if debug do format "NewChildName: %\n" NewChildName
local ChildMesh = #Null
for o in objects do
if o.name == NewChildName do
ChildMesh = o
if ChildMesh != #Null then
(
if debug do format "Found Child Object Match...%: %\n" NewChildName dta[CurrentChild][9]
if (dta[CurrentChild][9] != #NoObject) do
(
if debug do format "% is valid...\n" dta[CurrentChild][9].name
NewVec = (dta[CurrentChild][6] * (dta[CurrentChild][5] * (avgScale NParent.scale)))
if debug do format "OldVec: %\nNewVec: %\n" dta[CurrentChild][6] NewVec
RotChild NParent ChildMesh NewVec dta[CurrentChild][7]
if SclChildren do
(
if debug do format "Scaling Children is active...\n"
NewScale = (dta[CurrentChild][5] * (avgScale NParent.scale))
if debug do format "New Scale: %\n" Newscale
ChildMesh.scale = [Newscale, Newscale, Newscale]
)
UpdateSelection CurrentChild dta NParent PScale ScaleChildren
)
) else (
format "No Match found for Child Object %\n" NewChildName
)
)
)
-- *****************************************************************************************************************************
-- * Start Utility
-- *****************************************************************************************************************************
Utility PlacementManager "Placement Manager"
(
local CParent, CChild, FinalParentPosition,
RData = #(),
ChildrenArray = #(),
ObjArray = #()
local debug = false
group "Current Hierarchy"
(
listbox ObjectNames
checkbox AutoSelect "Auto Select" offset:[0,0]
)
group "Selection Tools"
(
button PropagateInstances "Propagate to Instances" width:140
button SelectGroupMembers "Sel Active Group Members"
checkbox KeepSel "Keep Current Selection"
)
group "Hierarchy Modifications"
(
label ParentLabel "Parent:" align:#left
pickbutton ChooseParent width:100 offset:[20,-20]
ListBox Children "Current Children Set:" height:5
checkbox ScaleChildren "Children scale with Parent" checked:true
button AddChild "Add" width:38 offset:[-53,0]
button RemoveChild "Remove" width:55 offset:[-2,-26]
button ClearList "Clear" width:40 offset:[49,-26]
checkbox AutoClear "AutoClear Parent/Children" checked:true
button CreateRelationship "Create Relationship" width:140
)
button RefreshSelection "Refresh Selection" width:140
label filler
group "Files"
(
button SaveFile "Save" width:70 offset:[-37,0]
button LoadFile "Load" width:70 offset:[37,-26]
label FileInfo
label SaveNow
)
on PropagateInstances pressed do
(
KeyNameArray = #()
for obj in selection do
if findItem KeyNameArray (KeyName obj.name) == 0 do
append KeyNameArray (KeyName obj.name)
oc = 1 / objects.count as float
cnt = 0
ProgressStart "Generating Selection...."
sel = #()
for o in objects where o.isselected == false do
(
cnt += 1
progressUpdate ((cnt * oc) * 100)
if findItem KeyNameArray (KeyName o.name) != 0 do
(
if o.isHidden do unhide o
append Sel o
)
)
selectmore sel
ProgressEnd()
)
-- ******************************************************************************
-- * Select Group Members
-- ******************************************************************************
on SelectGroupMembers pressed do
(
format "%\n" ObjectNames.selection
s = ObjectNames.selection
SelArray = #()
if ObjArray[s] != undefined do
(
if KeepSel.checked == false do
MAX Select None
ParentName = (KeyName ObjArray[s].name)
append SelArray ParentName
-- Find the Parent in RData
PIndex = #Null
for i = 1 to RData.count do
if RData[i][1] == ParentName do
(
PIndex = i
Exit
)
-- Step through the children
if PIndex != #Null do
for i = 1 to RData[PIndex][3].count do
(
CIndex = RData[PIndex][3][i]
append SelArray RData[CIndex][1]
)
if SelArray.count >= 1 do
(
prg = false
oc = Objects.count
ocInv = 1 / oc as float
if oc > 50 do
(
ProgressStart "Generating Selection...."
prg = true
)
cnt = 0
for o in objects do
(
cnt += 1
if prg do progressUpdate ((cnt * ocInv) * 100)
if (findItem SelArray (KeyName o.name)) != 0 do
selectmore o
)
if prg do ProgressEnd()
)
if debug do format "SelArray: %\n" SelArray
)
)
-- ******************************************************************************
-- * Initialize New File
-- ******************************************************************************
on SaveFile pressed do
(
-- if we have something in RData#()
if RData.count >= 2 then
if (CFileName = getSaveFilename caption:"spec file") != undefined do
(
f = createFile CFileName
for i = 1 to RData.count do
(
-- format the index we're in
format "\n:%\n" i to:f
format "%\n" RData[i][1] to:f -- Object Name
if RData[i][2] == #Parent do
format "#Parent\n" to:f
if RData[i][2] == #Child do
format "#Child\n" to:f
format "%\n" RData[i][3].count to:f
if RData[i][3].count == 0 then
(
format "0\n" to:f
) else (
for j = 1 to RData[i][3].count do
format "% " RData[i][3][j] to:f
format "\n" to:f
)
format "%\n" RData[i][4] to:f
if RData[i][5] != #Null then
format "%\n" RData[i][5] to:f
else
format "#Null\n" to:f
if RData[i][6] != #Null then
format "% % %\n" RData[i][6].x RData[i][6].y RData[i][6].z to:f
else
format "#Null\n" to:f
if RData[i][7] != #Null then
format "% % % %\n" RData[i][7].x RData[i][7].y RData[i][7].z RData[i][7].w to:f
else
format "#Null\n" to:f
-- Scale children???
format "%\n" RData[i][8] to:f
)
close f
FileInfoText = (filenameFromPath CFileName)
if FileInfoText.count > 25 do
FileInfoText = ((substring FileInfoText 1 23) + "...")
FileInfo.text = FileInfoText
SaveNow.text = "File has been saved..."
)
else
MessageBox "No Data!"
)
-- ******************************************************************************
-- * Load File
-- ******************************************************************************
on LoadFile pressed do
(
if (OpenFileName = getOpenFilename caption:"Spec File pleeeeze...") != undefined do
(
f = openFile OpenFileName
RData = #()
if debug do format "Reading from File....\n"
while not eof f do
(
CLine = readline f
if CLine[1] == ":" do
(
NData = #()
if CLine[CLine.count] == "\n" do Cline = (substring CLine 1 (CLine.count - 1))
Index = (substring CLine 2 (CLine.count - 1)) as integer
if debug do format "Index: %\n" Index
CLine = Readline f
-- prune off the newline character, if it exists
if CLine[CLine.count] == "\n" do Cline = (substring CLine 1 (CLine.count - 1))
-- this is the object name
NData[1] = CLine
CLine = Readline f
if CLine[CLine.count] == "\n" do Cline = (substring CLine 1 (CLine.count - 1))
if CLine == "#Parent" or CLine == "#parent" do NData[2] = #Parent
if CLine == "#Child" or CLine == "#child" do NData[2] = #Child
-- get the number of children
CLine = (readValue f) as integer
ca = #()
if CLine != 0 then
for i = 1 to CLine do
append ca (readvalue f)
else
CLine = readline f
NData[3] = ca
-- This is the Parent - will be 0 if none
NData[4] = (readValue f) as integer
-- Scale float value
if (tmp = readvalue f) != #Null then
NData[5] = tmp
else
NData[5] = #Null
-- Vector offset
if (tmp = (readvalue f)) != #Null then
NData[6] = [tmp, (ReadValue f), (ReadValue f)]
else
NData[6] = #Null
-- Quaternion rotation
if (tmp = (readvalue f)) != #Null then
NData[7] = quat tmp (ReadValue f) (ReadValue f) (ReadValue f)
else
NData[7] = #Null
NData[8] = readValue f
RData[Index] = NData
)
)
-- Update the interface
if RData.count >= 1 do
(
NameArray = #()
ObjArray = #()
for i = 1 to RData.count do
if (CObj = Find00th RData[i][1]) != undefined then
RData[i][9] = CObj
else
RData[i][9] = #NoObject
for i = 1 to RData.count do
(
if debug do format "%:%\n" i RData[i]
if RData[i][2] == #Parent then
BuildNameList i RData NameArray 0 ObjArray
)
ObjectNames.items = NameArray
FileInfoText = (filenameFromPath OpenFileName)
if FileInfoText.count > 25 do
FileInfoText = ((substring FileInfoText 1 23) + "...")
FileInfo.text = FileInfoText
)
)
)
-- ******************************************************************************
-- * Select Objects from interface
-- ******************************************************************************
on ObjectNames selected s do
if AutoSelect.checked do
if ObjArray.count != 0 do
select ObjArray[s]
-- ******************************************************************************
-- * select Children from interface
-- ******************************************************************************
on Children selected s do
if AutoSelect.checked do
if ChildrenArray.count != 0 do
select ChildrenArray[s]
-- ******************************************************************************
-- * Choose Parent Object
-- ******************************************************************************
on ChooseParent picked obj do
(
if FindItem ChildrenArray obj == 0 then
(
if (avgScale obj.scale) == 1.0 then
(
CParent = obj
ChooseParent.text = CParent.name
) else (
MessageBox "This object is scaled. Please make sure it has scale of 100% and try again."
)
) else (
MessageBox "You cannot define a Parent Object\nthat is currently in the Child Object list"
CParent = undefined
)
)
-- ******************************************************************************
-- * Clear List
-- ******************************************************************************
on ClearList pressed do
(
ChildrenArray = #()
CList = #()
Children.items = CList
)
-- ******************************************************************************
-- * Remove Child
-- ******************************************************************************
on RemoveChild pressed do
(
if ChildrenArray.count != 0 do
(
s = Children.selection
CList = Children.items
deleteItem ChildrenArray s
deleteItem CList s
Children.items = CList
)
)
-- ******************************************************************************
-- * Add Child
-- ******************************************************************************
on AddChild pressed do
(
CObjArray = for obj in selection collect obj
ierror = false
serror = false
-- Check for instancing in potential child objects
for i = 1 to CObjarray.count do
(
CName = (KeyName CObjArray[i].name)
for j = 1 to CObjArray.count do
if i != j do
if (KeyName CObjArray[j].name) == CName do
ierror = true
)
if iError == false then
(
for i = 1 to CObjArray.count do
if (avgScale CObjArray[i].scale) != 1.0 do
(
-- MessageBox ("Object \"" + CObjArray[i].name + " is scaled. Please make sure it's scale is 100% and try again.")
-- sError = true
Exit
)
if sError == false then
(
CList = Children.items
for i = 1 to CObjArray.count do
(
obj = CObjArray[i]
if (findItem ChildrenArray obj == 0) do
(
append ChildrenArray obj
append CList obj.name
)
)
Children.items = CList
)
) else (
MessageBox "Instancing was found in your object selection.\n You cannot instance child objects.\nPlease rename your objects without instancing."
)
)
-- ******************************************************************************
-- ******************************************************************************
-- *
-- * Create Relationship
-- *
-- ******************************************************************************
-- ******************************************************************************
on CreateRelationship pressed do
(
if (CParent != undefined) and (ChildrenArray.count != 0) then
(
ParentIndex = 0
ChildIndices = #()
-- Test for the existence of the child and parent in the data structure
for i = 1 to RData.count do
(
-- Test for the existence of the PARENT object in Rdata#()
if RData[i][1] == CParent.name do
(
if debug do format "ParentIndex found at: %\n" i
ParentIndex = i
)
)
for i = 1 to ChildrenArray.count do
(
CChild = ChildrenArray[i]
ChildIndices[i] = 0
for j = 1 to RData.count do
(
-- Test for the existence of the CHILD object in Rdata#()
if RData[j][1] == CChild.name then
(
if debug do format "ChildIndex found at: %\n" j
ChildIndices[i] = j
Exit
)
)
)
if debug do format "ChildIndices:%\n" ChildIndices
-- Process the Parent Object
if ParentIndex != 0 then
(
FinalParentPosition = ParentIndex
PData = RData[ParentIndex]
-- if it's in the list, make sure it's a parent, it could be #unused
RData[ParentIndex][2] = #Parent
-- set the object type as a child if it has a parent object defined
if PData[4] != 0 do PData[2] = #Child
if debug do format "CI:%\n" ChildIndices
for i = 1 to ChildIndices.count do
(
if (ChildIndices[i] == 0) do
append PData[3] (Rdata.count + i)
if (ChildIndices[i] != 0) and (finditem PData[3] ChildIndices[i]) == 0 do
append PData[3] ChildIndices[i]
)
) else (
-- is the parent a child of another parent?
PData = #()
PData[1] = (KeyName CParent.name) -- Name
PData[2] = #Parent -- Type
PData[3] = #() -- children it has
AlreadyThereCount = 0
for i = 1 to ChildIndices.count do
if ChildIndices[i] == 0 then
append PData[3] (RData.count + (i + 1) - AlreadyThereCount)
else
(
append PData[3] ChildIndices[i]
AlreadyThereCount += 1
)
PData[4] = 0 -- it's new position in RData
PData[5] = (avgScale CParent.scale) -- Scale
PData[6] = #Null -- Initial Vector
PData[7] = #Null -- Initial Offset Rotation
PData[8] = ScaleChildren.checked -- Object definition
PData[9] = CParent -- Object definition
-- add PData onto RData
append Rdata PData
FinalParentPosition = RData.count
)
for i = 1 to ChildrenArray.count do
(
CChild = ChildrenArray[i]
-- Process the Child Object
if ChildIndices[i] != 0 and ChildIndices[i] != undefined then
(
if debug do format "Already Have Child...\n"
CData = RData[ChildIndices[i]]
if (CIndex = FindItem RData[CData[4]][3] ChildIndices[i]) != 0 do
DeleteItem RData[CData[4]][3] CIndex
CData[4] = FinalParentPosition
CData[5] = (avgScale CChild.scale) / (avgScale CParent.scale)
CData[6] = (CChild.pos - CParent.pos) * (CParent.rotation) as matrix3
CData[7] = CChild.rotation - CParent.rotation
CData[8] = ScaleChildren.checked
CData[9] = CChild
RData[ChildIndices[i]] = CData
) else (
CData = #()
CData[1] = KeyName CChild.name
CData[2] = #Child
CData[3] = #()
CData[4] = FinalParentPosition
CData[5] = (avgScale CChild.scale) / (avgScale CParent.scale)
CData[6] = (CChild.pos - CParent.pos) * (CParent.rotation) as matrix3
CData[7] = CChild.rotation - CParent.rotation
CData[8] = ScaleChildren.checked
CData[9] = CChild
-- add PData onto RData
append Rdata CData
)
)
-- check for objects that are flagged as #parent and if they have no children, flag them as unused
for i = 1 to RData.count do
if (RData[i][2] == #Parent) and (RData[i][3].count == 0) do
RData[i][2] = #Unused
NameArray = #()
ObjArray = #()
if debug do
for i = 1 to Rdata.count do
format "%:%\n" i Rdata[i]
for i = 1 to RData.count do
if RData[i][2] == #Parent then
BuildNameList i RData NameArray 0 ObjArray
ObjectNames.items = NameArray
if AutoClear.checked do
(
ChildrenArray = #()
CList = #()
Children.items = CList
CParent = undefined
ChooseParent.text = ""
)
SaveNow.text = "SAVE YOUR FILE!!!!"
) else (
messageBox "Objects are undefined."
)
)
-- *************************************************
-- * Refresh Selection
-- *************************************************
on RefreshSelection pressed do
(
for i = 1 to RData.count do
(
if (CObj = FindByName RData[i][1]) != undefined then
RData[i][9] = CObj
else (
RData[i][9] = #NoObject
if debug do format "Parent found in RData, but no object found in the scene for %\n" RData[i][1]
)
)
ParentArray = #()
ParentNames = #()
for i = 1 to RData.count do
if RData[i][2] == #Parent and RData[i][9] != #NoObject do
(
if debug do format "Found Parent at %\n" i
append ParentArray #(RData[i][9], i)
append ParentNames (KeyName RData[i][1])
)
ObjArray = selection as array
oc = ObjArray.count
ProgressStart "Refreshing Objects..."
for i = 1 to oc do
(
if ProgressUpdate ((i / oc as float) * 100) == false then Exit
CObj = ObjArray[i]
if debug do format "CObj: %\n" CObj.name
-- Is it a parent Object?
if (PIndex = findItem ParentNames (KeyName CObj.name)) != 0 do
(
if debug do format "calling recursive function at RData Parent Index %....\n" ParentArray[PIndex][2]
RDataParentIndex = ParentArray[PIndex][2]
if debug do format "RDataParent Index: %\n" RDataParentIndex
-- Do we need to scale the children
if RData[RDataParentIndex][8] == true then
SChildren = true
else
SChildren = false
UpdateSelection RDataParentIndex RData CObj RData[RDataParentIndex][5] SChildren
)
)
ProgressEnd()
)
-- *************************************************
-- * Refresh objects
-- *************************************************
on refreshObjects pressed do
(
for i = 1 to RData.count do
(
if (CObj = FindByName RData[i][1]) != undefined then
RData[i][9] = CObj
else
RData[i][9] = #NoObject
)
for i = 1 to RData.count do
if RData[i][2] == #Parent then
UpdatePositions i RData
)
) -- End Utility