-- -- File:: drawablelod.ms -- Description:: Drawable LOD Hierarchy Utility Functions -- -- Author:: David Muir -- Date:: 24 March 2009 -- ----------------------------------------------------------------------------- -- Uses ----------------------------------------------------------------------------- filein "pipeline/util/drawablelod_private.ms" filein "pipeline/util/userprops.ms" ----------------------------------------------------------------------------- -- Globals ----------------------------------------------------------------------------- global LinkType_LOD = 0 global LinkType_DRAWLOD = 1 global LinkType_RENDERSIM = 2 ----------------------------------------------------------------------------- -- Functions ----------------------------------------------------------------------------- -- -- name: RsLodDrawable_SetHigherDetailModel -- desc: Set the higher detail mesh (model_hd) for model. -- fn RsLodDrawable_SetHigherDetailModel model model_hd = ( if ( not RsSceneLink.HasContainer linkType_DRAWLOD model_hd ) then RsSceneLink.AddContainer linkType_DRAWLOD model_hd RsSceneLink.SetParent linkType_DRAWLOD model_hd model ) -- -- name: RsLodDrawable_GetHigherDetailModel -- desc: Get the higher detail mesh for model. -- fn RsLodDrawable_GetHigherDetailModel model = ( local children = #() RsSceneLink.GetChildren linkType_DRAWLOD model &children -- print ("children:"+children as string) if ( children.count > 0 and not isDeleted children[1]) then ( children[1] ) else undefined ) -- -- name: RsLodDrawable_HasHigherDetailModel -- desc: Return whether model has a higher detail mesh assigned. -- fn RsLodDrawable_HasHigherDetailModel model = ( local hdmodel = RsLodDrawable_GetHigherDetailModel model return ( undefined != hdmodel and not isDeleted hdmodel ) ) -- -- name: RsLodDrawable_SetLowerDetailModel -- desc: Set the lower detail mesh (model_ld) for model. -- fn RsLodDrawable_SetLowerDetailModel model model_ld = ( if ( not RsSceneLink.HasContainer linkType_DRAWLOD model ) then RsSceneLink.AddContainer linkType_DRAWLOD model RsSceneLink.SetParent linkType_DRAWLOD model model_ld ) -- -- name: RsLodDrawable_GetLowerDetailModel -- desc: Get the lower detail mesh for model. -- fn RsLodDrawable_GetLowerDetailModel model = ( local ldmodel = RsSceneLink.GetParent linkType_DRAWLOD model if undefined!=ldmodel and not isDeleted ldmodel then return ldmodel return undefined ) -- -- name: RsLodDrawable_HasLowerDetailModel -- desc: Return whether the model has a lower detail mesh assigned. -- fn RsLodDrawable_HasLowerDetailModel model = ( local ldmodel = RsSceneLink.GetParent linkType_DRAWLOD model return (undefined != ldmodel and not isDeleted ldmodel) ) --------------------------------------------------------------------------------------------- -- renderable child node accessors ---- -- -- name: RsLodDrawable_SetHigherDetailModel -- desc: Set the higher detail mesh (model_hd) for model. -- fn RsLodDrawable_SetRenderChildModel model rendermodel = ( if ( not RsSceneLink.HasContainer LinkType_RENDERSIM rendermodel ) then RsSceneLink.AddContainer LinkType_RENDERSIM rendermodel if ( not RsSceneLink.HasContainer LinkType_RENDERSIM rendermodel ) then ( messagebox "Failed adding drawable lod container to node." ) RsSceneLink.SetParent LinkType_RENDERSIM rendermodel model ) fn RsLodDrawable_IsRenderModel model = ( return (RsSceneLink.HasContainer LinkType_RENDERSIM model) and (undefined!=RsSceneLink.GetParent LinkType_RENDERSIM model) ) -- -- name: RsLodDrawable_GetHigherDetailModel -- desc: Get the higher detail mesh for model. -- fn RsLodDrawable_GetRenderModel model = ( local children = #() RsSceneLink.GetChildren LinkType_RENDERSIM model &children if ( children.count > 0 and not isDeleted children[1]) then return ( children[1] ) else return ( undefined ) ) -- -- name: RsLodDrawable_GetHigherDetailModel -- desc: Get the higher detail mesh for model. -- fn RsLodDrawable_GetSimulationModel model = ( if ( not RsSceneLink.HasContainer LinkType_RENDERSIM model ) then return undefined else ( local simModel = RsSceneLink.GetParent LinkType_RENDERSIM model if undefined!=simModel and not isDeleted simModel then return simmodel else return undefined ) ) -- -- name: RsLodDrawable_HasHigherDetailModel -- desc: Return whether model has a higher detail mesh assigned. -- fn RsLodDrawable_HasSimulationModel model = ( return (undefined != (RsLodDrawable_GetSimulationModel model)) ) -- -- name: RsLodDrawable_GetSimulationModel -- desc: Get the parent (RENDER) mesh for model. -- fn RsLodDrawable_HasRenderModel model = ( return (undefined != (RsLodDrawable_GetRenderModel model)) ) fn RsLodDrawable_HasProxyModel model = ( return (undefined != (RsSceneLink.GetParent linkType_ShadowMesh model )) ) -- -- name: RsLodDrawable_GetShadowMeshCounterPart -- desc: Get the model that the shadow mesh is linked to -- fn RsLodDrawable_GetShadowMeshCounterPart model = ( local children = #() if undefined!=linkType_ShadowMesh then RsSceneLink.GetChildren linkType_ShadowMesh model &children else print "linkType_ShadowMesh is undefined" if ( children.count > 0 and not isDeleted children[1]) then return ( children[1] ) else return ( undefined ) ) fn RsLodDrawable_IsSimulationModel model = return RsLodDrawable_HasRenderModel model fn RsLodDrawable_GetLODGroupHead obj = ( local groupHead = obj if (groupHead != undefined) do ( local localparent local headNotFound = True while headNotFound do ( localparent = (RsLodDrawable_GetHigherDetailModel groupHead) if undefined==localparent then localparent = RsLodDrawable_GetShadowMeshCounterPart groupHead if (localparent == undefined) then (headNotFound = False) else (groupHead = localparent) ) ) groupHead ) fn RsLodDrawable_SetClothUserProps lodroot hasCloth clothTypeGroup = ( -- This is a render chain if we have a simulation chain attached OR ARE WITHOUT LINKS AT ALL local groupHead = (RsLodDrawable_GetLODGroupHead lodroot) local groupHeadIsCloth = RsCloth.IsCloth groupHead local isRenderChain = RsLodDrawable_HasSimulationModel groupHead local isSimChain = groupHeadIsCloth and RsLodDrawable_HasRenderModel groupHead -- mein cloth chain is either the simulation chain, or render chain if no simulation chain attached local isMainClothChain = groupHeadIsCloth and not RsLodDrawable_HasSimulationModel groupHead and not isSimChain local isFragmentRoot = (undefined==lodroot.parent) -- print (lodroot.name+" with parent "+groupHead.name) -- print ("isMainClothChain:"+isMainClothChain as string+"\nisRenderChain:"+isRenderChain as string+"\nisSimChain:"+isSimChain as string) local exclusiveTypeGroups = #() if isMainClothChain or isSimChain then ( append exclusiveTypeGroups "ClothPiece" if isMainClothChain then ( if isFragmentRoot then append exclusiveTypeGroups "fragments" append exclusiveTypeGroups clothTypeGroup ) setUserProp lodroot "specialFlags" clothTypeGroup setuserprop lodroot "optimseMeshForCloth" true setUserProp lodroot "optimize" false ) else if isRenderchain then ( if isFragmentRoot then append exclusiveTypeGroups "fragments" append exclusiveTypeGroups clothTypeGroup setUserProp lodroot "specialFlags" clothTypeGroup if RsVehicle!=true then -- can be undefined, so no boolean check ( setuserprop lodroot "optimseMeshForCloth" true ) setUserProp lodroot "optimize" false ) else ( exclusiveTypeGroups = #("fragments", "lodgroup") RsUserProp_Clear lodroot "optimseMeshForCloth" setUserProp lodroot "specialFlags" "lodgroup" ) local groupString = RsStringArray exclusiveTypeGroups token:"|" print (lodroot.name+":exclusiveTypeGroups:"+groupString ) setUserProp lodroot "exclusiveTypeGroups" groupString ) fn RsLodDrawable_HasAnimatedParent obj = ( local isAnimated = false if obj.parent != undefined and getattrclass obj.parent == "Gta Object" then ( local idxHasAnim = getattrindex "Gta Object" "Has Anim" isAnimated = (getAttr obj.parent idxHasAnim) ) isAnimated ) -- -- name: RsLodDrawable_SetUserProps -- desc: Setup max user properties for the complete Drawable LOD hierarchy -- starting with the lodroot node specified. -- return: Array of objects that have had lod user property set (typically -- used for selection to then select nodes for Rex export). -- -- This is recursive, when called from exporter enduser code DO NOT specify -- the depth parameter unless you know what you are doing. -- -- cloth parameters are for hierarchies that "have" cloth and object that "are" cloth. -- clothTypeGroup is used to give hint on whether function is used to assemble meshes (and hence not setting some user attributes) fn RsLodDrawable_SetUserProps lodroot &lodGroupCount \ depth:0 lastLodRange:0 lastLodDist:0 hasCloth:false isCloth:false clothTypeGroup:"lodgroup" doOptimize:true ignoreLeafReset:false = ( local objs = #() --format "RsLodDrawable_SetUserProps % %\n" lodroot depth local idxIsCloth = getattrindex "Gta Object" "Is Cloth" local lodDistAttrIndex = ( GetAttrIndex "Gta Object" "LOD distance" ) local lod_dist = ( GetAttr lodroot lodDistAttrIndex ) -- Set "lodthreshold" user property to LOD distance if we aren't -- the lower detail model (fade distance will be used for that). -- overridden throughout simulation chain descending if not isCloth then isCloth = getAttr lodroot idxIsCloth if hasCloth then ( lastLodDist = (lastLodDist + (lastLodRange/5)) setuserprop lodroot "lodthreshold" lastLodDist setuserprop lodroot "lodoutthreshold" lod_dist gRsUlog.LogMessage (lodroot.name+" lod in:"+lastLodDist as string+", out:"+lod_dist as string) context:lodroot RsUserProp_Clear lodroot "optimize" if undefined!=clothTypeGroup then RsLodDrawable_SetClothUserProps lodroot hasCloth clothTypeGroup ) else ( if ( RsLodDrawable_HasLowerDetailModel lodroot ) then ( setuserprop lodroot "lodthreshold" lastLodDist setuserprop lodroot "lodoutthreshold" lod_dist ) else ( -- Ensure we don't have a "lodthreshold" property set. RsUserProp_Clear lodroot "lodthreshold" RsUserProp_Clear lodroot "lodoutthreshold" ) RsUserProp_Clear lodroot "exclusiveTypeGroups" RsUserProp_Clear lodroot "specialFlags" ) if lastLodDist >= lod_dist then ( gRsUlog.LogError ("Drawable LOD setup failed as LOD level object "+lodroot as string+" must have higher LOD distance set than its higher part \n("+lastLodDist as string+" >= "+lod_dist as string+").") context:lodroot ) -- setting the lodgroup if undefined!=clothTypeGroup then ( setuserprop lodroot "lodgroup" lodGroupCount gRsUlog.LogDebug ("Setting lodgroup of "+lodroot.name+" to "+lodGroupCount as string) ) -- Set "lod" user property to our current depth (unless 0). setuserprop lodroot "lod" depth gRsUlog.LogDebug ("Set \"lod\" of " +lodroot.name + " to " + depth as string) local anyChildren = #() RsSceneLink.GetChildren -1 lodroot &anyChildren local childCount = anyChildren.count -- We bail out if the root object specified is not within -- a drawable LOD hierarchy or if the object is animated. if(not ( RsLodDrawable_HasLowerDetailModel lodroot ) and not ( RsLodDrawable_HasSimulationModel lodroot ) and ( childCount==0 ) and not ( RsLodDrawable_HasProxyModel lodroot) and not ( RsLodDrawable_HasAnimatedParent lodroot ) ) then ( -- Force LOD to 0, in case it was previously in a drawable -- LOD hierarchy and no longer is. if not ignoreLeafReset then ( RsUserProp_Clear lodroot "lod" RsUserProp_Clear lodroot "lodgroup" ) return ( #() ) ) appendIfUnique objs lodroot local parobj = ( RsSceneLink.GetParent linkType_DRAWLOD lodroot ) if ( undefined != parobj ) then ( if (RsLodDrawable_HasSimulationModel lodroot) then ( gRsUlog.LogError (lodroot.name + " has a LOD link is currently not supported. Please revise!") context:lodroot ) else ( subobjs = RsLodDrawable_SetUserProps parobj &lodGroupCount depth:(depth+1) lastLodRange:(lod_dist-lastLodDist) lastLodDist:lod_dist hasCloth:hasCloth isCloth:isCloth doOptimize:doOptimize clothTypeGroup:clothTypeGroup join objs subobjs ) ) local channelsToCheck = #(linkType_ShadowMesh) for ch in channelsToCheck do ( local parobj = ( RsSceneLink.GetParent ch lodroot ) if ( undefined != parobj ) then ( subobjs = RsLodDrawable_SetUserProps parobj &lodGroupCount depth:(depth) lastLodRange:0 lastLodDist:0 hasCloth:hasCloth doOptimize:false clothTypeGroup:clothTypeGroup join objs subobjs ) ) local renderobj = ( RsLodDrawable_GetRenderModel lodroot ) -- print ("renderobj:"+renderobj as string) if ( undefined != renderobj ) then ( -- increment to add renderable chain to different group lodGroupCount = lodGroupCount+1 -- set optimize to false!! subobjs = RsLodDrawable_SetUserProps renderobj &lodGroupCount depth:(depth) lastLodRange:0 lastLodDist:0 hasCloth:hasCloth doOptimize:false clothTypeGroup:clothTypeGroup join objs subobjs ) local idxIsFragment = getattrindex "Gta Object" "Is Fragment" local idxIsDynamic = getattrindex "Gta Object" "Is Dynamic" if getattr lodroot idxIsCloth then ( setattr lodroot idxIsDynamic true setattr lodroot idxIsFragment true ) objs = MakeUniqueArray objs return objs ) fn RsLodDrawable_GetAllModels lodroot = ( local objs = #(lodroot) local parobj = ( RsSceneLink.GetParent linkType_DRAWLOD lodroot ) if ( undefined != parobj ) then ( subobjs = RsLodDrawable_GetAllModels parobj join objs subobjs ) local channelsToCheck = #(linkType_ShadowMesh) for ch in channelsToCheck do ( local parobj = ( RsSceneLink.GetParent ch lodroot ) if ( undefined != parobj ) then ( subobjs = RsLodDrawable_GetAllModels parobj join objs subobjs ) ) local renderobj = ( RsLodDrawable_GetRenderModel lodroot ) -- print ("renderobj:"+renderobj as string) if ( undefined != renderobj ) then ( subobjs = RsLodDrawable_GetAllModels renderobj join objs subobjs ) objs = MakeUniqueArray objs return objs ) ------------------------------------------------------------------------------------------------- -- util functions ------------------------------------------------------------------------------------------------- fn setupSliderAndHandler rc index caption target = ( local lodidx = getAttrindex "Gta Object" "LOD distance" if "Gta Object"!=(getattrclass target) then return false rc.addControl #spinner ("control_"+index as string) caption paramStr:(" range:[0,10000,"+(getattr target lodidx) as string+"]") rc.addHandler ("control_"+index as string) #changed paramStr:"val " codeStr:("if @Gta Object@==(getattrclass $"+target.name+") then setattr $"+target.name+" "+lodidx as string+" val") filter:true ) fn RsLodDrawable_CreateLODSetupDialog = ( local parentOfChain = RsLodDrawable_GetLODGroupHead selection[1] if undefined==parentOfChain then ( messagebox "select at least one object" return false ) local renderGrouplink = RsLodDrawable_GetSimulationModel parentOfChain if undefined!=renderGrouplink then parentOfChain = renderGrouplink local parentOfRenderChain = undefined local localChainObjs = #() -- find parent RsLodDrawable_GetLODGroupHead parentOfChain -- find render chain local bottomOfChain = parentOfChain while undefined!=bottomOfChain do ( renderChild = (RsLodDrawable_GetSimulationModel bottomOfChain) if undefined==renderChild then renderChild = (RsLodDrawable_GetRenderModel bottomOfChain) if undefined!=renderChild then ( parentOfRenderChain = renderChild exit ) bottomOfChain = (RsLodDrawable_GetLowerDetailModel bottomOfChain) ) --find parent of render chain RsLodDrawable_GetLODGroupHead parentOfRenderChain local rc = RolloutCreator "RsLodHierSetup" "Setup LOD hierarchy" rc.begin() -- find render chain bottomOfChain = parentOfChain local controlindex = 0 --rc.addtext "group @current group@ (" filter:true rc.addControl #label "groupLabel1" "current group:" while undefined!=bottomOfChain do ( setupSliderAndHandler rc controlindex (bottomOfChain.name+" distance") bottomOfChain bottomOfChain = (RsLodDrawable_GetLowerDetailModel bottomOfChain) controlindex = controlindex+1 ) -- rc.addtext ")" if undefined!=parentOfRenderChain then ( -- rc.addtext "group @attached group@ (" filter:true rc.addControl #label "groupLabel2" "attached group:" local bottomOfRenderChain = parentOfRenderChain -- local controlindex = 0 while undefined!=bottomOfRenderChain do ( setupSliderAndHandler rc controlindex (bottomOfRenderChain.name+" distance") bottomOfRenderChain bottomOfRenderChain = (RsLodDrawable_GetLowerDetailModel bottomOfRenderChain) controlindex = controlindex+1 ) -- rc.addtext ")" ) CreateDialog (rc.end()) 300 300 modal:true ) -- drawablelod.ms