701 lines
18 KiB
Plaintext
Executable File
701 lines
18 KiB
Plaintext
Executable File
-- Author : Mike Wilson (mike.wilson@rockstarnorth.com)
|
|
|
|
-- cutfileLoader plugin
|
|
filein "pipeline/util/lighteditor_ng.ms"
|
|
|
|
global string g_lastDir
|
|
global string g_lastCutFile
|
|
global string g_lastLightFile
|
|
global g_cutFileLastWrite
|
|
global g_lightFileLastWrite
|
|
global int g_perforce = true
|
|
global g_DateTime = dotNetClass "System.DateTime"
|
|
|
|
fn SetPerforceIntegration p4 = (
|
|
g_perforce = p4
|
|
RsProjectSetPerforceIntegration g_perforce
|
|
)
|
|
|
|
fn CleanUpScene = (
|
|
local objsDeleted = true
|
|
while objsDeleted do
|
|
(
|
|
objsDeleted = false
|
|
for scene_node in rootScene.world.children do
|
|
(
|
|
if scene_node != undefined then
|
|
(
|
|
if (getuserprop scene_node "persistant_geo") == undefined then
|
|
(
|
|
delete scene_node
|
|
objsDeleted = true
|
|
)
|
|
)
|
|
)
|
|
)
|
|
)
|
|
|
|
fn LoadCutXMLFile dir = (
|
|
|
|
gRsPerforce.sync dir silent:true
|
|
|
|
g_lastCutFile = dir
|
|
local cutFileInfo = (dotNetObject "System.IO.FileInfo" g_lastCutFile)
|
|
g_cutFileLastWrite = cutFileInfo.LastWriteTime
|
|
|
|
CleanUpScene()
|
|
Reset()
|
|
if doesFileExist dir then
|
|
(
|
|
if LoadCutFile dir == true then
|
|
(
|
|
-- set the range of the animation time line to the range of the cut file
|
|
animationRange = interval 0 (GetCutFileEndRange() as Integer)
|
|
|
|
offsetNode = getNodeByName "Scene_Offset"
|
|
if (offsetNode != undefined) do
|
|
(
|
|
sceneTranslation = GetSceneOffsetTranslation()
|
|
sceneRotation = GetSceneOffsetRotation()
|
|
euler = eulerAngles sceneRotation.x sceneRotation.y sceneRotation.z
|
|
offsetNode.rotation = eulerToQuat euler
|
|
offsetNode.position = sceneTranslation
|
|
)
|
|
|
|
if RsContentTree.DoesDLCProjectExist dir then
|
|
(
|
|
RsContentTree.SetupProjectAndBranchGlobals dlcProjectName:(RsContentTree.GetDLCProject dir).name
|
|
)
|
|
else
|
|
(
|
|
RsContentTree.SetupProjectAndBranchGlobals()
|
|
)
|
|
|
|
return true
|
|
)
|
|
)
|
|
|
|
return false
|
|
)
|
|
|
|
fn ImportLight dir = (
|
|
|
|
gRsPerforce.sync dir silent:true
|
|
|
|
g_lastLightFile = dir
|
|
local lightFileInfo = (dotNetObject "System.IO.FileInfo" g_lastLightFile)
|
|
g_lightFileLastWrite = lightFileInfo.LastWriteTime
|
|
|
|
outOfDateError = false
|
|
outOfDateString = ""
|
|
--if doesFileExist dir then
|
|
(
|
|
if ImportLightXML dir == true then
|
|
(
|
|
for i=0 to GetLightCount()-1 do
|
|
(
|
|
myLight = getNodeByName (GetLightName i)
|
|
|
|
if myLight == undefined then
|
|
(
|
|
myLight = RageLight lightType:1 lightIntensity:3.0
|
|
if RotationIsRelative i then
|
|
(
|
|
format "Light node '%' has relative rotation\n" myLight.name
|
|
myLight.rotation = quat (GetLightRotationQuat i).x (GetLightRotationQuat i).y (GetLightRotationQuat i).z (GetLightRotationQuat i).w
|
|
)
|
|
else
|
|
(
|
|
format "Light node '%' has absolute rotation\n" myLight.name
|
|
euler = eulerAngles (GetLightRotation i).x (GetLightRotation i).y (GetLightRotation i).z
|
|
myLight.rotation = eulerToQuat euler
|
|
)
|
|
myLight.position = GetLightPosition i
|
|
myLight.name = GetLightName i
|
|
myLight.lightColour = Color ((GetLightColour i).x*255) ((GetLightColour i).y*255) ((GetLightColour i).z*255)
|
|
myLight.lightIntensity = GetLightIntensity i
|
|
myLight.lightAttenEnd = GetLightFallOff i
|
|
myLight.lightFalloff = GetLightConeAngle i
|
|
myLight.lightType = GetLightType i
|
|
myLight.lightHotspot = GetLightInnerConeAngle i
|
|
myLight.lightExpFalloff = GetLightExpFallOff i
|
|
|
|
SetLightAttributes i myLight
|
|
SetLightKeyFrames i myLight
|
|
|
|
if GetLightCameraAnimatedFlag i == false then
|
|
(
|
|
setUserProp myLight "animated" "true"
|
|
)
|
|
|
|
if GetLightAttachedName i != "" then
|
|
(
|
|
myAttached = GetNodeByName (GetLightAttachedName i)
|
|
if myAttached == undefined then
|
|
(
|
|
myAttached = Dummy boxsize:[15,15,15]
|
|
myAttached.name = (GetLightAttachedName i)
|
|
myAttached.rotation = quat (GetLightAttachedRotation i).x (GetLightAttachedRotation i).y (GetLightAttachedRotation i).z (GetLightAttachedRotation i).w
|
|
myAttached.position = GetLightAttachedPosition i
|
|
)
|
|
|
|
setUserProp myLight "attached" (GetLightAttachedName i)
|
|
)
|
|
)
|
|
|
|
-- re-parent the camera / light
|
|
-- this solely relys on the camera names, if these change the mapping will be wrong
|
|
cameraname = GetLightCamera i
|
|
cameraNode = getNodeByName cameraname
|
|
|
|
--HACK: To convert existing asset data, see if there's a node that begins with the name of the light's camera.
|
|
--This is a best-match scenario, which can cause bugs but it's better than lights being removed entirely.
|
|
if cameraNode == undefined then
|
|
(
|
|
format "Unable to find camera named '%' for node '%'\n" cameraname myLight.name
|
|
for child in rootnode.children do
|
|
(
|
|
if ( findString child.name cameraname != 0) then
|
|
(
|
|
cameraname = child.name
|
|
cameranode = getNodeByName cameraName
|
|
exit
|
|
)
|
|
)
|
|
)
|
|
|
|
if cameraNode != undefined then
|
|
(
|
|
myLight.parent = cameraNode
|
|
)
|
|
else
|
|
(
|
|
outOfDateString = outOfDateString + ("Unable to find camera \"" + cameraname + "\" in scene to be associated with light " + (GetLightName i) as string) + ".\n"
|
|
outOfDateError = true
|
|
)
|
|
)
|
|
|
|
if outOfDateError == true then
|
|
(
|
|
messagebox outOfDateString title:"Out of Date"
|
|
)
|
|
|
|
return true
|
|
)
|
|
)
|
|
|
|
return false
|
|
)
|
|
|
|
fn GetAnimatedLightNodes = (
|
|
|
|
animatedLights = #()
|
|
for node in $objects do
|
|
(
|
|
if classof node == Dummy then
|
|
(
|
|
if node.children.count > 0 then
|
|
(
|
|
-- iterate every light which is a child of this camera
|
|
for child in node.children do
|
|
(
|
|
if classof child == RageLight then
|
|
(
|
|
if IsAnimatable child == true then
|
|
(
|
|
append animatedLights child
|
|
)
|
|
)
|
|
)
|
|
)
|
|
)
|
|
)
|
|
|
|
animatedLights
|
|
)
|
|
|
|
fn ValidateLightNames rename:false =
|
|
(
|
|
local lightList = #()
|
|
local invalidNames = #()
|
|
local promptForRename = true
|
|
for node in $objects do
|
|
(
|
|
if classOf node != Dummy then
|
|
(
|
|
if not (appendIfUnique lightList node.name) then
|
|
(
|
|
if rename then
|
|
(
|
|
local firstName = node.name
|
|
node.name = uniqueName node.name
|
|
append lightList node.name
|
|
print "---LIGHT RENAMED---"
|
|
format "% renamed to: %\n" firstName node.name
|
|
)
|
|
else
|
|
(
|
|
if promptForRename then
|
|
(
|
|
local msg = ("Light name " + node.name + " is a duplicate, would you like to auto-rename?")
|
|
local ret = RsQueryBoxMultiBtn msg title:"Erro: Duplicate Light Names" labels:#("Yes to All","Yes","No","No to All") defaultBtn:2 timeout:0
|
|
if ret==1 or ret==2 then
|
|
(
|
|
if ret==1 do
|
|
rename=true
|
|
local firstName = node.name
|
|
node.name = uniqueName node.name
|
|
append lightList node.name
|
|
print "---LIGHT RENAMED---"
|
|
format "% renamed to: %\n" firstName node.name
|
|
)
|
|
else
|
|
(
|
|
if ret==4 do
|
|
promptForRename=false
|
|
appendIfUnique invalidNames node.name
|
|
)
|
|
)
|
|
else
|
|
appendIfUnique invalidNames node.name
|
|
)
|
|
)
|
|
)
|
|
)
|
|
if (not rename) and invalidNames.count != 0 then
|
|
(
|
|
ss = stringStream ""
|
|
format "The following light names are not unique: " to:ss
|
|
for iName in invalidNames do
|
|
(
|
|
format "%" iName to:ss
|
|
if (iName != invalidNames[invalidNames.Count]) do
|
|
format " , " to:ss
|
|
)
|
|
messagebox ss title:"Error: Duplicate Names"
|
|
return false
|
|
)
|
|
else
|
|
return true
|
|
)
|
|
|
|
fn ValidateUniqueLights dir =
|
|
(
|
|
--rename local scene lights, then check concats
|
|
ValidateLightNames rename:true
|
|
|
|
gRsPerforce.sync ( RsConfigGetAssetsDir() + "cuts/!!Cutlists/...") silent:true
|
|
|
|
-- iterate every camera and find the lights attached - camera cut objects are Dummy objects in the scene
|
|
for node in $objects do
|
|
(
|
|
if classof node == Dummy then
|
|
(
|
|
if node.children.count > 0 then
|
|
(
|
|
-- iterate every light which is a child of this camera
|
|
for child in node.children do
|
|
(
|
|
if classof child == RageLight then
|
|
(
|
|
-- Pre-validate light names
|
|
while ( (strMessage = ValidateUniqueLightName (RsMakeSafeSlashes dir) child.name) != undefined ) do
|
|
(
|
|
if firstMessage == undefined do
|
|
firstMessage = strMessage
|
|
child.name = uniqueName child.name
|
|
)
|
|
if firstMessage != undefined do
|
|
(
|
|
print "---LIGHT RENAMED---"
|
|
format "%\nrenamed to: %\n" firstMessage child.name
|
|
)
|
|
)
|
|
)
|
|
)
|
|
)
|
|
)
|
|
)
|
|
|
|
fn ExportLight dir = (
|
|
|
|
if IsCutFileLoaded() == 0 or ValidateLightNames() == false then
|
|
(
|
|
return false
|
|
)
|
|
|
|
CreateLightXML()
|
|
containsAnimatedLights = false
|
|
|
|
animatedLightNodes = GetAnimatedLightNodes()
|
|
|
|
Reset()
|
|
|
|
gRsPerforce.sync ( RsConfigGetAssetsDir() + "cuts/!!Cutlists/...") silent:true
|
|
|
|
-- iterate every camera and find the lights attached - camera cut objects are Dummy objects in the scene
|
|
for node in $objects do
|
|
(
|
|
if classof node == Dummy then
|
|
(
|
|
if node.children.count > 0 then
|
|
(
|
|
-- iterate every light which is a child of this camera
|
|
for child in node.children do
|
|
(
|
|
if classof child == RageLight then
|
|
(
|
|
sliderTime = 0
|
|
|
|
strMessage = undefined
|
|
-- Pre-validate light names
|
|
while ( (strMessage = ValidateUniqueLightName dir child.name) != undefined ) do
|
|
(
|
|
ss = stringStream ""
|
|
format "% \n\nDo you want to automatically rename this light?" strMessage to:ss
|
|
if queryBox ss title:"Rename Light?" then
|
|
(
|
|
child.name = uniqueName child.name
|
|
)
|
|
else
|
|
(
|
|
return false
|
|
)
|
|
)
|
|
|
|
euler = (quatToEuler child.rotation)
|
|
if AddLightToLightXML child child.position (point3 euler.x euler.y euler.z) child.transform child.lightType child.lightColour child.lightIntensity child.lightAttenEnd child.lightFalloff child.lightHotspot child.lightExpFalloff == false then
|
|
(
|
|
continue
|
|
)
|
|
)
|
|
)
|
|
)
|
|
)
|
|
)
|
|
|
|
for i = 1 to animatedLightNodes.Count do
|
|
(
|
|
containsAnimatedLights = true
|
|
CreateAnim (animationRange.start/30) ((animationRange.end + 1)/30) (animationRange.end + 1) animatedLightNodes[i].name dir animatedLightNodes[i].lightType
|
|
)
|
|
|
|
if containsAnimatedLights == True then
|
|
(
|
|
for i=0 to animationRange.end do
|
|
(
|
|
for j = 1 to animatedLightNodes.Count do
|
|
(
|
|
child = animatedLightNodes[j]
|
|
AddFrameToAnim (j-1) child i
|
|
)
|
|
)
|
|
)
|
|
|
|
for i = 1 to animatedLightNodes.Count do
|
|
(
|
|
child = animatedLightNodes[i]
|
|
if g_perforce == true then
|
|
(
|
|
sceneDir = dir
|
|
if sceneDir[sceneDir.count] == "/" or sceneDir[sceneDir.count] == "\\" then
|
|
(
|
|
sceneDir = substring sceneDir 1 (sceneDir.count-1)
|
|
)
|
|
|
|
p4Dir = sceneDir + "\\" + child.name + ".anim"
|
|
gRsPerforce.sync p4Dir silent:true
|
|
if gRsPerforce.edit p4Dir silent:true == false then
|
|
(
|
|
gRsPerforce.add #( "-t", "binary+m", (p4Dir) ) silent:true
|
|
)
|
|
|
|
p4Dir = sceneDir + "\\" + child.name + ".clip"
|
|
gRsPerforce.sync p4Dir silent:true
|
|
if gRsPerforce.edit p4Dir silent:true == false then
|
|
(
|
|
gRsPerforce.add #( "-t", "binary+m", (p4Dir) ) silent:true
|
|
)
|
|
)
|
|
|
|
SaveAnim(i-1)
|
|
)
|
|
|
|
sceneDir = dir
|
|
if sceneDir[sceneDir.count] == "/" or sceneDir[sceneDir.count] == "\\" then
|
|
(
|
|
sceneDir = substring sceneDir 1 (sceneDir.count-1)
|
|
)
|
|
|
|
assetFileName = sceneDir + "/data.lightxml"
|
|
cutFileName = sceneDir + "/data.cutxml"
|
|
|
|
if g_perforce == true then
|
|
(
|
|
gRsPerforce.sync assetFileName silent:true
|
|
if gRsPerforce.edit assetFileName silent:true == false then
|
|
(
|
|
gRsPerforce.add assetFileName silent:true
|
|
)
|
|
)
|
|
|
|
result = SaveLightXML assetFileName false
|
|
|
|
g_lastLightFile = assetFileName
|
|
lightFileInfo = dotNetObject "System.IO.FileInfo" g_lastLightFile
|
|
g_lightFileLastWrite = lightFileInfo.LastWriteTime
|
|
|
|
--Although we wont be updating the cutxml, if they have exported to a different folder,
|
|
--We need to keep track of the new cutxml
|
|
g_lastCutFile = cutFileName
|
|
cutFileInfo = dotNetObject "System.IO.FileInfo" g_lastCutFile
|
|
g_cutFileLastWrite = cutFileInfo.LastWriteTime
|
|
|
|
return result
|
|
)
|
|
|
|
fn BuildCutscene dir preview = (
|
|
|
|
if g_perforce == true then
|
|
(
|
|
syncDir = RsConfigGetAssetsDir() + "export/anim/cutscene/..."
|
|
gRsPerforce.sync syncDir silent:false
|
|
)
|
|
|
|
if BuildZip dir true preview == false then
|
|
(
|
|
false
|
|
)
|
|
|
|
return true
|
|
)
|
|
|
|
--Takes in dummy node with name 'AutoClip...' and returns a new unique light name
|
|
--Function a bit dirty due to naming conventions of lights
|
|
fn GetLightNameFromParent light = (
|
|
if light == undefined or light.parent == undefined do return undefined
|
|
local cam = light.parent
|
|
local index = findString cam.Name "AutoClip"
|
|
if index == undefined do return undefined
|
|
local newName = replace cam.name index 8 "AC"
|
|
local camNames = filterString newName "_"
|
|
local lightNames = filterString light.Name "_"
|
|
local notFound = true
|
|
for camName in camNames while notFound do
|
|
(
|
|
if matchPattern camName pattern:"AC*" do
|
|
(
|
|
for i = 1 to lightNames.count while notFound do
|
|
(
|
|
if matchPattern lightNames[i] pattern:"AC*" do
|
|
(
|
|
notFound = false
|
|
lightNames[i] = camName
|
|
)
|
|
)
|
|
)
|
|
)
|
|
newName = RsArrayJoin lightNames token:"_"
|
|
uniqueName newName numDigits:3
|
|
)
|
|
|
|
fn CopyLightProps objsFrom objsTo = (
|
|
if objsFrom.count != objsTo.count do
|
|
return false
|
|
|
|
for i=1 to objsFrom.count do
|
|
(
|
|
local fromLight = objsFrom[i]
|
|
local toLight = objsTo[i]
|
|
|
|
copyattrs fromLight
|
|
pasteattrs toLight
|
|
|
|
if GetAttrClass fromLight != "Gta LightPhoto" do return false
|
|
if GetAttrClass toLight != "Gta LightPhoto" do return false
|
|
local fromLightType = lightEditorInstanceNG.GetLightType fromLight
|
|
local toLightType = lightEditorInstanceNG.GetLightType toLight
|
|
|
|
--get properties of the source light
|
|
local excluded = #(#lightType, #Omni_Light, #Free_Spot, #Target_Spot, #Free_Directional_Light, #Target_Directional_Light)
|
|
|
|
--if its capsule to capsule then copy the capsule width, otherwise. skip it!
|
|
if toLightType == #Capsule and fromLightType != #Capsule then
|
|
(
|
|
join excluded #(#lightWidthAttenEnd, #lightAttenEnd, #lightExpFalloff)
|
|
)
|
|
|
|
for prop in (getPropNames fromLight) where findItem excluded prop == 0 do
|
|
(
|
|
local val = getProperty fromLight prop
|
|
lightEditorInstanceNG.CopyProperty fromLight toLight prop
|
|
)
|
|
|
|
--copy the wirecolor
|
|
setProperty toLight #wireColor (getProperty fromLight #wireColor)
|
|
)
|
|
return true
|
|
)
|
|
|
|
|
|
fn DuplicateLights lights targets: rename:false copyStyle:#copy = (
|
|
|
|
if lights == undefined or copyStyle == undefined do
|
|
(
|
|
return false
|
|
)
|
|
|
|
if classOf lights != Array do lights = #(lights)
|
|
|
|
if targets == unsupplied or targets == undefined or targets.count == 0 then
|
|
(
|
|
if (maxOps.cloneNodes lights cloneType:copyStyle actualNodeList:&onl newNodes:&nnl) then #nodialog
|
|
(
|
|
--Copy properties across using light editor
|
|
CopyLightProps onl nnl
|
|
|
|
if rename then
|
|
(
|
|
for i = 1 to nnl.count do
|
|
(
|
|
newName = GetLightNameFromParent nnl[i]
|
|
if newName != undefined then nnl[i].name = newName
|
|
)
|
|
)
|
|
)
|
|
)
|
|
else
|
|
(
|
|
for target in targets do
|
|
(
|
|
--Clone the selected objects
|
|
if (maxOps.cloneNodes lights cloneType:copyStyle actualNodeList:&onl newNodes:&nnl) then #nodialog
|
|
(
|
|
--Copy properties across using light editor
|
|
CopyLightProps onl nnl
|
|
|
|
for i = 1 to nnl.count do
|
|
(
|
|
nnl.parent = target
|
|
if rename then
|
|
(
|
|
newName = GetLightNameFromParent nnl[i]
|
|
if newName != undefined then nnl[i].name = newName
|
|
)
|
|
)
|
|
)
|
|
)
|
|
)
|
|
|
|
--Max adds a redundant userProp onto any copied objects, doesn't even ensure a new line, so remove it
|
|
for scene_obj in objects do
|
|
(
|
|
ori_prop= getUserPropBuffer scene_obj
|
|
bad_prop="LastPose = undefined"
|
|
if matchPattern ori_prop pattern:"*LastPose = undefined*"==true do
|
|
(
|
|
bad_start=findString ori_prop bad_prop
|
|
new_prop=substring ori_prop 1 (bad_start-1)
|
|
setUserPropBuffer scene_obj new_prop
|
|
)
|
|
)
|
|
)
|
|
|
|
fn CreateExportBuildScenes scenes numberOfLights =
|
|
(
|
|
for scene in scenes do
|
|
(
|
|
resetMaxFile #noPrompt
|
|
|
|
msg = "\n*" + scene
|
|
print msg
|
|
|
|
datastream = scene + "/data_stream.cutxml"
|
|
if LoadCutXMLFile datastream == true then
|
|
(
|
|
for node in $objects do
|
|
(
|
|
if classof node == Dummy then
|
|
(
|
|
if node.name == "OnAllTime" or node.name == "Scene_Offset" then
|
|
(
|
|
continue
|
|
)
|
|
|
|
for i = 1 to numberOfLights do
|
|
(
|
|
r = RageLight()
|
|
r.lightType = 2
|
|
r.parent = node
|
|
|
|
-- set attributes to be default
|
|
|
|
castDynamicObjectShadowIndex = getattrindex "Gta LightPhoto" "Cast Dynamic Object Shadow"
|
|
setattr r castDynamicObjectShadowIndex true
|
|
|
|
softLightIndex = getattrindex "Gta LightPhoto" "Soft Light"
|
|
setattr r softLightIndex true
|
|
|
|
dayIndex = getattrindex "Gta LightPhoto" "Day"
|
|
setattr r dayIndex true
|
|
|
|
nightIndex = getattrindex "Gta LightPhoto" "Night"
|
|
setattr r nightIndex true
|
|
|
|
coronaSizeIndex = getattrindex "Gta LightPhoto" "Corona size"
|
|
setattr r coronaSizeIndex 0
|
|
|
|
coronaHDRMultiplier = getattrindex "Gta LightPhoto" "Corona HDR multiplier"
|
|
setattr r coronaHDRMultiplier 0
|
|
)
|
|
)
|
|
)
|
|
|
|
if ExportLight scene == true then
|
|
(
|
|
BuildCutscene scene false
|
|
)
|
|
)
|
|
)
|
|
)
|
|
|
|
fn ExportCutsceneLightingScenes scenes =
|
|
(
|
|
print "--START--"
|
|
|
|
for scene in scenes do
|
|
(
|
|
resetMaxFile #noPrompt
|
|
|
|
msg = "\n*" + scene
|
|
print msg
|
|
|
|
datastream = scene + "data.cutxml"
|
|
if LoadCutXMLFile datastream == true then
|
|
(
|
|
datalight = scene + "data.lightxml"
|
|
|
|
if ImportLight datalight == true then
|
|
(
|
|
ExportLight scene
|
|
)
|
|
)
|
|
)
|
|
|
|
print "\n--END--"
|
|
)
|
|
|
|
fn GetDirFromFilename fileName = (
|
|
|
|
newFileName = RsMakeSafeSlashes fileName
|
|
dirTokens = filterString newFileName "/"
|
|
newFileName = ""
|
|
|
|
for i = 1 to dirTokens.count-1 do
|
|
(
|
|
newFileName += (dirTokens[i] + "/")
|
|
)
|
|
|
|
newFileName
|
|
)
|