Files
2025-09-29 00:52:08 +02:00

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
)