2440 lines
90 KiB
Plaintext
Executable File
2440 lines
90 KiB
Plaintext
Executable File
try( ClearAllProgressWindows() ) catch()
|
|
try( ProceduralPainter.ToolWindow.Close() ) catch()
|
|
|
|
FileIn ( RsConfigGetWildWestDir() + "script/3dsMax/_config_files/Wildwest_header.ms" )
|
|
|
|
--FileIn the types for the procedural painter and editor
|
|
FileIn "ProceduralBase.ms"
|
|
FileIn "ProceduralPainter_MapImage.ms"
|
|
FileIn "ProcPainter_Live.ms"
|
|
|
|
struct ExportedLocTri
|
|
(
|
|
Center,
|
|
Area,
|
|
VertList = #(),
|
|
GroundTintList = #(),
|
|
GroundTint,
|
|
ScaleXYZLevel,
|
|
ScaleZLevel,
|
|
DensityLevel,
|
|
ProceduralTagIndex
|
|
)
|
|
|
|
|
|
struct ProceduralPainter
|
|
(
|
|
Include @"X:\gta5\tools_ng\wildwest\script\3dsMax\General_tools\Collision\ProceduralPainter_LiveEditing.ms"
|
|
|
|
--Contains the core logic of the painter tool
|
|
Painter,
|
|
|
|
--The tool window
|
|
ToolWindow,
|
|
|
|
--The working object we are operating on and the working layer
|
|
WorkingObject,
|
|
WorkingObjectFaceCount,
|
|
WorkingLayer,
|
|
|
|
--The source objects that we are working on
|
|
SourceObjectList = #(),
|
|
|
|
--Our blank procedural level
|
|
BlankProceduralLevel,
|
|
|
|
--Channel we store the our procedural data.
|
|
DataChannel = 31,
|
|
|
|
--Map images we source data from
|
|
GroundTintMapImage = MapImage ImageFilePath:( RsMakeBackSlashes( gRsConfig.Project.DefaultBranch.Assets + "/maps/procPaint/ProceduralTintMap.png" ) ),
|
|
ProceduralMapImage = MapImage ImageFilePath:( RsMakeBackSlashes( RsConfigGetAssetsDir() + "/maps/procPaint/ProceduralSetMap.png" ) ),
|
|
|
|
--A list of visual meshes that dont result in a proc_mesh in this session
|
|
CreatesEmptyProcMesh = #(),
|
|
|
|
/*------------------------------------------------------------------------------
|
|
Starts an edit session setting up the active object that we are working on.
|
|
*/------------------------------------------------------------------------------
|
|
fn StartEditing =
|
|
(
|
|
--Check our selection is valid.
|
|
if not( this.CheckNodesAreValid Selection ) then
|
|
(
|
|
return False
|
|
)
|
|
|
|
with undo off
|
|
(
|
|
SuspendEditing()
|
|
|
|
--Set our source object selection
|
|
this.SourceObjectList = Selection as Array
|
|
|
|
--Collect any data that already exists on the source objects
|
|
this.CollectData()
|
|
|
|
--Setup our working object
|
|
this.CreateWorkingObject()
|
|
|
|
--Push an update to all our materials
|
|
this.UpdateAllRenderSettings()
|
|
this.UpdateAllDisplaySettings()
|
|
|
|
ResumeEditing()
|
|
)
|
|
|
|
--Select our working object and engage a lock on it
|
|
Select this.WorkingObject
|
|
|
|
--Transform lock the object
|
|
SetTransformLockFlags this.WorkingObject #All
|
|
|
|
--Get count of faces
|
|
this.WorkingObjectFaceCount = PolyOp_GetNumFaces this.WorkingObject
|
|
|
|
--Engage a selection/editing lock on our working object
|
|
this.EngageLock()
|
|
|
|
return True
|
|
),
|
|
|
|
/*------------------------------------------------------------------------------
|
|
Concludes this editing session
|
|
*/------------------------------------------------------------------------------
|
|
fn StopEditing =
|
|
(
|
|
--Check we are currently editing first. If we aren't then then we don't need to stop anything.
|
|
--This occurs if the tool is opened and then closed again straight after.
|
|
if( this.Painter.CurrentlyEditing ) then
|
|
(
|
|
--Check if we have unsaved data before stopping.
|
|
if( this.Painter.NodeCollection.UnsavedDataChanges ) then
|
|
(
|
|
if not( QueryBox "There is some unsaved data on the current object. If we continue all unsaved changes will be lost. Would you like to continue?" ) then
|
|
(
|
|
return False
|
|
)
|
|
)
|
|
|
|
--Mark that we are no longer currently editing
|
|
this.Painter.CurrentlyEditing = false
|
|
|
|
--Atempt to clean up the working object
|
|
this.DeleteWorkingObject()
|
|
)
|
|
|
|
--Unhide all decal/cutout/alpha faces on the source objects
|
|
for SourceObject in this.SourceObjectList do
|
|
(
|
|
if( IsValidNode SourceObject ) then ( PolyOp.UnHideAllFaces SourceObject )
|
|
)
|
|
|
|
--Dispose map images
|
|
this.GroundTintMapImage.Dispose()
|
|
this.ProceduralMapImage.Dispose()
|
|
|
|
--Clear the collection
|
|
this.Painter.NodeCollection.Clear()
|
|
|
|
--Clear the applied count
|
|
this.Painter.ResetAppliedCounts()
|
|
|
|
--Stop sync the camera
|
|
this.Painter.CameraSyncState = off
|
|
|
|
--Disengage any locks we may have
|
|
this.DisengageLock()
|
|
),
|
|
|
|
/*------------------------------------------------------------------------------
|
|
Callback functions and variables.
|
|
*/------------------------------------------------------------------------------
|
|
LockCallback,
|
|
fn LockCallbackFn =
|
|
(
|
|
--Set to modifier panel
|
|
SetCommandPanelTaskMode #Modify
|
|
|
|
--Check the node is still valid before forcing it
|
|
if not ( IsValidNode this.WorkingObject ) then
|
|
(
|
|
--If it isn't then it's likely been deleted or the user has opened a new scene.
|
|
--Mark that we are no longer editing and call StopEditing.
|
|
|
|
MessageBox "Editing will be stopped and changes will be lost. This is because the tool has detected that the working object is no longer in a valid and editable state. It is likely becuase it has been deleted and/or a fresh scene has been opened."
|
|
this.Painter.CurrentlyEditing = false
|
|
this.StopEditing()
|
|
this.DeleteWorkingObject()
|
|
|
|
return()
|
|
)
|
|
|
|
--Check that modifiers haven't been added
|
|
if( this.WorkingObject.Modifiers.Count > 0 ) then
|
|
(
|
|
DeleteModifier this.WorkingObject this.WorkingObject.Modifiers[1]
|
|
)
|
|
|
|
--Check if the user has converted the object into something strange
|
|
if( ClassOf this.WorkingObject != Editable_Poly ) then
|
|
(
|
|
Max Undo
|
|
)
|
|
|
|
--Check that geometry edits haven't been made
|
|
CurrentWorkingObjectFaceCount = PolyOp_GetNumFaces this.WorkingObject
|
|
if( CurrentWorkingObjectFaceCount != this.WorkingObjectFaceCount ) then
|
|
(
|
|
Max Undo
|
|
)
|
|
|
|
--Check if our working object is the current and only selection. If it isn't then force it.
|
|
if not( Selection.Count == 1 and Selection[1] == this.WorkingObject ) then
|
|
(
|
|
Select this.WorkingObject
|
|
)
|
|
|
|
--Put us in select mode if anything invalid is set
|
|
if not ( ToolMode.CommandMode == #SELECT or ToolMode.CommandMode == #VIEWPORT ) then
|
|
(
|
|
ToolMode.CommandMode = #SELECT
|
|
)
|
|
|
|
--Make sure we are in the correct sub selection mode
|
|
if( GetSelectionLevel this.WorkingObject != #Face ) then
|
|
(
|
|
SetSelectionLevel this.WorkingObject #Face
|
|
)
|
|
),
|
|
|
|
/*------------------------------------------------------------------------------
|
|
Locks selection to the working object using callbacks.
|
|
*/------------------------------------------------------------------------------
|
|
fn EngageLock = ( RegisterRedrawViewsCallback this.LockCallbackFn),
|
|
|
|
/*------------------------------------------------------------------------------
|
|
Unlocks the selection. Used when we have finished editing. Or something unexpected
|
|
has happened which is blocking the tool from working correctly.
|
|
*/------------------------------------------------------------------------------
|
|
fn DisengageLock = ( UnregisterRedrawViewsCallback this.LockCallbackFn ),
|
|
|
|
/*------------------------------------------------------------------------------
|
|
Checks the passed nodes to ensures they are each valid for edit.
|
|
*/------------------------------------------------------------------------------
|
|
fn CheckNodesAreValid TargetNodeArray =
|
|
(
|
|
if ( Selection.Count > 50 ) then
|
|
(
|
|
MessageBox "You have more than 50 objects selected. Please reduce this number. Try working in batches."
|
|
return False
|
|
)
|
|
if ( Selection.Count < 1 ) then
|
|
(
|
|
MessageBox "Please select some objects and try again."
|
|
return False
|
|
)
|
|
|
|
for SubNode in TargetNodeArray do
|
|
(
|
|
if not ( IsValidNode SubNode and SubNode.modifiers.Count == 0 and ( ClassOf SubNode == Editable_Poly or ClassOf SubNode == PolyMeshObject ) ) then
|
|
(
|
|
MessageBox "One or more of the selected objects are not valid. Check that all objects are of type 'Editable_Poly' and collapsed. Also ensure none of the objects are LOD objects. "
|
|
return False
|
|
)
|
|
)
|
|
|
|
return True
|
|
),
|
|
|
|
/*------------------------------------------------------------------------------
|
|
Creates our working object for the target object selection
|
|
*/------------------------------------------------------------------------------
|
|
fn CreateWorkingObject =
|
|
(
|
|
RSPushPrompt "Creating working object..."
|
|
|
|
--Create holding poly
|
|
this.WorkingObject = Editable_Mesh Name:"__ProceduralPainter__WorkingObject__"
|
|
ConvertToPoly( this.WorkingObject )
|
|
|
|
--Clone our input objects
|
|
ClonedNodes = #()
|
|
MaxOps.CloneNodes this.SourceObjectList newNodes:&ClonedNodes
|
|
|
|
--Clear materials so we can attached together safely
|
|
ClonedNodes.Material = Undefined
|
|
|
|
--For each clone
|
|
for ClonedNode in ClonedNodes do
|
|
(
|
|
--Attach into holding poly
|
|
PolyOp.Attach this.WorkingObject ClonedNode
|
|
)
|
|
|
|
--Assign our master multimat
|
|
this.WorkingObject.Material = this.WorkingObjectMultiMat
|
|
|
|
--Set the pivot to the centre of the object and reset
|
|
this.WorkingObject.Pivot = this.WorkingObject.Center
|
|
ResetXForm this.WorkingObject
|
|
|
|
--Use push
|
|
PushMod = Push Push_Value:0.05
|
|
AddModifier this.WorkingObject PushMod
|
|
|
|
--Add UVW map modifier and collapse
|
|
UVWMapMod = UVWMap Position:[0,0,0] Length:1 Width:10000 UTile:0.01
|
|
AddModifier this.WorkingObject UVWMapMod
|
|
ConvertToPoly this.WorkingObject
|
|
|
|
--Push a full update to all faces - sets up the material IDs correctly
|
|
this.PushFaceUpdate #All
|
|
|
|
--Set object properties
|
|
this.WorkingObject.BackFaceCull = true
|
|
this.WorkingObject.ShowFrozenInGray = false
|
|
|
|
--Clear face selection and setup editing
|
|
SetCommandPanelTaskMode #Modify
|
|
PolyOp.SetFaceSelection this.WorkingObject #{}
|
|
|
|
--Create a new layer for our working object - stops the object getting created on a layer that is hidden or frozen
|
|
this.WorkingLayer = LayerManager.NewLayer()
|
|
this.WorkingLayer.SetName "__ProceduralPainter__WorkingLayer__"
|
|
this.WorkingLayer.AddNode this.WorkingObject
|
|
|
|
RSPopPrompt()
|
|
),
|
|
|
|
/*------------------------------------------------------------------------------
|
|
Attempts to clean up the working object and layer
|
|
*/------------------------------------------------------------------------------
|
|
fn DeleteWorkingObject =
|
|
(
|
|
print this.WorkingObject
|
|
--Delete the working object
|
|
if( IsValidNode this.WorkingObject ) then ( Delete this.WorkingObject )
|
|
|
|
--Try and remove the working layer
|
|
try( LayerManager.DeleteLayerByName this.WorkingLayer.Name ) catch ()
|
|
),
|
|
|
|
/*------------------------------------------------------------------------------
|
|
Collects information about what ProceduralLevels are applied to the various faces of the target nodes.
|
|
*/------------------------------------------------------------------------------
|
|
fn CollectData =
|
|
(
|
|
--Create our top progress window
|
|
SourceObjectProgress = RSProgressWindow Title:"Collecting previous data..." StartStep:0 EndStep:SourceObjectList.Count
|
|
SourceObjectProgress.Start()
|
|
|
|
--Go through each object in the source object list
|
|
for SourceObject in this.SourceObjectList do
|
|
(
|
|
--Push progress update
|
|
SourceObjectProgress.PostProgressStep()
|
|
|
|
--Set the object as a procedural source
|
|
this.SetProceduralSourceProperty SourceObject True
|
|
|
|
--Check we have map support on the handle channel
|
|
this.SetupPresetChannel SourceObject this.DataChannel
|
|
|
|
--Convert the object to and from editable mesh which fixes a very strange issue where face indexes go out of wack
|
|
ConvertToMesh SourceObject
|
|
ConvertToPoly SourceObject
|
|
|
|
--Get face list for the whole object
|
|
FaceList = RSPoly_GetFaceList_NamedParameter SourceObject #All
|
|
|
|
--Create a new node via our node collection
|
|
CurrentNode = this.Painter.NodeCollection.CreateNode SourceObject.Handle SourceObject.Name FaceList.Count
|
|
|
|
--Unhide all faces
|
|
PolyOp.UnHideAllFaces SourceObject
|
|
|
|
--Start a sub progress
|
|
FaceIndexProgress = SourceObjectProgress.StartSubProgress 0 FaceList.Count SubTitle:SourceObject.Name
|
|
FaceIndexProgress.Start()
|
|
|
|
--Go through each face
|
|
HiddenFaceList = #{}
|
|
for FaceIndex in FaceList do
|
|
(
|
|
--Push progress update
|
|
FaceIndexProgress.PostProgressStep()
|
|
|
|
--Get source level map value
|
|
LevelMapValue = RSPoly_GetFace_MapValue SourceObject FaceIndex this.DataChannel
|
|
|
|
--Get the material on the face
|
|
FaceMaterial = RSGeom_GetFace_Material SourceObject FaceIndex
|
|
if( ClassOf FaceMaterial == Rage_Shader ) then
|
|
(
|
|
--If the shader is decal/cutout/alpha then mark it too be hidden
|
|
ShaderName = RstGetShaderName FaceMaterial
|
|
if( FindString ShaderName "decal" != Undefined or \
|
|
FindString ShaderName "alpha" != Undefined or \
|
|
FindString ShaderName "cutout" != Undefined ) then
|
|
(
|
|
Append HiddenFaceList FaceIndex
|
|
LevelMapValue = [0,0,0]
|
|
RSPoly_SetFace_MapValue SourceObject FaceIndex this.DataChannel LevelMapValue
|
|
)
|
|
)
|
|
|
|
--Get the procedural level from the components of LevelMapValue.
|
|
ProceduralLevel = this.Painter.SetData.GetProceduralLevel LevelMapValue[1] LevelMapValue[2] LevelMapValue[3]
|
|
|
|
--Create face data on the node with this information
|
|
CurrentNode.CreateFaceData FaceIndex ProceduralLevel
|
|
)
|
|
|
|
--Hide decal/cutout/alpha faces
|
|
PolyOp.SetHiddenFaces SourceObject HiddenFaceList
|
|
|
|
--End progress
|
|
FaceIndexProgress.End()
|
|
)
|
|
|
|
--Update the applied set
|
|
this.Painter.UpdateAppliedSet()
|
|
|
|
--Update applied counts
|
|
this.Painter.UpdateAppliedCounts()
|
|
|
|
--Set the applied set as the currently selected set
|
|
this.Painter.ResetSelectedSet()
|
|
|
|
--End progress
|
|
SourceObjectProgress.End()
|
|
),
|
|
|
|
/*------------------------------------------------------------------------------
|
|
Checks and sets up preset channel.
|
|
*/------------------------------------------------------------------------------
|
|
fn SetupPresetChannel InputNode InputMapChannel =
|
|
(
|
|
--Check for map support
|
|
if not ( PolyOp.GetMapSupport InputNode InputMapChannel ) then
|
|
(
|
|
--If it doesn't have any then set it up. Passing in black as the base map value - which is blank
|
|
RSPoly_ResetMapChannel InputNode InputMapChannel [0,0,0]
|
|
)
|
|
),
|
|
|
|
--Our master MultiMat
|
|
WorkingObjectMultiMat = MultiMaterial Name:"ProceduralPainter" NumSubs:1,
|
|
|
|
/*------------------------------------------------------------------------------
|
|
Gets the relevant material ID for the passed procedural level
|
|
*/------------------------------------------------------------------------------
|
|
fn GetProceduralLevelMaterialID InputProceduralLevel =
|
|
(
|
|
--Get the target material
|
|
TargetProceduralLevelMaterial = this.ResolveProceduralLevelMaterial InputProceduralLevel
|
|
|
|
--Return the ID
|
|
return( MultiMat_GetMaterialID WorkingObjectMultiMat TargetProceduralLevelMaterial)
|
|
),
|
|
|
|
/*------------------------------------------------------------------------------
|
|
Takes a procedural level and returns the associated material. Sets up a new material if need be.
|
|
*/------------------------------------------------------------------------------
|
|
fn ResolveProceduralLevelMaterial InputProceduralLevel =
|
|
(
|
|
ProceduralLevelString = InputProceduralLevel.ToString()
|
|
|
|
--Check if we already have an associated procedural level material
|
|
ReturnProceduralLevelMaterial = MultiMat_GetMaterialByName WorkingObjectMultiMat ProceduralLevelString
|
|
|
|
--Otherwise create a new procedural level material
|
|
if( ReturnProceduralLevelMaterial == Undefined ) then
|
|
(
|
|
--Create a new standard material with our checkered opacity map
|
|
ReturnProceduralLevelMaterial = Standard Name:ProceduralLevelString ShowInViewport:True
|
|
ReturnProceduralLevelMaterial.SelfIllumAmount = 30.0
|
|
ReturnProceduralLevelMaterial.OpacityMap = Checker Name:( ProceduralLevelString + " - OPACITY")
|
|
|
|
--Add the material to the next available slot
|
|
MultiMat_AddMaterial WorkingObjectMultiMat ReturnProceduralLevelMaterial
|
|
)
|
|
|
|
--Return the material
|
|
return ReturnProceduralLevelMaterial
|
|
),
|
|
|
|
DisplayMode = DotNetClass "ProceduralSystem.DisplayMode",
|
|
/*------------------------------------------------------------------------------
|
|
Updates the respective material of the passed procedural level so that it is in sync with our current display mode
|
|
*/------------------------------------------------------------------------------
|
|
fn UpdateDisplaySettings InputProceduralLevel =
|
|
(
|
|
--Get the target material
|
|
TargetProceduralLevelMaterial = this.ResolveProceduralLevelMaterial InputProceduralLevel
|
|
|
|
--Combined result
|
|
if( this.Painter.Display.CurrentMode == DisplayMode.CombinedResult ) then
|
|
(
|
|
TargetProceduralLevelMaterial.Diffuse = Color InputProceduralLevel.Color.R InputProceduralLevel.Color.G InputProceduralLevel.Color.B
|
|
return()
|
|
)
|
|
|
|
--IsolateDensity
|
|
if( this.Painter.Display.CurrentMode == DisplayMode.IsolateDensity ) then
|
|
(
|
|
ColorValue = InputProceduralLevel.Density * 255
|
|
TargetProceduralLevelMaterial.Diffuse = Color ColorValue ColorValue ColorValue
|
|
return()
|
|
)
|
|
|
|
--IsolateGroundTint
|
|
if( this.Painter.Display.CurrentMode == DisplayMode.IsolateGroundTint ) then
|
|
(
|
|
TargetProceduralLevelMaterial.Diffuse = Color InputProceduralLevel.GroundTint.R InputProceduralLevel.GroundTint.G InputProceduralLevel.GroundTint.B
|
|
return()
|
|
)
|
|
|
|
--IsolateScaleZ
|
|
if( this.Painter.Display.CurrentMode == DisplayMode.IsolateScaleZ ) then
|
|
(
|
|
ColorValue = InputProceduralLevel.ScaleZ * 255
|
|
TargetProceduralLevelMaterial.Diffuse = Color ColorValue ColorValue ColorValue
|
|
return()
|
|
)
|
|
|
|
--IsolateScaleXYZ
|
|
if( this.Painter.Display.CurrentMode == DisplayMode.IsolateScaleXYZ ) then
|
|
(
|
|
ColorValue = InputProceduralLevel.ScaleXYZ * 255
|
|
TargetProceduralLevelMaterial.Diffuse = Color ColorValue ColorValue ColorValue
|
|
return()
|
|
)
|
|
|
|
),
|
|
fn UpdateAllDisplaySettings =
|
|
(
|
|
for Procedural in this.Painter.AppliedSet.ProceduralArray do
|
|
(
|
|
for ProceduralLevel in Procedural.LevelArray do
|
|
(
|
|
this.UpdateDisplaySettings ProceduralLevel
|
|
)
|
|
)
|
|
),
|
|
|
|
RenderMode = DotNetClass "ProceduralSystem.RenderMode",
|
|
/*------------------------------------------------------------------------------
|
|
Updates the respective material of the passed procedural level so that it is in sync with our current render mode
|
|
*/------------------------------------------------------------------------------
|
|
fn UpdateRenderSettings InputProceduralLevel =
|
|
(
|
|
--Get the target material
|
|
TargetProceduralLevelMaterial = this.ResolveProceduralLevelMaterial InputProceduralLevel
|
|
|
|
--Transparent
|
|
if( this.Painter.Render.CurrentMode == RenderMode.Transparent ) then
|
|
(
|
|
ProceduralLevelOpacityValue = InputProceduralLevel.ParentProcedural.DisplayOpacity * 1.25
|
|
TargetProceduralLevelMaterial.OpacityMap.Color1 = Color ProceduralLevelOpacityValue ProceduralLevelOpacityValue ProceduralLevelOpacityValue
|
|
ProceduralLevelOpacityValue = InputProceduralLevel.ParentProcedural.DisplayOpacity * 2.55
|
|
TargetProceduralLevelMaterial.OpacityMap.Color2 = Color ProceduralLevelOpacityValue ProceduralLevelOpacityValue ProceduralLevelOpacityValue
|
|
return()
|
|
)
|
|
|
|
--Opaque
|
|
if( this.Painter.Render.CurrentMode == RenderMode.Opaque ) then
|
|
(
|
|
TargetProceduralLevelMaterial.OpacityMap.Color1 = Color 255 255 255
|
|
TargetProceduralLevelMaterial.OpacityMap.Color2 = Color 255 255 255
|
|
return()
|
|
)
|
|
),
|
|
fn UpdateAllRenderSettings =
|
|
(
|
|
for Procedural in this.Painter.AppliedSet.ProceduralArray do
|
|
(
|
|
for ProceduralLevel in Procedural.LevelArray do
|
|
(
|
|
this.UpdateRenderSettings ProceduralLevel
|
|
)
|
|
)
|
|
),
|
|
|
|
/*------------------------------------------------------------------------------
|
|
Updates the material IDs of the passed faces so they are upto date with the associated procedural level
|
|
*/------------------------------------------------------------------------------
|
|
fn PushFaceUpdate InputFaceList =
|
|
(
|
|
--Check if we have been passed a named parameter #All #Selection #None
|
|
if( ClassOf InputFaceList == Name ) then
|
|
(
|
|
--Convert to proper bitarray
|
|
InputFaceList = RSPoly_GetFaceList_NamedParameter this.WorkingObject InputFaceList
|
|
)
|
|
|
|
--Convert to array
|
|
InputFaceList = InputFaceList as Array
|
|
|
|
--Get the procedural levels used across the given faces
|
|
ProceduralLevelList = this.Painter.NodeCollection.GetProceduralLevelList InputFaceList
|
|
|
|
--For each of the procedural level applied
|
|
for TargetProceduralLevel in ProceduralLevelList do
|
|
(
|
|
--Resolve the material ID that relates to our procedural level
|
|
TargetProceduralLevelMaterialID = this.GetProceduralLevelMaterialID TargetProceduralLevel
|
|
|
|
--Get the face list the procedural is applied to - restrict by input face list
|
|
TargetFaceList = this.Painter.NodeCollection.GetFaceListByProceduralLevel TargetProceduralLevel InputFaceList
|
|
|
|
--Convert to bit array and set the material ID
|
|
TargetFaceList = TargetFaceList as BitArray
|
|
PolyOp_SetFaceMatID this.WorkingObject TargetFaceList TargetProceduralLevelMaterialID
|
|
)
|
|
),
|
|
|
|
/*------------------------------------------------------------------------------
|
|
Applies the passed procedural level to all the faces in the passed face list
|
|
*/------------------------------------------------------------------------------
|
|
fn ApplyProceduralLevel InputFaceList InputProceduralLevel =
|
|
(
|
|
--Check if we have been passed a named parameter #All #Selection #None
|
|
if( ClassOf InputFaceList == Name ) then
|
|
(
|
|
--If we are working with a selection then check that the selection is not to big
|
|
if( InputFaceList == #Selection ) then
|
|
(
|
|
InputFaceList = RSPoly_GetFaceList_NamedParameter this.WorkingObject InputFaceList
|
|
|
|
if( ( InputFaceList as Array ).Count > 1000 ) then
|
|
(
|
|
if not( QueryBox "This operation is going to affect more than 1000 faces. The operation will be permanent. Would you like to continue?" ) then ( return() )
|
|
)
|
|
)
|
|
else
|
|
(
|
|
InputFaceList = RSPoly_GetFaceList_NamedParameter this.WorkingObject InputFaceList
|
|
)
|
|
)
|
|
|
|
--Mutilate from bitarray to an array so it can be passed to DotNet
|
|
InputFaceList = InputFaceList as Array
|
|
|
|
--Apply the procedural
|
|
this.Painter.NodeCollection.SetProceduralLevel InputFaceList InputProceduralLevel
|
|
|
|
--Mark that we now have unsaved changes
|
|
this.Painter.NodeCollection.UnsavedDataChanges = true
|
|
|
|
if( InputProceduralLevel != this.BlankProceduralLevel ) then
|
|
(
|
|
--Update the display and render settings for the material
|
|
this.UpdateRenderSettings InputProceduralLevel
|
|
this.UpdateDisplaySettings InputProceduralLevel
|
|
)
|
|
|
|
--Push this update through to the face mat ID
|
|
this.PushFaceUpdate InputFaceList
|
|
),
|
|
|
|
/*------------------------------------------------------------------------------
|
|
Sets a time and data stamp on the passed object
|
|
*/------------------------------------------------------------------------------
|
|
ProceduralTimeStampKey = "ProceduralTimeStamp",
|
|
ProceduralDataStampKey = "ProceduralDataStamp",
|
|
fn SetProceduralStamp InputNode =
|
|
(
|
|
UTCNow = ( DotNetClass "System.DateTime" ).UTCNow
|
|
SetUserProp InputNode this.ProceduralTimeStampKey ( UTCNow.ToFileTime() )
|
|
SetUserProp InputNode this.ProceduralDataStampKey ( this.Painter.SetData.Version.ToString() )
|
|
),
|
|
|
|
/*------------------------------------------------------------------------------
|
|
Returns true if the passed object has a data version stamp that matches our current SetData
|
|
*/------------------------------------------------------------------------------
|
|
fn HasProceduralStamp InputNode =
|
|
(
|
|
ProceduralTimeStampValue = GetUserProp InputNode this.ProceduralTimeStampKey
|
|
ProceduralDataStampValue = GetUserProp InputNode this.ProceduralDataStampKey
|
|
|
|
if( ProceduralTimeStampValue != Undefined and ProceduralDataStampValue != Undefined ) then
|
|
( return True )
|
|
else
|
|
( return False )
|
|
),
|
|
|
|
/*------------------------------------------------------------------------------
|
|
Returns true if the passed object has a data version stamp that matches our current SetData
|
|
*/------------------------------------------------------------------------------
|
|
fn CheckDataStamp InputNode =
|
|
(
|
|
CurrentDataStamp = GetUserProp InputNode this.ProceduralDataStampKey
|
|
|
|
if( CurrentDataStamp == this.Painter.SetData.Version.ToString() ) then
|
|
( return True )
|
|
else
|
|
( return False )
|
|
),
|
|
|
|
/*------------------------------------------------------------------------------
|
|
Commits/writes the stored data from the NodeCollection out to the relevant nodes
|
|
*/------------------------------------------------------------------------------
|
|
fn CommitData =
|
|
(
|
|
--Create our top progress window
|
|
NodeDataProgress = RSProgressWindow Title:"Saving procedural data..." StartStep:0 EndStep:this.Painter.NodeCollection.NodeDataArray.Count
|
|
NodeDataProgress.Start()
|
|
|
|
--Go through each of our node data objects
|
|
for NodeData in this.Painter.NodeCollection.NodeDataArray do
|
|
(
|
|
--Push progress update
|
|
NodeDataProgress.PostProgressStep()
|
|
|
|
--Get the target node by handle
|
|
TargetNode = MaxOps.GetNodeByHandle NodeData.Handle
|
|
|
|
--Start a sub progress
|
|
NodeFaceDataProgress = NodeDataProgress.StartSubProgress 0 NodeData.NodeFaceDataArray.Count SubTitle:TargetNode.Name
|
|
NodeFaceDataProgress.Start()
|
|
|
|
--Reset channel to black ready to apply procedural level map values
|
|
RSPoly_ResetMapChannel TargetNode this.DataChannel [0,0,0]
|
|
|
|
--Go through each NodeFaceData
|
|
for NodeFaceData in NodeData.NodeFaceDataArray do
|
|
(
|
|
--Push progress update
|
|
NodeFaceDataProgress.PostProgressStep()
|
|
|
|
--Get our applied procedural level
|
|
ProceduralLevel = NodeFaceData.ProceduralLevel
|
|
|
|
if( ProceduralLevel != this.BlankProceduralLevel ) then
|
|
(
|
|
--Setup our map values from the procedural level
|
|
LevelMapValue = [ProceduralLevel.Color.ScR, ProceduralLevel.Color.ScG, ProceduralLevel.Color.ScB]
|
|
|
|
--Set the target faces to the map value
|
|
RSPoly_SetFace_MapValue TargetNode NodeFaceData.FaceIndex this.DataChannel LevelMapValue
|
|
)
|
|
|
|
--Reset value changed
|
|
NodeFaceData.DataAltered = False
|
|
)
|
|
|
|
--Set the the procedural stamp for this change
|
|
this.SetProceduralStamp TargetNode
|
|
|
|
--End progress
|
|
NodeFaceDataProgress.End()
|
|
)
|
|
|
|
--End progress
|
|
NodeDataProgress.End()
|
|
|
|
--Mark that we now have saved all changes
|
|
this.Painter.NodeCollection.UnsavedDataChanges = False
|
|
|
|
--Automatically transfer to collision meshes if needed
|
|
if( this.Painter.AutoTransferAfterCommit ) then
|
|
(
|
|
this.TransferListUpdate()
|
|
--this.TransferDataToProcMesh()
|
|
)
|
|
),
|
|
|
|
/*------------------------------------------------------------------------------
|
|
Selects the faces of the passed procedural level
|
|
*/------------------------------------------------------------------------------
|
|
fn SelectProceduralLevel InputProceduralLevel =
|
|
(
|
|
--Get an array of all the faces
|
|
SourceFaceList = RSPoly_GetFaceList_NamedParameter this.WorkingObject #All
|
|
SourceFaceList = SourceFaceList as Array
|
|
|
|
--Get faces used by the input procedural level
|
|
TargetFaceList = this.Painter.NodeCollection.GetFaceListByProceduralLevel InputProceduralLevel SourceFaceList
|
|
|
|
--Mutilate to bit array
|
|
TargetFaceList = TargetFaceList as BitArray
|
|
|
|
--Select polys
|
|
PolyOp.SetFaceSelection this.WorkingObject TargetFaceList
|
|
|
|
--Push a scene redraw so the faces appear selected
|
|
RedrawViews()
|
|
),
|
|
|
|
/*------------------------------------------------------------------------------
|
|
Attempts to auto step/blend the levels. Works on selected faces
|
|
*/------------------------------------------------------------------------------
|
|
fn AutoBlendProceduralLevels =
|
|
(
|
|
--Get an array of selected the faces
|
|
SourceFaceList = RSPoly_GetFaceList_NamedParameter this.WorkingObject #Selection
|
|
SourceFaceList = SourceFaceList as Array
|
|
|
|
--Get the procedurals used on the passed faces
|
|
ProceduralList = this.Painter.NodeCollection.GetProceduralList SourceFaceList
|
|
|
|
--For each procedural
|
|
for Procedural in ProceduralList do
|
|
(
|
|
--Start with all faces (from all levels)
|
|
ProceduralFaceList = this.Painter.NodeCollection.GetFaceListByProcedural Procedural SourceFaceList
|
|
ProceduralFaceList = ProceduralFaceList as BitArray
|
|
|
|
--Set the base level as our current level
|
|
CurrentLevel = Procedural.BaseLevel
|
|
|
|
--While we haven't reached the top level
|
|
while CurrentLevel != Undefined do
|
|
(
|
|
--Get the procedural level faces by reducing from the original face list
|
|
ProceduralLevelFaceList = RSPoly_GetFaceList_DistanceReduced this.WorkingObject ProceduralFaceList CurrentLevel.BlendDistance
|
|
|
|
--Set faces to current level
|
|
this.ApplyProceduralLevel ProceduralLevelFaceList CurrentLevel
|
|
|
|
--Move onto next level
|
|
CurrentLevel = CurrentLevel.NextLevel
|
|
)
|
|
)
|
|
),
|
|
|
|
/*------------------------------------------------------------------------------
|
|
Fragments the block of faces based on the spacing values stored in the procedural
|
|
*/------------------------------------------------------------------------------
|
|
fn ProcessFaceSpacing =
|
|
(
|
|
--Get an array of selected the faces
|
|
SourceFaceList = RSPoly_GetFaceList_NamedParameter this.WorkingObject #Selection
|
|
SourceFaceList = SourceFaceList as Array
|
|
|
|
--Get the procedurals used on the passed faces
|
|
ProceduralList = this.Painter.NodeCollection.GetProceduralList SourceFaceList
|
|
|
|
--For each procedural
|
|
for Procedural in ProceduralList do
|
|
(
|
|
--Start with all faces (from all levels)
|
|
ProceduralFaceList = this.Painter.NodeCollection.GetFaceListByProcedural Procedural SourceFaceList
|
|
ProceduralFaceList = ProceduralFaceList as BitArray
|
|
|
|
--Then get a reduced selection based on distance
|
|
ProcessedProceduralFaceList = RSPoly_GetFaceList_DistanceDistributed this.WorkingObject ProceduralFaceList Procedural.Spacing
|
|
|
|
--Get the inversion
|
|
FinalProceduralFaceList = ProceduralFaceList - ProcessedProceduralFaceList
|
|
|
|
--First clear the faces
|
|
this.ApplyProceduralLevel FinalProceduralFaceList this.BlankProceduralLevel
|
|
)
|
|
),
|
|
|
|
/*------------------------------------------------------------------------------
|
|
Selects the faces of the passed procedural
|
|
*/------------------------------------------------------------------------------
|
|
fn SelectProcedural InputProcedural =
|
|
(
|
|
--Get an array of all the faces
|
|
SourceFaceList = RSPoly_GetFaceList_NamedParameter this.WorkingObject #All
|
|
SourceFaceList = SourceFaceList as Array
|
|
|
|
--Get faces used by the input procedural
|
|
TargetFaceList = this.Painter.NodeCollection.GetFaceListByProcedural InputProcedural SourceFaceList
|
|
|
|
--Mutilate to bit array
|
|
TargetFaceList = TargetFaceList as BitArray
|
|
|
|
--Select polys
|
|
PolyOp.SetFaceSelection this.WorkingObject TargetFaceList
|
|
|
|
--Push a scene redraw so the faces appear selected
|
|
RedrawViews()
|
|
),
|
|
|
|
/*------------------------------------------------------------------------------
|
|
Removes the passed procedural from the any of the objects faces
|
|
*/------------------------------------------------------------------------------
|
|
fn RemoveProcedural InputProcedural =
|
|
(
|
|
--Get an array of all the faces
|
|
SourceFaceList = RSPoly_GetFaceList_NamedParameter this.WorkingObject #All
|
|
SourceFaceList = SourceFaceList as Array
|
|
|
|
--Get faces used by the input procedural level
|
|
TargetFaceList = this.Painter.NodeCollection.GetFaceListByProcedural InputProcedural SourceFaceList
|
|
|
|
--Apply our blank procedural to those faces
|
|
this.ApplyProceduralLevel TargetFaceList this.BlankProceduralLevel
|
|
),
|
|
|
|
/*------------------------------------------------------------------------------
|
|
Returns an array of objects that are within range for transfering of data
|
|
*/------------------------------------------------------------------------------
|
|
fn GetProximateProceduralSourceList InputCollisionMesh =
|
|
(
|
|
return( for ProceduralSource in this.GetProceduralSourceList() where RSNodesAreProximal InputCollisionMesh ProceduralSource collect ProceduralSource )
|
|
),
|
|
|
|
/*------------------------------------------------------------------------------
|
|
Sets a time and data stamp on the passed object
|
|
*/------------------------------------------------------------------------------
|
|
fn NeedsUpdating InputVisualMesh =
|
|
(
|
|
if ((finditem CreatesEmptyProcMesh InputVisualMesh) != 0) then
|
|
(
|
|
return false
|
|
)
|
|
|
|
--First we check the data stamp of the visualmesh. If it doesn't match then we'll have to do an update.
|
|
if not( this.CheckDataStamp InputVisualMesh ) then
|
|
(
|
|
--format "% Check dataStamp\n" InputVisualMesh
|
|
return true
|
|
)
|
|
|
|
--does this visual mesh have a corresponding procedural collision mesh
|
|
local InputCollisionMesh = getNodeByName (InputVisualMesh.name + "_PROC_MESH")
|
|
if (InputCollisionMesh != undefined) then
|
|
(
|
|
--If the data stamp matched then we check the time stamp on each of the source objects
|
|
--and see if it is later than the stamp on our collision mesh. Or in other words; has any of the
|
|
--procedural source objects been changed since we last transfered data.
|
|
CollisionTimeStamp = GetUserProp InputCollisionMesh this.ProceduralTimeStampKey
|
|
|
|
--Check to make sure we have a time stamp on our collision mesh. If not then we must update.
|
|
if( CollisionTimeStamp == Undefined ) then
|
|
(
|
|
--format "% Collision time stamp\n" InputCollisionMesh
|
|
return true
|
|
)
|
|
|
|
--Check the collision time stamp against the InputVisualMesh
|
|
--Get the time stamp
|
|
local ProceduralSourceTimeStamp = GetUserProp InputVisualMesh this.ProceduralTimeStampKey
|
|
if( ProceduralSourceTimeStamp == Undefined ) then
|
|
(
|
|
--If it doesn't have one set then add one now
|
|
this.SetProceduralStamp InputVisualMesh
|
|
ProceduralSourceTimeStamp = GetUserProp InputVisualMesh this.ProceduralTimeStampKey
|
|
)
|
|
|
|
--Check it
|
|
if( ProceduralSourceTimeStamp > CollisionTimeStamp ) then
|
|
(
|
|
--format "% out of date collision: % \n" ProceduralSource InputCollisionMesh
|
|
return true
|
|
)
|
|
)
|
|
else if (InputCollisionMesh == undefined) or (not isValidNode InputCollisionMesh) then
|
|
(
|
|
--format "% no collision mesh\n" InputVisualMesh
|
|
return true
|
|
)
|
|
|
|
--default
|
|
return false
|
|
),
|
|
|
|
/*------------------------------------------------------------------------------
|
|
Gets the material for passed collision mesh
|
|
*/------------------------------------------------------------------------------
|
|
fn GetCollisionContainerMaterial InputCollisionMesh =
|
|
(
|
|
--Get the container of the collision
|
|
CollisionContainer = Containers.IsInContainer InputCollisionMesh
|
|
if( CollisionContainer != Undefined ) then
|
|
(
|
|
CollisionContainerMaterialName = CollisionContainer.Name + "_REX_COLLISION"
|
|
MaterialMatches = for SceneMat in SceneMaterials where SceneMat.Name == CollisionContainerMaterialName collect SceneMat
|
|
|
|
if( MaterialMatches.Count > 0 ) then
|
|
(
|
|
return MaterialMatches[1]
|
|
)
|
|
else
|
|
(
|
|
return ( MultiMaterial NumSubs:1 Name:CollisionContainerMaterialName )
|
|
)
|
|
)
|
|
else ( return Undefined )
|
|
),
|
|
|
|
/*------------------------------------------------------------------------------
|
|
Gets the material applied to the passed face
|
|
*/------------------------------------------------------------------------------
|
|
fn GetCollisionFaceMaterial InputCollisionMesh InputFaceIndex =
|
|
(
|
|
CollisionFaceMaterial = RSGeom_GetFace_Material InputCollisionMesh InputFaceIndex
|
|
|
|
if( ClassOf CollisionFaceMaterial == RexBoundMtl ) then
|
|
( return CollisionFaceMaterial )
|
|
else
|
|
( return Undefined )
|
|
),
|
|
|
|
/*------------------------------------------------------------------------------
|
|
Updates the collision transfer list
|
|
*/------------------------------------------------------------------------------
|
|
fn TransferListUpdate =
|
|
(
|
|
local VisualTargetList = this.GetProceduralSourceList()
|
|
gRsUlog.validate()
|
|
--CollisionTargetList = this.GetCollisionTargetList()
|
|
|
|
this.Painter.TransferListClear()
|
|
for VisualTarget in VisualTargetList do
|
|
(
|
|
VisualTargetNeedsUpdating = this.NeedsUpdating VisualTarget
|
|
this.Painter.TransferListAddCollision VisualTarget.Handle VisualTarget.Name VisualTargetNeedsUpdating
|
|
)
|
|
),
|
|
|
|
|
|
|
|
/*------------------------------------------------------------------------------
|
|
Adds collision meshes from the passed selection.
|
|
*/------------------------------------------------------------------------------
|
|
fn TransferListAddCollision InputObjArray =
|
|
(
|
|
for Obj in InputObjArray do ( this.SetCollisionTargetProperty Obj True )
|
|
this.TransferListUpdate()
|
|
),
|
|
|
|
/*------------------------------------------------------------------------------
|
|
Removes collision meshes from the passed selection
|
|
*/------------------------------------------------------------------------------
|
|
fn TransferListRemoveCollision InputObjArray =
|
|
(
|
|
for Obj in InputObjArray do
|
|
(
|
|
this.Painter.TransferListRemoveCollision Obj.Handle
|
|
this.SetCollisionTargetProperty Obj False
|
|
)
|
|
this.TransferListUpdate()
|
|
),
|
|
|
|
/*------------------------------------------------------------------------------
|
|
Removes collision meshes from the passed selection
|
|
*/------------------------------------------------------------------------------
|
|
fn TransferListSelectAllCollision =
|
|
(
|
|
this.TransferListUpdate()
|
|
--CollisionTargetList = this.GetCollisionTargetList()
|
|
CollisionTargetList = this.GetProceduralSourceList()
|
|
ClearSelection()
|
|
Select CollisionTargetList
|
|
),
|
|
|
|
|
|
/*------------------------------------------------------------------------------
|
|
Clear list selection
|
|
*/------------------------------------------------------------------------------
|
|
fn TransferListSelectNoneCollision =
|
|
(
|
|
this.TransferListUpdate()
|
|
for i = 0 to (this.Painter.TransferList.Count - 1) do
|
|
(
|
|
this.Painter.TransferList.Item[i].SelectedForTransfer = false
|
|
)
|
|
ClearSelection()
|
|
|
|
),
|
|
|
|
|
|
/*------------------------------------------------------------------------------
|
|
Gets a list of all collisions that are marked as targets for transfer
|
|
*/------------------------------------------------------------------------------
|
|
fn GetCollisionTargetList =
|
|
(
|
|
return ( for HelperObj in Helpers where this.IsCollisionTarget HelperObj collect HelperObj )
|
|
),
|
|
|
|
/*------------------------------------------------------------------------------
|
|
Returns true if the passed object is a collision target
|
|
*/------------------------------------------------------------------------------
|
|
CollisionTargetKey = "ProceduralTransfer",
|
|
fn IsCollisionTarget InputObject =
|
|
(
|
|
--Check the object is of the correct type (rules out things like RSRef objects)
|
|
if not( ClassOf InputObject == Col_Mesh ) then ( return False )
|
|
|
|
--Check that the col_mesh is in a Containers
|
|
if ( Containers.IsInContainer InputObject == Undefined ) then ( return False )
|
|
|
|
--Check that the col_mesh is material type
|
|
--if not ( gRsCollTypes.hasWeaponsFlag InputObject ) then ( return False )
|
|
if ( getUserProp InputObject "material" == undefined ) then ( return False )
|
|
if not ( getUserProp InputObject "material" ) then
|
|
(
|
|
return False
|
|
)
|
|
else
|
|
(
|
|
return true
|
|
)
|
|
|
|
--Check the target collision property exists
|
|
CollisionTargetPropertyValue = GetUserProp InputObject this.CollisionTargetKey
|
|
if( CollisionTargetPropertyValue != Undefined and ClassOf CollisionTargetPropertyValue == BooleanClass ) then
|
|
( return CollisionTargetPropertyValue )
|
|
else
|
|
( return False )
|
|
),
|
|
|
|
/*------------------------------------------------------------------------------
|
|
Sets the collision target property on the passed object to the passed value
|
|
*/------------------------------------------------------------------------------
|
|
fn SetCollisionTargetProperty InputObject InputValue = ( SetUserProp InputObject this.CollisionTargetKey InputValue ),
|
|
|
|
/*------------------------------------------------------------------------------
|
|
Updates our collision target spatial hash set. Primarily used to pair changes from the game to collision meshes.
|
|
*/------------------------------------------------------------------------------
|
|
CollisionTargetSpatialHashSet,
|
|
fn UpdateCollisionTargetSpatialHashSet =
|
|
(
|
|
--Get list of our collision targets
|
|
CollisionTargetList = this.GetCollisionTargetList()
|
|
|
|
--Check if we need to update the hash set
|
|
if( this.CollisionTargetSpatialHashSet != Undefined ) then
|
|
(
|
|
if( this.CollisionTargetSpatialHashSet.ContentHash != CollisionTargetList as String ) then
|
|
(
|
|
this.CollisionTargetSpatialHashSet.Dispose()
|
|
)
|
|
else ( return Ok )
|
|
)
|
|
|
|
--Create our SpatialHashSet
|
|
this.CollisionTargetSpatialHashSet = SpatialHashSet()
|
|
this.CollisionTargetSpatialHashSet.SetCellSearchBreadth 1
|
|
|
|
--Create our top progress window
|
|
SpatialHashSetProgress = RSProgressWindow Title:"Gathering target collision data..." StartStep:0 EndStep:CollisionTargetList.Count
|
|
SpatialHashSetProgress.Start()
|
|
|
|
for CollisionTarget in CollisionTargetList do
|
|
(
|
|
--Push progress update
|
|
SpatialHashSetProgress.PostProgressStep()
|
|
|
|
--Convert the collision mesh to editable mesh
|
|
Col2Mesh CollisionTarget
|
|
FaceCount = GetNumFaces CollisionTarget
|
|
|
|
--Create sub progress
|
|
FaceProgress = SpatialHashSetProgress.StartSubProgress 0 FaceCount SubTitle:CollisionTarget.Name
|
|
FaceProgress.Start()
|
|
|
|
--For each face of the ProceduralSource
|
|
for FaceIndex = 1 to FaceCount do
|
|
(
|
|
--Push progress update
|
|
FaceProgress.PostProgressStep()
|
|
|
|
--Get the face centre
|
|
FaceCentre = MeshOp_GetFaceCenter CollisionTarget FaceIndex
|
|
|
|
--Create our entry and add it
|
|
FaceEntry = DataPair FaceIndex:FaceIndex Node:CollisionTarget
|
|
this.CollisionTargetSpatialHashSet.AddEntry FaceCentre FaceEntry
|
|
)
|
|
|
|
--Back to collision
|
|
Mesh2Col CollisionTarget
|
|
|
|
--End progress
|
|
FaceProgress.End()
|
|
)
|
|
|
|
--End progress
|
|
SpatialHashSetProgress.End()
|
|
|
|
--Set content hash so we know not to rebuild
|
|
this.CollisionTargetSpatialHashSet.ContentHash = CollisionTargetList as String
|
|
),
|
|
|
|
/*------------------------------------------------------------------------------
|
|
Gets a list of all procedural sources in the scene
|
|
*/------------------------------------------------------------------------------
|
|
fn GetProceduralSourceList =
|
|
(
|
|
return( for GeomObj in Geometry where this.IsProceduralSource GeomObj collect GeomObj )
|
|
),
|
|
|
|
/*------------------------------------------------------------------------------
|
|
Returns true if the passed object is a procedural source
|
|
*/------------------------------------------------------------------------------
|
|
ProceduralSourceKey = "ProceduralSource",
|
|
fn IsProceduralSource InputObject =
|
|
(
|
|
--Check the object is of the correct type (rules out things like RSRef objects)
|
|
if not( ClassOf InputObject == Editable_Mesh or ClassOf InputObject == Editable_Poly or ClassOf InputObject == PolyMeshObject ) then
|
|
(
|
|
return false
|
|
)
|
|
|
|
--Check the object isn't a LOD because that wouldn't make sense
|
|
if( RsIsAnyLOD InputObject ) then
|
|
(
|
|
return false
|
|
)
|
|
|
|
--Check the procedural source property exists
|
|
ProceduralSourcePropertyValue = GetUserProp InputObject this.ProceduralSourceKey
|
|
if( ProceduralSourcePropertyValue == Undefined or ClassOf ProceduralSourcePropertyValue != BooleanClass or ProceduralSourcePropertyValue == False ) then
|
|
( return False )
|
|
|
|
--Check what shader is applied. If its a single fur_grass type then exclude it
|
|
local InputObjectMaterial = InputObject.material
|
|
local faceMats = RsGetMatIdsUsedByObj InputObject
|
|
|
|
if (classOf InputObjectMaterial == Multimaterial) then
|
|
(
|
|
local faceMats = RsGetMatIdsUsedByObj InputObject
|
|
|
|
if (faceMats.numberSet == 1) then --singular material assignment
|
|
(
|
|
local matId = (faceMats as Array)[1]
|
|
|
|
-- CHECK TO SEE IF SHADER IS VALID
|
|
if (InputObjectMaterial[matId] != undefined) then
|
|
(
|
|
local shaderName = RstGetShaderName InputObjectMaterial[matId]
|
|
|
|
if (matchpattern shaderName pattern:"*fur*") then
|
|
(
|
|
return false
|
|
)
|
|
)
|
|
else
|
|
(
|
|
messageBox ("MapID [" + matId as string + "] on " + InputObject.name + " isn't a valid shader, please check your mapIDs!") title:"Proc Painter Error!"
|
|
return false
|
|
)
|
|
)
|
|
)
|
|
else
|
|
(
|
|
if (classOf InputObjectMaterial) != Rage_Shader then
|
|
(
|
|
return false
|
|
)
|
|
else
|
|
(
|
|
local shaderName = RstGetShaderName InputObjectMaterial
|
|
|
|
if (matchpattern shaderName pattern:"*fur*") then
|
|
(
|
|
return false
|
|
)
|
|
)
|
|
)
|
|
|
|
|
|
--Check we have some data in channel 31 (if we don't then we'll give it some).
|
|
--This really shouldn't happen it's merely a defensive measure.
|
|
if( ClassOf InputObject == Editable_Mesh ) then
|
|
(
|
|
if not( MeshOp.GetMapSupport InputObject this.DataChannel ) then ( RSMesh_ResetMapChannel InputObject this.DataChannel [0,0,0] )
|
|
)
|
|
if( ClassOf InputObject == Editable_Poly or ClassOf InputObject == PolyMeshObject ) then
|
|
(
|
|
if not( PolyOp.GetMapSupport InputObject this.DataChannel ) then ( RSPoly_ResetMapChannel InputObject this.DataChannel [0,0,0] )
|
|
)
|
|
|
|
return True
|
|
),
|
|
|
|
/*------------------------------------------------------------------------------
|
|
Sets the procedural source property on the passed object to the passed value
|
|
*/------------------------------------------------------------------------------
|
|
fn SetProceduralSourceProperty InputObject InputValue = ( SetUserProp InputObject this.ProceduralSourceKey InputValue ),
|
|
|
|
/*------------------------------------------------------------------------------
|
|
Updates our procedural source spatial hash set. Primarily used to pair collision faces with procedural source faces.
|
|
*/------------------------------------------------------------------------------
|
|
ProceduralSourceSpatialHashSet,
|
|
fn UpdateProceduralSourceSpatialHashSet =
|
|
(
|
|
--Get list of procedural sources
|
|
ProceduralSourceList = this.GetProceduralSourceList()
|
|
|
|
--Check if we need to update the hash set
|
|
if( this.ProceduralSourceSpatialHashSet != Undefined ) then
|
|
(
|
|
if( this.ProceduralSourceSpatialHashSet.ContentHash != ProceduralSourceList as String ) then
|
|
(
|
|
this.ProceduralSourceSpatialHashSet.Dispose()
|
|
)
|
|
else ( return Ok )
|
|
)
|
|
|
|
--Create our SpatialHashSet
|
|
this.ProceduralSourceSpatialHashSet = SpatialHashSet()
|
|
this.ProceduralSourceSpatialHashSet.SetCellSearchBreadth 1
|
|
|
|
--Create our top progress window
|
|
SpatialHashSetProgress = RSProgressWindow Title:"Gathering scene procedural data..." StartStep:0 EndStep:ProceduralSourceList.Count
|
|
SpatialHashSetProgress.Start()
|
|
|
|
for ProceduralSource in ProceduralSourceList do
|
|
(
|
|
--Push progress update
|
|
SpatialHashSetProgress.PostProgressStep()
|
|
|
|
FaceCount = GetNumFaces ProceduralSource
|
|
|
|
--Create sub progress
|
|
FaceProgress = SpatialHashSetProgress.StartSubProgress 0 FaceCount SubTitle:ProceduralSource.Name
|
|
FaceProgress.Start()
|
|
|
|
--For each face of the ProceduralSource
|
|
for FaceIndex = 1 to FaceCount do
|
|
(
|
|
--Push progress update
|
|
FaceProgress.PostProgressStep()
|
|
|
|
--Get the material on the face
|
|
FaceMaterial = RSGeom_GetFace_Material ProceduralSource FaceIndex
|
|
if( ClassOf FaceMaterial == Rage_Shader ) then
|
|
(
|
|
--If the shader is decal/cutout/alpha then continue to the next face
|
|
ShaderName = RstGetShaderName FaceMaterial
|
|
if( FindString ShaderName "decal" != Undefined or \
|
|
FindString ShaderName "alpha" != Undefined or \
|
|
FindString ShaderName "cutout" != Undefined ) then ( continue )
|
|
)
|
|
|
|
--Get the face centre
|
|
FaceCentre
|
|
if( ClassOf ProceduralSource == Editable_Mesh ) then
|
|
( FaceCentre = MeshOp_GetFaceCenter ProceduralSource FaceIndex )
|
|
else
|
|
( FaceCentre = PolyOp_GetFaceCenter ProceduralSource FaceIndex )
|
|
|
|
--Create our entry and add it
|
|
FaceEntry = DataPair FaceIndex:FaceIndex Node:ProceduralSource
|
|
this.ProceduralSourceSpatialHashSet.AddEntry FaceCentre FaceEntry
|
|
)
|
|
|
|
--End progress
|
|
FaceProgress.End()
|
|
)
|
|
|
|
--End progress
|
|
SpatialHashSetProgress.End()
|
|
|
|
--Set content hash so we know not to rebuild
|
|
this.ProceduralSourceSpatialHashSet.ContentHash = ProceduralSourceList as String
|
|
),
|
|
|
|
--Channel for storing the ground tinting
|
|
CollisionGroundTintChannel = 11,
|
|
CollisionGroundTintOverrideChannel = 13,
|
|
|
|
--Channel for storing the scale and density
|
|
CollisionScaleDensityChannel = 12,
|
|
CollisionScaleDensityOverrideChannel = 14,
|
|
|
|
/*------------------------------------------------------------------------------
|
|
Transfers data from source procedural objects to collision meshes
|
|
*/------------------------------------------------------------------------------
|
|
TransferFaceAreaThreshold = 3.0,
|
|
GroundTintBlankMapValue = [1,1,1],
|
|
ProcecduralTintAttributeIdx = ( GetAttrIndex "Gta Collision" "Use Procedural Tint" ),
|
|
|
|
|
|
/***
|
|
Chack and create a layer to hold any generated Procmeshes
|
|
***/
|
|
fn AddModelToProcMeshLayer model =
|
|
(
|
|
local layerName = "Procedural Material Meshes"
|
|
local procMeshLayer = LayerManager.getLayerFromName layerName
|
|
if (procMeshLayer == undefined) then
|
|
(
|
|
procMeshLayer = LayerManager.newLayerFromName layerName
|
|
)
|
|
|
|
procMeshLayer.addNode model
|
|
|
|
),
|
|
|
|
/*------------------------------------------------------------------------------
|
|
Transfers data from source procedural objects to procedural meshes
|
|
*/------------------------------------------------------------------------------
|
|
fn TransferDataToProcMesh =
|
|
(
|
|
local keepGoing = undefined
|
|
|
|
--Get visual targets that are marked for transfer
|
|
VisualTargetList = for VisualTarget in this.Painter.TransferArray
|
|
where VisualTarget.SelectedForTransfer and \
|
|
((MaxOps.GetNodeByHandle VisualTarget.NodeHandle) != Undefined)
|
|
collect MaxOps.GetNodeByHandle VisualTarget.NodeHandle
|
|
|
|
--Load the ground tint image
|
|
--if( CollisionTargetList.Count == 0 ) then( return() )
|
|
|
|
-- if (Selection.count == 0) then
|
|
-- (
|
|
clearSelection()
|
|
for VisualMesh in VisualTargetList do
|
|
(
|
|
selectmore VisualMesh
|
|
)
|
|
-- )
|
|
|
|
--Check our selection is valid.
|
|
if not( this.CheckNodesAreValid Selection ) then
|
|
(
|
|
return False
|
|
)
|
|
|
|
--Process the valid selected items
|
|
for i=1 to selection.count do
|
|
(
|
|
local item = selection[i]
|
|
-- local lastItem = if (i == selection.count) then true else false
|
|
-- format "lastItem? %\n" lastItem
|
|
--check if the procmesh name already exists
|
|
local dupeName = for o in objects where ((tolower o.name) == (tolower(item.name + "_PROC_MESH"))) collect o
|
|
if (dupeName.count > 0) then
|
|
(
|
|
--local keepGoing = queryBox "There is already a ProcMesh for this mesh do you want to replace it?" title:"Duplicate ProcMesh"
|
|
if (keepGoing != #yesAll) then
|
|
(
|
|
keepGoing = RsQueryBoxAll "There is already a ProcMesh for this mesh do you want to replace it?" title:"Duplicate ProcMesh"
|
|
print keepGoing
|
|
if (keepGoing == #yes) or (keepGoing == #yesAll) then
|
|
(
|
|
print "#yes"
|
|
local theObj = getNodeByName (item.name + "_PROC_MESH")
|
|
delete theObj
|
|
)
|
|
else
|
|
(
|
|
print "NO"
|
|
continue
|
|
)
|
|
)
|
|
else
|
|
(
|
|
local theObj = getNodeByName (item.name + "_PROC_MESH")
|
|
delete theObj
|
|
)
|
|
|
|
)
|
|
|
|
--Dupe the selected mesh
|
|
local Cloned = #()
|
|
maxOps.cloneNodes item newNodes:&Cloned
|
|
local ProcMesh = Cloned[1]
|
|
ProcMesh.name = item.name + "_PROC_MESH"
|
|
|
|
--convert to editable mesh
|
|
ConvertToMesh ProcMesh
|
|
ConvertToPoly ProcMesh
|
|
|
|
--give it a new multmaterial
|
|
--ProcMesh.material = Multimaterial()
|
|
|
|
--Check if we should include ground tinting in the transfer
|
|
if( this.Painter.TransferGroundTint ) then
|
|
(
|
|
--Load the ground tint image
|
|
if not( this.GroundTintMapImage.Load() ) then
|
|
(
|
|
MessageBox @"Failed to load the image. Check your workspace is mapped and upto date with; //depot/gta5/assets/maps/procPaint/ProceduralTintMap.png"
|
|
return()
|
|
)
|
|
)
|
|
|
|
--Update our procedural source spatial hash set
|
|
this.UpdateProceduralSourceSpatialHashSet()
|
|
|
|
--Create our top progress window
|
|
--ProcMeshProgress = RSProgressWindow Title:"Transfering data to collision meshes..." StartStep:0 EndStep:1
|
|
--ProcMeshProgress.Start()
|
|
|
|
local CollisionMesh = VisualTargetList[1]
|
|
|
|
--Clear map channels
|
|
--ConvertToPoly CollisionMesh
|
|
RSPoly_ResetMapChannel ProcMesh this.CollisionGroundTintChannel [1,1,1]
|
|
RSPoly_ResetMapChannel ProcMesh this.CollisionScaleDensityChannel [1,1,1]
|
|
|
|
--Get the master collision material - the collision material which covers the whole container
|
|
--CollisionContainerMaterial = this.GetCollisionContainerMaterial CollisionMesh
|
|
CollisionContainerMaterial = Multimaterial numsubs:1
|
|
|
|
|
|
--Get face count for collision
|
|
FaceCount = GetNumFaces ProcMesh
|
|
|
|
--Stores all the information about how face matIDs will get remapped to new MultiMat
|
|
FaceMatIDRemapList = #()
|
|
|
|
--Create sub progress
|
|
FaceProgress = RSProgressWindow Title:"Transfering data to ProcMesh..." StartStep:0 EndStep:FaceCount
|
|
FaceProgress.Start()
|
|
|
|
|
|
--For each face of the procmesh mesh
|
|
for FaceIndex = 1 to FaceCount do
|
|
(
|
|
try
|
|
(
|
|
--Push progress update
|
|
FaceProgress.PostProgressStep()
|
|
|
|
--Get the collision face centre
|
|
FaceCenter = PolyOp_GetFaceCenter ProcMesh FaceIndex
|
|
|
|
--Resolve locality entry
|
|
FaceProceduralSourceSpatialEntry = this.ProceduralSourceSpatialHashSet.GetClosestEntry FaceCenter Threshold:0.4
|
|
|
|
--Target procedural level - start with nothing
|
|
ProceduralLevel = this.BlankProceduralLevel
|
|
|
|
--Check we actually got something and get the procedural level
|
|
if( FaceProceduralSourceSpatialEntry != Undefined ) then
|
|
(
|
|
--Get source level map value
|
|
LevelMapValue
|
|
if( ClassOf FaceProceduralSourceSpatialEntry.Value.Node == Editable_Mesh ) then
|
|
( LevelMapValue = RSMesh_GetFace_MapValue FaceProceduralSourceSpatialEntry.Value.Node FaceProceduralSourceSpatialEntry.Value.FaceIndex this.DataChannel )
|
|
else
|
|
( LevelMapValue = RSPoly_GetFace_MapValue FaceProceduralSourceSpatialEntry.Value.Node FaceProceduralSourceSpatialEntry.Value.FaceIndex this.DataChannel )
|
|
|
|
--Get the procedural level from the components of HandleMapValue.
|
|
ProceduralLevel = this.Painter.SetData.GetProceduralLevel LevelMapValue[1] LevelMapValue[2] LevelMapValue[3]
|
|
)
|
|
|
|
|
|
--If not then create a blank 'Default' RexBoundMtl
|
|
NewRexMtl = RexBoundMtl()
|
|
RexSetCollisionName NewRexMtl "DEFAULT"
|
|
|
|
--Set the procedural name to the correct type
|
|
if( ProceduralLevel == this.BlankProceduralLevel ) then
|
|
(
|
|
RexSetProceduralName NewRexMtl ""
|
|
)
|
|
else
|
|
(
|
|
RexSetProceduralName NewRexMtl ProceduralLevel.TargetTag
|
|
RexSetProcCullImmune NewRexMtl ProceduralLevel.ParentProcedural.CullImmune
|
|
)
|
|
|
|
--Resolve the material ID from the master collision material
|
|
NewMatID
|
|
for MatID in CollisionContainerMaterial.MaterialIDList while (NewMatID == undefined) do
|
|
(
|
|
if( RexAreMatsEqual CollisionContainerMaterial[MatID] NewRexMtl ) then
|
|
(
|
|
NewMatID = MatID
|
|
--exit()
|
|
)
|
|
)
|
|
|
|
|
|
--If we have reached this far and we still don't have a MatID then we'll have to add a new one
|
|
if( NewMatID == undefined ) then
|
|
(
|
|
NewMatID = MultiMat_AddNewMultiMaterialSlot CollisionContainerMaterial
|
|
NewRexMtl.Name = GetMaterialString NewRexMtl
|
|
CollisionContainerMaterial.Names[ NewMatID ] = NewRexMtl.Name
|
|
CollisionContainerMaterial[ NewMatID ] = NewRexMtl
|
|
)
|
|
|
|
--Store ID changes to be acted on after loop
|
|
if( FaceMatIDRemapList[ NewMatID ] == Undefined ) then
|
|
(
|
|
FaceMatIDRemapList[ NewMatID ] = #{ FaceIndex }
|
|
)
|
|
else
|
|
(
|
|
Append FaceMatIDRemapList[ NewMatID ] FaceIndex
|
|
)
|
|
|
|
--Scale density channel
|
|
ScaleDensityMapValue = [ ProceduralLevel.ScaleZ, ProceduralLevel.ScaleXYZ, ProceduralLevel.Density ]
|
|
RSPoly_SetFace_MapValue ProcMesh FaceIndex this.CollisionScaleDensityChannel ScaleDensityMapValue
|
|
|
|
--Ground tint channel
|
|
if( this.Painter.TransferGroundTint ) then
|
|
(
|
|
--Check to see if we should use the tint override channel
|
|
if( this.Painter.UseGroundTintOverride ) then
|
|
(
|
|
--Check we have the override channel
|
|
if ( PolyOp.GetMapSupport ProcMesh this.CollisionGroundTintOverrideChannel ) then
|
|
(
|
|
--If the color is anything other than white (off) then set it
|
|
GroundTintOverrideMapValue = RSPoly_GetFace_MapValue ProcMesh FaceIndex this.CollisionGroundTintOverrideChannel
|
|
if( GroundTintOverrideMapValue != [1,1,1] ) then
|
|
(
|
|
RSPoly_SetFace_MapValue ProcMesh FaceIndex this.CollisionGroundTintChannel GroundTintOverrideMapValue
|
|
continue
|
|
)
|
|
)
|
|
)
|
|
|
|
--Otherwise we'll use the color from our ground tint map image
|
|
FaceCentre = PolyOp_GetFaceCenter ProcMesh FaceIndex
|
|
GroundTintColor = this.GroundTintMapImage.GetPixel FaceCentre
|
|
if (GroundTintColor == undefined) then
|
|
(
|
|
GroundTintColor = color 128 128 128
|
|
)
|
|
GroundTintMapValue = [ GroundTintColor.R, GroundTintColor.G, GroundTintColor.B ] / 255.0
|
|
RSPoly_SetFace_MapValue ProcMesh FaceIndex this.CollisionGroundTintChannel GroundTintMapValue
|
|
)
|
|
|
|
)
|
|
catch
|
|
(
|
|
print "hit an exception"
|
|
print(getCurrentException())
|
|
print item
|
|
|
|
--End progress
|
|
FaceProgress.End()
|
|
)
|
|
)
|
|
|
|
--Run through each MatID setting target faces in batches
|
|
FaceMatIDRemapCount = FaceMatIDRemapList.Count
|
|
for MatID = 1 to FaceMatIDRemapCount do
|
|
(
|
|
TargetFaces = FaceMatIDRemapList[MatID]
|
|
--break()
|
|
if( TargetFaces != Undefined ) then
|
|
(
|
|
PolyOp_SetFaceMatID ProcMesh TargetFaces MatID
|
|
)
|
|
)
|
|
|
|
|
|
|
|
--End progress
|
|
FaceProgress.End()
|
|
|
|
--Apply master material (if it's not applied already)
|
|
ProcMesh.Material = CollisionContainerMaterial
|
|
--meditMaterials[3] = CollisionContainerMaterial
|
|
|
|
--Collapse dead structs (applies the color changes we have made during this process)
|
|
PolyOp_CollapseDeadStructs ProcMesh
|
|
|
|
--find and strip out faces that dont have procedural type assigned to them
|
|
local FacesWithProc = #()
|
|
RsGetProceduralFaces ProcMesh ProcMesh.material FacesWithProc
|
|
|
|
--Check that all the faces with proc is not the same as all the faces of the procmesh. if they are not then
|
|
--cull the faces without proc from the whole face set
|
|
if not ((ProcMesh.faces as BitArray).numberSet == (FacesWithProc as BitArray).numberSet) then
|
|
(
|
|
local CullFaces = (ProcMesh.faces as BitArray) - (FacesWithProc as BitArray)
|
|
if (CullFaces.numberSet == 0) then
|
|
(
|
|
print "no proc faces set"
|
|
delete ProcMesh
|
|
continue
|
|
)
|
|
|
|
polyop.deleteFaces ProcMesh CullFaces
|
|
)
|
|
|
|
|
|
--Collapse dead structs
|
|
PolyOp_CollapseDeadStructs ProcMesh
|
|
|
|
--check we have some faces left
|
|
if (ProcMesh.faces.count > 0) then
|
|
(
|
|
print "we got proc faces"
|
|
--Convert mesh back to collision
|
|
Mesh2Col ProcMesh
|
|
|
|
--Set a new stamp
|
|
this.SetProceduralStamp item
|
|
this.SetProceduralStamp ProcMesh
|
|
|
|
--Set the flag to 'Use Procedural Tint'
|
|
SetAttr ProcMesh this.ProcecduralTintAttributeIdx True
|
|
|
|
--Set the material collision flag
|
|
gRsCollTypes.setObjCollTypeFlags ProcMesh "Material"
|
|
|
|
/*
|
|
if( this.Painter.TransferGroundTint ) then
|
|
(
|
|
--Check the collisions to ensure they are under the 255 combination limit
|
|
this.PalletiseGroundTint CollisionTargetList
|
|
)
|
|
*/
|
|
--add the procmesh to its own layer
|
|
AddModelToProcMeshLayer ProcMesh
|
|
|
|
SetCollisionTargetProperty CollisionMesh False
|
|
ProcMesh.wirecolor = orange
|
|
)
|
|
else
|
|
(
|
|
print "no faces in the procmesh"
|
|
delete ProcMesh
|
|
|
|
--remove the object from the transfer list
|
|
--this.Painter.TransferArray
|
|
append CreatesEmptyProcMesh item
|
|
|
|
--remove it as a target
|
|
-- if lastItem then
|
|
-- (
|
|
-- this.TransferListRemoveCollision CollisionTargetList
|
|
-- )
|
|
)
|
|
)
|
|
|
|
--Update our transfer list
|
|
this.TransferListUpdate()
|
|
),
|
|
|
|
/*------------------------------------------------------------------------------
|
|
Imports data from the procedural map image
|
|
*/------------------------------------------------------------------------------
|
|
fn ImportData =
|
|
(
|
|
--Check selection is valid
|
|
if not( this.CheckNodesAreValid Selection ) then
|
|
(
|
|
return False
|
|
)
|
|
|
|
--Check user does want to do the operation
|
|
if not( QueryBox "This operation will import procedural data from the master map image. This will overwrite procedural data that exists all ready on the selected objects. Continue?") then
|
|
(
|
|
return()
|
|
)
|
|
|
|
--First we load the map image
|
|
if not( this.ProceduralMapImage.Load() ) then
|
|
(
|
|
MessageBox @"Failed to load the image. Check your workspace is mapped and upto date with; //depot/gta5/assets/maps/procPaint/ProceduralTypeMap.png"
|
|
return()
|
|
)
|
|
|
|
--Then check our selection
|
|
TargetArray = Selection as Array
|
|
|
|
--Create our top progress window
|
|
ImportMapImageDataProgress = RSProgressWindow Title:"Importing data from map image..." StartStep:0 EndStep:TargetArray.Count
|
|
ImportMapImageDataProgress.Start()
|
|
|
|
--Then we go through each object in the target array
|
|
for Target in TargetArray do
|
|
(
|
|
--Push progress update
|
|
ImportMapImageDataProgress.PostProgressStep()
|
|
|
|
--Check we have map support on the handle channel and wipe down to black
|
|
RSPoly_ResetMapChannel Target this.DataChannel [0,0,0]
|
|
|
|
--Get face count for the target
|
|
FaceCount = GetNumFaces Target
|
|
|
|
--Create sub progress
|
|
FaceProgress = ImportMapImageDataProgress.StartSubProgress 0 FaceCount SubTitle:Target.Name
|
|
FaceProgress.Start()
|
|
|
|
--For each face in the target we will get the major pixel and
|
|
--attempt to derive the procedural from this.
|
|
for FaceIndex = 1 to FaceCount do
|
|
(
|
|
--Push progress update
|
|
FaceProgress.PostProgressStep()
|
|
|
|
--Get face centre
|
|
FaceCentre = PolyOp_GetFaceCenter Target FaceIndex
|
|
|
|
--Get the major color
|
|
FaceColor = this.ProceduralMapImage.GetPixel FaceCentre --RSImage_GetMajorColor this.MapImage FacePointList
|
|
|
|
--Create a Point3 which has the values scaled so they fit in the 0.0 - 1.0
|
|
FaceMapValue = [ FaceColor.R, FaceColor.G, FaceColor.B ] / 255.0
|
|
|
|
--Set the target faces to the map value
|
|
RSPoly_SetFace_MapValue Target FaceIndex this.DataChannel FaceMapValue
|
|
)
|
|
|
|
--Collapse dead structs to push the changes through and garbage collect
|
|
PolyOp.CollapseDeadStructs Target
|
|
|
|
--Set time and data stamp
|
|
this.SetProceduralStamp Target
|
|
|
|
--End progress
|
|
FaceProgress.End()
|
|
)
|
|
|
|
--End progress
|
|
ImportMapImageDataProgress.End()
|
|
),
|
|
|
|
/*------------------------------------------------------------------------------
|
|
Exports data to the procedural map image
|
|
*/------------------------------------------------------------------------------
|
|
fn ExportData =
|
|
(
|
|
--First we load the map image
|
|
if not( this.ProceduralMapImage.Load() ) then
|
|
(
|
|
MessageBox @"Failed to load the image. Check your workspace is mapped and upto date with; //depot/gta5/assets/maps/procPaint/ProceduralTypeMap.png"
|
|
return()
|
|
)
|
|
|
|
--Then check our selection
|
|
TargetArray = this.GetProceduralSourceList()
|
|
|
|
--Create our top progress window
|
|
ExportMapImageDataProgress = RSProgressWindow Title:"Exporting procedural data to map image..." StartStep:0 EndStep:TargetArray.Count
|
|
ExportMapImageDataProgress.Start()
|
|
|
|
--Then we go through each object in the target array
|
|
for Target in TargetArray do
|
|
(
|
|
--Push progress update
|
|
ExportMapImageDataProgress.PostProgressStep()
|
|
|
|
--Get face count for the target
|
|
FaceCount = GetNumFaces Target
|
|
|
|
--Create sub progress
|
|
FaceProgress = ExportMapImageDataProgress.StartSubProgress 0 FaceCount SubTitle:Target.Name
|
|
FaceProgress.Start()
|
|
|
|
--For each face in the target we will get the procedural level
|
|
for FaceIndex = 1 to FaceCount do
|
|
(
|
|
--ToDo Fix the exporting of data. Currently it doesn't work properly.
|
|
--Max seems to add noise to the image effectively breaking the whole system.
|
|
|
|
--Push progress update
|
|
FaceProgress.PostProgressStep()
|
|
|
|
--Get all the face verts and map value
|
|
FaceVertexPositionList
|
|
LevelMapValue
|
|
if( ClassOf Target == Editable_Mesh ) then
|
|
(
|
|
FaceVertexList = GetFace Target FaceIndex
|
|
FaceVertexPositionList = for FaceVertex in FaceVertexList collect ( MeshOp.GetVert Target FaceVertex )
|
|
LevelMapValue = RSMesh_GetFace_MapValue Target FaceIndex this.DataChannel
|
|
)
|
|
if( ClassOf Target == Editable_Poly or ClassOf Target == PolyMeshObject ) then
|
|
(
|
|
FaceVertexList = PolyOp.GetFaceVerts Target FaceIndex
|
|
FaceVertexPositionList = for FaceVertex in FaceVertexList collect ( PolyOp.GetVert Target FaceVertex )
|
|
LevelMapValue = RSPoly_GetFace_MapValue Target FaceIndex this.DataChannel
|
|
)
|
|
|
|
--Get the procedural level from the components of LevelMapValue.
|
|
ProceduralLevel = this.Painter.SetData.GetProceduralLevel LevelMapValue[1] LevelMapValue[2] LevelMapValue[3]
|
|
|
|
--Setup our map values from the procedural level
|
|
LevelColor = Black
|
|
if( ProceduralLevel != this.BlankProceduralLevel ) then
|
|
(
|
|
LevelColor = Color ProceduralLevel.Color.R ProceduralLevel.Color.G ProceduralLevel.Color.B
|
|
)
|
|
|
|
--Set the color
|
|
this.ProceduralMapImage.SetAreaPixels FaceVertexPositionList LevelColor
|
|
)
|
|
|
|
--End progress
|
|
FaceProgress.End()
|
|
)
|
|
|
|
--End progress
|
|
ExportMapImageDataProgress.End()
|
|
|
|
--Save the map image
|
|
this.ProceduralMapImage.Save()
|
|
|
|
--Dispose of the map image resources
|
|
this.ProceduralMapImage.Dispose()
|
|
),
|
|
|
|
/*--------------------------------------------------
|
|
Clips the values of the input MapValue so that it sits correctly in the 0-1 range
|
|
*/--------------------------------------------------
|
|
fn NormaliseMapValue InputMapValue =
|
|
(
|
|
for MapValueIndex = 1 to 3 do
|
|
(
|
|
CurrentValue = InputMapValue[MapValueIndex]
|
|
|
|
if( CurrentValue == 0 or CurrentValue == 1 ) then continue
|
|
if( CurrentValue < 0 ) then
|
|
(
|
|
OffsetValue = Ceil ( Abs( CurrentValue ) )
|
|
InputMapValue[MapValueIndex] += OffsetValue
|
|
)
|
|
else
|
|
(
|
|
OffsetValue = Floor CurrentValue
|
|
InputMapValue[MapValueIndex] -= OffsetValue
|
|
)
|
|
)
|
|
|
|
return InputMapValue
|
|
),
|
|
|
|
--The maximum limit on collision combinations
|
|
CollisionCombinationLimit = 100,
|
|
/*--------------------------------------------------
|
|
Creates a collision set for the input mesh. Note that the mesh must be converted to a editable mesh before
|
|
*/--------------------------------------------------
|
|
fn GetCollisionCombinationSet InputMesh ParentProgress:Undefined =
|
|
(
|
|
--Get face count for collision
|
|
FaceCount = GetNumFaces InputMesh
|
|
|
|
--Check if we have information in the various channels
|
|
MeshHasScaleDensity = MeshOp_GetMapSupport InputMesh this.CollisionScaleDensityChannel
|
|
MeshHasGroundTint = MeshOp_GetMapSupport InputMesh this.CollisionGroundTintChannel
|
|
|
|
--Start our collision combination set (tracks all our collision combinations)
|
|
CollisionCombinationSet = DotNetObject "ProceduralSystem.CollisionCombinationSet"
|
|
|
|
--Start a sub progress
|
|
FaceIndexProgress
|
|
if( ParentProgress == Undefined )then
|
|
(
|
|
FaceIndexProgress = RSProgressWindow Title:"Palletising collision meshes (255 limit)..." StartStep:0 EndStep:FaceCount
|
|
)
|
|
else
|
|
(
|
|
FaceIndexProgress = ParentProgress.StartSubProgress 0 FaceCount SubTitle:InputMesh.Name
|
|
)
|
|
FaceIndexProgress.Start()
|
|
|
|
--For each face of the collision mesh
|
|
for FaceIndex = 1 to FaceCount do
|
|
(
|
|
--Push progress update
|
|
FaceIndexProgress.PostProgressStep()
|
|
|
|
--Get face material
|
|
FaceMatID = MeshOp_GetFaceMatID InputMesh FaceIndex
|
|
FaceRexMat = InputMesh.Material[FaceMatID]
|
|
|
|
--Get string representation of the RexBoundMtl
|
|
FaceRexMatString = ""
|
|
if( ClassOf FaceRexMat == RexBoundMtl ) then
|
|
(
|
|
FaceRexMatString = GetMaterialString FaceRexMat
|
|
)
|
|
|
|
--Figure out the various different levels applied for Scale and Density
|
|
ScaleXYZLevel = 0
|
|
ScaleZLevel = 0
|
|
DensityLevel = 0
|
|
if( MeshHasScaleDensity ) then
|
|
(
|
|
ScaleDensityMapValue = RSMesh_GetFace_MapValue InputMesh FaceIndex 12
|
|
ScaleDensityMapValue = NormaliseMapValue ScaleDensityMapValue
|
|
|
|
ScaleZLevel = RoundToIncrement( ScaleDensityMapValue[1] * 3 )
|
|
ScaleXYZLevel = RoundToIncrement( ScaleDensityMapValue[2] * 15 )
|
|
DensityLevel = RoundToIncrement( ScaleDensityMapValue[3] * 3 )
|
|
)
|
|
|
|
--Get current ground tint color
|
|
GroundTintR = 0
|
|
GroundTintG = 0
|
|
GroundTintB = 0
|
|
if( MeshHasGroundTint ) then
|
|
(
|
|
GroundTintMapValue = RSMesh_GetFace_MapValue InputMesh FaceIndex 11
|
|
GroundTintMapValue = this.NormaliseMapValue GroundTintMapValue
|
|
|
|
GroundTintR = RoundToIncrement ( 255 * GroundTintMapValue[1] )
|
|
GroundTintG = RoundToIncrement ( 255 * GroundTintMapValue[2] )
|
|
GroundTintB = RoundToIncrement ( 255 * GroundTintMapValue[3] )
|
|
|
|
GroundTintR = DotNetObject "System.Byte" GroundTintR
|
|
GroundTintG = DotNetObject "System.Byte" GroundTintG
|
|
GroundTintB = DotNetObject "System.Byte" GroundTintB
|
|
)
|
|
|
|
--Create ground tint color
|
|
FaceGroundTint = DotNetObject "ProceduralSystem.Color" GroundTintR GroundTintG GroundTintB
|
|
|
|
--Create a combined string from all the information collected
|
|
--FaceCollisionCombinationString = ToUpper( FaceRexMatString + " SCALEZ:" + (ScaleZLevel as String) + " SCALEXYZ:" + (ScaleXYZLevel as String) + " DENSITY:" + (DensityLevel as String) + " TINT_R:" + ( GroundTintR as String) + " TINT_G:" + ( GroundTintG as String) + " TINT_B:" + ( GroundTintB as String) )
|
|
FaceCollisionCombinationString = ToUpper( FaceRexMatString + " SCALEZ:" + (ScaleZLevel as String) + " SCALEXYZ:" + (ScaleXYZLevel as String) + " DENSITY:" + (DensityLevel as String) )
|
|
|
|
--Create hash from the string
|
|
FaceCollisionCombinationHash = GetHashValue FaceCollisionCombinationString 1
|
|
|
|
--Add the face to the collision combination set
|
|
CollisionCombinationSet.AddFace FaceCollisionCombinationHash FaceIndex FaceGroundTint
|
|
)
|
|
|
|
--End progress
|
|
FaceIndexProgress.End()
|
|
|
|
--Return our CollisionCombinationSet
|
|
return CollisionCombinationSet
|
|
),
|
|
|
|
/*--------------------------------------------------
|
|
Palletise the ground tint channel for each of the passed collision
|
|
*/--------------------------------------------------
|
|
fn PalletiseGroundTint InputCollisionMeshList =
|
|
(
|
|
--Create our top progress window
|
|
CollisionMeshProgress = RSProgressWindow Title:"Palletising collision meshes (255 limit)..." StartStep:0 EndStep:InputCollisionMeshList.Count
|
|
CollisionMeshProgress.Start()
|
|
|
|
for CollisionMesh in InputCollisionMeshList do
|
|
(
|
|
--Push progress update
|
|
CollisionMeshProgress.PostProgressStep()
|
|
|
|
--Convert the collision mesh to mesh
|
|
Col2Mesh CollisionMesh
|
|
|
|
--Create our collision combination set based on the materials on the collision
|
|
CollisionCombinationSet = this.GetCollisionCombinationSet CollisionMesh ParentProgress:CollisionMeshProgress
|
|
if( CollisionCombinationSet.BaseCombinationCount() < this.CollisionCombinationLimit ) then
|
|
(
|
|
--Reduce the ground tint channel until we are under the combination limit
|
|
CurrentThreshold = 2
|
|
while( CollisionCombinationSet.FullCombinationCount() > this.CollisionCombinationLimit ) do
|
|
(
|
|
CollisionCombinationSet.CondenseGroundTints( CurrentThreshold )
|
|
CurrentThreshold += 2
|
|
)
|
|
|
|
--Give all the faces unique map space
|
|
MeshOp_ApplyUVWMap CollisionMesh #Face Channel:this.CollisionGroundTintChannel
|
|
|
|
for FaceInfo in CollisionCombinationSet.FaceInfoArray do
|
|
(
|
|
GroundTintMapValue = [FaceInfo.FaceGroundTint.ScR, FaceInfo.FaceGroundTint.ScG, FaceInfo.FaceGroundTint.ScB]
|
|
RSMesh_SetFace_MapValue CollisionMesh FaceInfo.FaceIndex this.CollisionGroundTintChannel GroundTintMapValue
|
|
)
|
|
)
|
|
else
|
|
(
|
|
WarningMessage = Format "Can't fix this collision mesh [%] by palletising the ground tint channel as there are already too many base collision material combinations. This mesh will need to be split or the number of procedurals/surface types reduced in order to get it to export correctly." CollisionMesh.Name
|
|
gRSULog.LogWarning WarningMessage Context:"ProceduralPainter"
|
|
)
|
|
|
|
--Convert mesh back to collision
|
|
Mesh2Col CollisionMesh
|
|
)
|
|
|
|
--End progress
|
|
CollisionMeshProgress.End()
|
|
),
|
|
|
|
--The paths to the relevant metadata and UI markup for the tool
|
|
UIMarkupFilePath = RsMakeBackSlashes( RsConfigGetWildWestDir() + "/script/3dsMax/UI/ProceduralPainter.xaml" ),
|
|
SetDataFilePath = RsMakeBackSlashes( gRsConfig.Project.DefaultBranch.Assets + "/maps/procPaint/ProceduralSets.xml" ),
|
|
MetadataFilePath = RsMakeBackSlashes( gRsConfig.Project.DefaultBranch.Common + "/data/materials/procedural.meta" ),
|
|
ThumbnailDirectoryPath = RsMakeBackSlashes( gRsConfig.Project.DefaultBranch.Assets + "/maps/procPaint/Thumbnails/..." ),
|
|
|
|
/*------------------------------------------------------------------------------
|
|
Intializes the tool
|
|
*/------------------------------------------------------------------------------
|
|
on Create do
|
|
(
|
|
--Sync to the latest on the relevant files
|
|
if( gRsPerforce.connect() ) then
|
|
(
|
|
RSPushPrompt "Syncing assets..."
|
|
SyncSuccess = gRsPerforce.Sync #( this.SetDataFilePath,
|
|
this.MetadataFilePath,
|
|
this.ThumbnailDirectoryPath,
|
|
this.GroundTintMapImage.ImageFilePath,
|
|
this.ProceduralMapImage.ImageFilePath )
|
|
|
|
if not ( SyncSuccess ) then ( MessageBox "Unable to sync correctly to some of the required assets. You may have them set to be writable locally and/or there maybe problems with your P4 setup. The tool may not function correctly without the latest on those assets. Continue at your own risk..." )
|
|
RSPopPrompt()
|
|
)
|
|
|
|
--Create an instance of the 'Painter' class passing in the relevant file paths
|
|
this.Painter = DotNetObject "ProceduralSystem.Painter" SetDataFilePath MetadataFilePath
|
|
|
|
--Setup our tool window and open it
|
|
this.ToolWindow = RSToolWindow Name:"Procedural Painter" UISource:UIMarkupFilePath
|
|
|
|
--Alias our blank procedural level - nothing more than a shortcut in script
|
|
this.BlankProceduralLevel = this.Painter.SetData.BlankProceduralLevel
|
|
this.UpdateRenderSettings this.BlankProceduralLevel
|
|
this.UpdateDisplaySettings this.BlankProceduralLevel
|
|
|
|
--Bind our tool window content to the painter instance
|
|
--This will link them together.
|
|
this.Painter.BindElement this.ToolWindow.Content
|
|
|
|
--Updates our transfer list
|
|
this.TransferListUpdate()
|
|
|
|
--Make sure we have 1GB of heap memory (needed for transfering)
|
|
if( HeapSize < 1048576000 ) then ( HeapSize = 1048576000 )
|
|
|
|
--Open the window
|
|
this.ToolWindow.Open()
|
|
)
|
|
)
|
|
ProceduralPainter = ProceduralPainter()
|
|
|
|
/*------------------------------------------------------------------------------
|
|
EVENTS
|
|
/*------------------------------------------------------------------------------
|
|
Action on display mode changed.
|
|
*/------------------------------------------------------------------------------
|
|
fn ProceduralPainter_OnDisplayModeChanged =
|
|
(
|
|
print "Updating overall display settings"
|
|
ProceduralPainter.UpdateAllDisplaySettings()
|
|
)
|
|
DotNet.AddEventHandler ProceduralPainter.Painter "DisplayModeChanged" ProceduralPainter_OnDisplayModeChanged
|
|
|
|
/*------------------------------------------------------------------------------
|
|
Action on display mode changed.
|
|
*/------------------------------------------------------------------------------
|
|
fn ProceduralPainter_OnRenderModeChanged =
|
|
(
|
|
print "Updating overall render settings"
|
|
ProceduralPainter.UpdateAllRenderSettings()
|
|
)
|
|
DotNet.AddEventHandler ProceduralPainter.Painter "RenderModeChanged" ProceduralPainter_OnRenderModeChanged
|
|
|
|
/*------------------------------------------------------------------------------
|
|
Action when user requests to apply procedural level to selection
|
|
*/------------------------------------------------------------------------------
|
|
fn ProceduralPainter_OnRequestedApplyLevelToSelection s e =
|
|
(
|
|
print "Applying to selection"
|
|
ProceduralPainter.ApplyProceduralLevel #Selection e.TargetProceduralLevel
|
|
)
|
|
DotNet.AddEventHandler ProceduralPainter.Painter "RequestedApplyLevelToSelection" ProceduralPainter_OnRequestedApplyLevelToSelection
|
|
|
|
/*------------------------------------------------------------------------------
|
|
Action when user requests to select polys that use a given procedural level
|
|
*/------------------------------------------------------------------------------
|
|
fn ProceduralPainter_OnRequestedSelectFacesUsedByLevel s e =
|
|
(
|
|
print "Selecting procedural level"
|
|
ProceduralPainter.SelectProceduralLevel e.TargetProceduralLevel
|
|
)
|
|
DotNet.AddEventHandler ProceduralPainter.Painter "RequestedSelectFacesUsedByLevel" ProceduralPainter_OnRequestedSelectFacesUsedByLevel
|
|
|
|
/*------------------------------------------------------------------------------
|
|
Action when user requests to start editing
|
|
*/------------------------------------------------------------------------------
|
|
fn ProceduralPainter_OnRequestedStartEdit s e =
|
|
(
|
|
print "Starting edit"
|
|
ProceduralPainter.Painter.CurrentlyEditing = ProceduralPainter.StartEditing()
|
|
)
|
|
DotNet.AddEventHandler ProceduralPainter.Painter "RequestedStartEdit" ProceduralPainter_OnRequestedStartEdit
|
|
|
|
/*------------------------------------------------------------------------------
|
|
Action when user requests to stop editing
|
|
*/------------------------------------------------------------------------------
|
|
fn ProceduralPainter_OnRequestedStopEdit s e =
|
|
(
|
|
print "Stoping edit"
|
|
ProceduralPainter.StopEditing()
|
|
)
|
|
DotNet.AddEventHandler ProceduralPainter.Painter "RequestedStopEdit" ProceduralPainter_OnRequestedStopEdit
|
|
|
|
/*------------------------------------------------------------------------------
|
|
Action when user requests to commit unsaved data
|
|
*/------------------------------------------------------------------------------
|
|
fn ProceduralPainter_OnRequestedCommitData s e =
|
|
(
|
|
print "Commiting data"
|
|
DisableSceneRedraw()
|
|
with undo off
|
|
(
|
|
ProceduralPainter.CommitData()
|
|
)
|
|
EnableSceneRedraw()
|
|
)
|
|
DotNet.AddEventHandler ProceduralPainter.Painter "RequestedCommitData" ProceduralPainter_OnRequestedCommitData
|
|
|
|
/*------------------------------------------------------------------------------
|
|
Action when user requests to select polys that use a given procedural
|
|
*/------------------------------------------------------------------------------
|
|
fn ProceduralPainter_OnRequestedSelectFacesUsedByProcedural s e =
|
|
(
|
|
print "Selecting procedural"
|
|
ProceduralPainter.SelectProcedural e.TargetProcedural
|
|
)
|
|
DotNet.AddEventHandler ProceduralPainter.Painter "RequestedSelectFacesUsedByProcedural" ProceduralPainter_OnRequestedSelectFacesUsedByProcedural
|
|
|
|
/*------------------------------------------------------------------------------
|
|
Action when user requests to auto blend the levels across the faces selected
|
|
*/------------------------------------------------------------------------------
|
|
fn ProceduralPainter_OnRequestedAutoBlendFaceProceduralLevels s e =
|
|
(
|
|
print "Selecting procedural"
|
|
ProceduralPainter.AutoBlendProceduralLevels()
|
|
)
|
|
DotNet.AddEventHandler ProceduralPainter.Painter "RequestedAutoBlendFaceProceduralLevels" ProceduralPainter_OnRequestedAutoBlendFaceProceduralLevels
|
|
|
|
/*------------------------------------------------------------------------------
|
|
Action when user requests to process spacing on the selected faces
|
|
*/------------------------------------------------------------------------------
|
|
fn ProceduralPainter_OnRequestedProcessFaceSpacing s e =
|
|
(
|
|
print "Processing spacing on the selected faces."
|
|
ProceduralPainter.ProcessFaceSpacing()
|
|
)
|
|
DotNet.AddEventHandler ProceduralPainter.Painter "RequestedProcessFaceSpacing" ProceduralPainter_OnRequestedProcessFaceSpacing
|
|
|
|
/*------------------------------------------------------------------------------
|
|
Action when user requests to clear polys that use a given procedural
|
|
*/------------------------------------------------------------------------------
|
|
fn ProceduralPainter_OnRequestedClearProcedural s e =
|
|
(
|
|
print "Clearing procedural"
|
|
if( QueryBox "This is going to clear all faces using this procedural (across all levels). Are you sure you want to do this?" ) then
|
|
(
|
|
ProceduralPainter.RemoveProcedural e.TargetProcedural
|
|
)
|
|
)
|
|
DotNet.AddEventHandler ProceduralPainter.Painter "RequestedClearProcedural" ProceduralPainter_OnRequestedClearProcedural
|
|
|
|
/*------------------------------------------------------------------------------
|
|
Action when user requests to import data from previous procedural painter tool
|
|
*/------------------------------------------------------------------------------
|
|
fn ProceduralPainter_OnRequestedImportData s e =
|
|
(
|
|
print "Importing data from master map image"
|
|
with undo off
|
|
(
|
|
ProceduralPainter.ImportData()
|
|
)
|
|
)
|
|
DotNet.AddEventHandler ProceduralPainter.Painter "RequestedImportData" ProceduralPainter_OnRequestedImportData
|
|
|
|
/*------------------------------------------------------------------------------
|
|
Action when user requests to import data from previous procedural painter tool
|
|
*/------------------------------------------------------------------------------
|
|
fn ProceduralPainter_OnRequestedExportData s e =
|
|
(
|
|
print "Exporting data to master map image"
|
|
ProceduralPainter.ExportData()
|
|
)
|
|
DotNet.AddEventHandler ProceduralPainter.Painter "RequestedExportData" ProceduralPainter_OnRequestedExportData
|
|
|
|
/*------------------------------------------------------------------------------
|
|
Action when user requests to transfer data across to the selected collision objects
|
|
*/------------------------------------------------------------------------------
|
|
/*
|
|
fn ProceduralPainter_OnRequestedTransferData s e =
|
|
(
|
|
print "Transfering data"
|
|
DisableSceneRedraw()
|
|
with undo off
|
|
(
|
|
ProceduralPainter.TransferData()
|
|
)
|
|
EnableSceneRedraw()
|
|
)
|
|
DotNet.AddEventHandler ProceduralPainter.Painter "RequestedTransferData" ProceduralPainter_OnRequestedTransferData
|
|
*/
|
|
/*------------------------------------------------------------------------------
|
|
Action when user requests to transfer data across to new procmesh object
|
|
*/------------------------------------------------------------------------------
|
|
fn ProceduralPainter_OnRequestedTransferDataProcMesh s e =
|
|
(
|
|
print "Transfering data"
|
|
try
|
|
(
|
|
DisableSceneRedraw()
|
|
with undo off
|
|
(
|
|
ProceduralPainter.TransferDataToProcMesh()
|
|
)
|
|
EnableSceneRedraw()
|
|
)
|
|
catch
|
|
(
|
|
EnableSceneRedraw()
|
|
)
|
|
)
|
|
DotNet.AddEventHandler ProceduralPainter.Painter "RequestedTransferDataProcMesh" ProceduralPainter_OnRequestedTransferDataProcMesh
|
|
|
|
|
|
/*------------------------------------------------------------------------------
|
|
Action when user requests to live update the selected faces
|
|
*/------------------------------------------------------------------------------
|
|
fn ProceduralPainter_OnRequestedLiveFaceUpdate s e =
|
|
(
|
|
print "Live updating faces"
|
|
ProceduralPainter.LiveUpdateFaces()
|
|
)
|
|
DotNet.AddEventHandler ProceduralPainter.Painter "RequestedLiveFaceUpdate" ProceduralPainter_OnRequestedLiveFaceUpdate
|
|
|
|
/*------------------------------------------------------------------------------
|
|
Action when user requests to add the selected collision mesh to the transfer list
|
|
*/------------------------------------------------------------------------------
|
|
fn ProceduralPainter_OnRequestedAddCollision s e =
|
|
(
|
|
print "Adding collision meshes"
|
|
ProceduralPainter.TransferListAddCollision (Selection as Array)
|
|
)
|
|
DotNet.AddEventHandler ProceduralPainter.Painter "RequestedAddCollision" ProceduralPainter_OnRequestedAddCollision
|
|
|
|
/*------------------------------------------------------------------------------
|
|
Action when user requests to remove the selected collision mesh from the transfer list
|
|
*/------------------------------------------------------------------------------
|
|
fn ProceduralPainter_OnRequestedRemoveCollision s e =
|
|
(
|
|
print "Removing collision meshes"
|
|
ProceduralPainter.TransferListRemoveCollision (Selection as Array)
|
|
|
|
)
|
|
DotNet.AddEventHandler ProceduralPainter.Painter "RequestedRemoveCollision" ProceduralPainter_OnRequestedRemoveCollision
|
|
|
|
/*------------------------------------------------------------------------------
|
|
Action when user requests to select a mesh from the transfer list
|
|
*/------------------------------------------------------------------------------
|
|
|
|
fn ProceduralPainter_FocusSelectListItemEvent s e =
|
|
(
|
|
print "Selecting list mesh"
|
|
|
|
clearSelection()
|
|
local newSelection = #()
|
|
for NodeData in ProceduralPainter.Painter.TransferArray do
|
|
(
|
|
if NodeData.IsSelected then
|
|
(
|
|
--print "isSelected"
|
|
append newSelection (MaxOps.GetNodeByHandle NodeData.NodeHandle)
|
|
)
|
|
)
|
|
|
|
if newSelection.count > 0 then
|
|
(
|
|
select newSelection
|
|
max zoomext sel all
|
|
)
|
|
)
|
|
DotNet.AddEventHandler ProceduralPainter.Painter "RequestedFocusSelectedVisualTargets" ProceduralPainter_FocusSelectListItemEvent
|
|
|
|
/*------------------------------------------------------------------------------
|
|
Action when user requests to select all collision mesh from the transfer list
|
|
*/------------------------------------------------------------------------------
|
|
fn ProceduralPainter_OnRequestedSelectVisualTargets s e =
|
|
(
|
|
print "Selecting visual meshes"
|
|
ProceduralPainter.TransferListSelectAllCollision()
|
|
)
|
|
DotNet.AddEventHandler ProceduralPainter.Painter "RequestedSelectVisualTargets" ProceduralPainter_OnRequestedSelectVisualTargets
|
|
|
|
/*------------------------------------------------------------------------------
|
|
Action when user requests to select none collision mesh from the transfer list
|
|
*/------------------------------------------------------------------------------
|
|
fn ProceduralPainter_OnRequestedSelectNoneVisualTargets s e =
|
|
(
|
|
print "Unselecting visual meshes"
|
|
ProceduralPainter.TransferListSelectNoneCollision()
|
|
)
|
|
DotNet.AddEventHandler ProceduralPainter.Painter "RequestedSelectNoneVisualTargets" ProceduralPainter_OnRequestedSelectNoneVisualTargets
|
|
|
|
/*------------------------------------------------------------------------------
|
|
Action when user requests to update the transfer list
|
|
*/------------------------------------------------------------------------------
|
|
fn ProceduralPainter_OnRequestedUpdateTransferList s e =
|
|
(
|
|
print "Updating transfer list"
|
|
ProceduralPainter.TransferListUpdate()
|
|
)
|
|
DotNet.AddEventHandler ProceduralPainter.Painter "RequestedUpdateTransferList" ProceduralPainter_OnRequestedUpdateTransferList
|
|
|
|
/*------------------------------------------------------------------------------
|
|
Action when tool requests to start visually highlighting a given procedural level
|
|
*/------------------------------------------------------------------------------
|
|
fn ProceduralPainter_OnRequestedStartHighlightProceduralLevel s e =
|
|
(
|
|
print "Starting highlighting of procedural."
|
|
)
|
|
DotNet.AddEventHandler ProceduralPainter.Painter "RequestedStartHighlightProceduralLevel" ProceduralPainter_OnRequestedStartHighlightProceduralLevel
|
|
|
|
/*------------------------------------------------------------------------------
|
|
Action when tool requests to stop visually highlighting a given procedural level
|
|
*/------------------------------------------------------------------------------
|
|
fn ProceduralPainter_OnRequestedStopHighlightProceduralLevel s e =
|
|
(
|
|
print "Stoping highlighting of procedural."
|
|
)
|
|
DotNet.AddEventHandler ProceduralPainter.Painter "RequestedStopHighlightProceduralLevel" ProceduralPainter_OnRequestedStopHighlightProceduralLevel
|
|
|
|
/*------------------------------------------------------------------------------
|
|
Action when tool posts a change to the camera sync state
|
|
*/------------------------------------------------------------------------------
|
|
fn ProceduralPainter_OnCameraSyncStateAltered s e =
|
|
(
|
|
print "Camera sync state altered."
|
|
|
|
if( ProceduralPainter.Painter.CameraSyncState == On ) then
|
|
(
|
|
ProceduralPainter.LiveSyncCameraOn()
|
|
)
|
|
else
|
|
(
|
|
ProceduralPainter.LiveSyncCameraOff()
|
|
)
|
|
)
|
|
DotNet.AddEventHandler ProceduralPainter.Painter "CameraSyncStateAltered" ProceduralPainter_OnCameraSyncStateAltered
|
|
|
|
/*------------------------------------------------------------------------------
|
|
Action when tool request to import live data from game
|
|
*/------------------------------------------------------------------------------
|
|
fn ProceduralPainter_OnRequestedImportLiveData s e =
|
|
(
|
|
print "Requested import of live data."
|
|
|
|
ProceduralPainter.LiveImport()
|
|
)
|
|
DotNet.AddEventHandler ProceduralPainter.Painter "RequestedImportLiveData" ProceduralPainter_OnRequestedImportLiveData
|
|
|
|
/*------------------------------------------------------------------------------
|
|
Action when the user requests the tool to be closed down
|
|
*/------------------------------------------------------------------------------
|
|
fn ProceduralPainter_OnFormClosing s e =
|
|
(
|
|
print "Closing down"
|
|
|
|
ProceduralPainter.StopEditing()
|
|
|
|
if( ProceduralPainter.Painter.CurrentlyEditing ) then
|
|
(
|
|
--If we are still editing then cancel the close down.
|
|
e.Cancel = true
|
|
)
|
|
)
|
|
DotNet.AddEventHandler ProceduralPainter.ToolWindow.Form "FormClosing" ProceduralPainter_OnFormClosing
|
|
|