899 lines
28 KiB
Plaintext
Executable File
899 lines
28 KiB
Plaintext
Executable File
Filein (RsConfigGetWildWestDir() + "script/3dsMax/_config_files/Wildwest_header.ms")
|
|
FileIn (RsConfigGetWildWestDir() + "script/3dsMax/_common_functions/FN_RSTA_userSettings.ms")
|
|
FileIn (RsConfigGetWildWestDir() + "script/3dsMax/_common_functions/FN_RSTA_xml.ms")
|
|
Filein (RsConfigGetWildWestDir() + "script/3dsMax/_common_functions/FN_RSTA_rageMat.ms")
|
|
Filein (RsConfigGetWildWestDir() + "script/3dsMax/_common_functions/FN_RSTA_UV.ms")
|
|
|
|
if (RSG_Struct != undefined) do RSG_Struct.dispose()
|
|
struct RSG_Struct
|
|
(
|
|
-- LOCALS ------------------------------------------------
|
|
MainWindow,
|
|
vm,
|
|
Settings = rsta_userSettings app:"RSG_tutorial",
|
|
BaseObject,
|
|
OriginalObject,
|
|
FeatureFile,
|
|
MeshObjs,
|
|
LayerProp,
|
|
m_SplineDetailObj,
|
|
m_SweepSpline,
|
|
m_RelativeXmlPath = @"wildwest/etc/config/maps/DecalRoadPlacerList.xml",
|
|
|
|
-- FUNCTIONS ---------------------------------------------
|
|
------------------------------------------------------------------------------------------------------
|
|
--Unhides the original object and deletes our copy of it
|
|
------------------------------------------------------------------------------------------------------
|
|
fn UnsetTargetSurface =
|
|
(
|
|
try(unhide OriginalObject)catch()
|
|
try(delete BaseObject)catch()
|
|
),
|
|
|
|
------------------------------------------------------------------------------------------------------
|
|
--Removes layer and all objects in it (this layer contained all the decal objects)
|
|
------------------------------------------------------------------------------------------------------
|
|
fn CleanupScene =
|
|
(
|
|
UnsetTargetSurface()
|
|
|
|
if (LayerProp != undefined AND not isDeleted LayerProp) do
|
|
(
|
|
local layerName = LayerProp.name
|
|
|
|
LayerProp.nodes &thenodes
|
|
|
|
delete thenodes
|
|
LayerManager.deleteLayerByName layerName
|
|
)
|
|
),
|
|
|
|
fn dispose =
|
|
(
|
|
if (MainWindow != undefined) do
|
|
(
|
|
CleanupScene()
|
|
|
|
-- WINDOW POS
|
|
settings.wpf_windowPos mainWindow #set
|
|
-- CLOSE AND DISPOSE THE WINDOW
|
|
MainWindow.Close()
|
|
MainWindow = undefined
|
|
)
|
|
execute ("RSG_Struct = undefined")
|
|
),
|
|
|
|
------------------------------------------------------------------------------------------------------
|
|
--- This function merges the max file
|
|
------------------------------------------------------------------------------------------------------
|
|
fn MergeFile =
|
|
(
|
|
firstObj = (objects.count)+1
|
|
|
|
--Create new layer to put all this stuff in.
|
|
LayerProp = LayerManager.newLayer()
|
|
LayerProp.on = false
|
|
|
|
--Load xml
|
|
local xmlPath = RsConfigGetToolsDir() + m_RelativeXmlPath
|
|
xmlPath = rsMakeSafeSlashes xmlPath
|
|
|
|
--Load XML file
|
|
vm.xmlPath = xmlPath
|
|
|
|
--Get all preview images and sync them
|
|
local aPreviewImages = vm.PreviewImages
|
|
gRsPerforce.sync(aPreviewImages)
|
|
|
|
--Get all names
|
|
local objectNames = vm.ObjectNames
|
|
|
|
-- --Loop over all objects and check their name
|
|
for o in geometry do
|
|
(
|
|
for mergedObjectName in objectNames do
|
|
(
|
|
if (o.Name == mergedObjectName)do
|
|
(
|
|
local sNewUniqueName = uniquename o.Name
|
|
o.Name = sNewUniqueName
|
|
)
|
|
)
|
|
)
|
|
|
|
--Merge file
|
|
mergeMAXFile FeatureFile #noRedraw #useSceneMtlDups #neverReparent --#AutoRenameDups we don't want autoRename because we check for names in the xml
|
|
|
|
--Find merged objects
|
|
if objects.count >= firstObj do
|
|
(
|
|
lastObj = objects.count
|
|
mergedObjs = for objI = firstObj to lastObj collect (objects[objI])
|
|
)
|
|
|
|
--Somehow cacelled the merge
|
|
if (mergedObjs != undefined) then
|
|
(
|
|
for mergedObj in mergedObjs do
|
|
(
|
|
--Add node to hidden layer
|
|
LayerProp.addnode mergedObj
|
|
|
|
--Add node: Returns true if the node has been added to our array, false if not. This way we keep MeshObjs array and m_FeatureObjectList (C#)
|
|
local result = vm.AddFeatureObject mergedObj.Name
|
|
|
|
--only add the object if the result was true, this way our arrays are synced
|
|
if (result) then
|
|
(
|
|
append MeshObjs mergedObj
|
|
)
|
|
--The object does not exist in the XML so we don't want it in our scene either
|
|
else try(delete mergedObj)catch()
|
|
)
|
|
|
|
vm.AddLineObjects()
|
|
)
|
|
else dispose()
|
|
),
|
|
|
|
fn getValidUvVerts mod_uv obj =
|
|
(
|
|
-- THIS GETS RID OF ANY NON-UVS
|
|
local validVerts = #()
|
|
local maxValue = 10000
|
|
local minValue = -10000
|
|
|
|
mod_uv.unwrap2.setTVSubObjectMode 1
|
|
mod_uv.selectVertices #{1..(mod_uv.numberVerticesByNode obj)}
|
|
local verts = mod_uv.unwrap6.getSelectedVerticesByNode obj
|
|
|
|
for i=1 to verts.count do
|
|
(
|
|
local pt = mod_uv.unwrap6.GetVertexPositionByNode 1 i obj
|
|
local isValid = true
|
|
if (pt.x > maxValue OR pt.x < minValue) do isValid = false
|
|
if (pt.y > maxValue OR pt.y < minValue) do isValid = false
|
|
|
|
if (isValid) do append validVerts i
|
|
)
|
|
|
|
return validVerts
|
|
),
|
|
|
|
------------------------------------------------------------------------------------------------------
|
|
--Makes spline from edge selection
|
|
------------------------------------------------------------------------------------------------------
|
|
fn MakeSplineFromSelection obj =
|
|
(
|
|
if (classof obj == Editable_Mesh) do ConvertToPoly obj
|
|
|
|
obj.EditablePoly.createShape "sweepSpline_temp" false $
|
|
m_SweepSpline = getnodebyname "sweepSpline_temp"
|
|
m_SweepSpline.name = ($.name + "_Lines_")
|
|
),
|
|
|
|
------------------------------------------------------------------------------------------------------
|
|
--Create the actual spline object, width is stored in the XML read in C# stored in m_SplineDetailObj
|
|
------------------------------------------------------------------------------------------------------
|
|
fn CreateLine =
|
|
(
|
|
--Get the detailObject from FilteredLineObjectList at selectedLineIndex
|
|
m_SplineDetailObj = vm.FilteredLineObjectList.item[vm.SelectedLineDecalIndex]
|
|
|
|
--SectionSpline:
|
|
local width = m_SplineDetailObj.Width
|
|
-- local knots = #([-width,0,0],[0,0,0],[0,0,0])
|
|
local ss = SplineShape pos:[0,0,0] name:"sweepShape"
|
|
addNewSpline ss
|
|
addKnot ss 1 #corner #line [0,0,0]
|
|
addKnot ss 1 #corner #line [-width,0,0]
|
|
updateShape ss
|
|
|
|
mod_sweep = sweep()
|
|
mod_normal = Normalmodifier()
|
|
|
|
mod_sweep.shapes[1] = ss
|
|
mod_sweep.CustomShape = 1
|
|
mod_sweep.Angle = 0
|
|
mod_sweep.PivotAlignment = 4
|
|
mod_sweep.GenerateMappingCoords = true
|
|
mod_sweep.RealWorldMapSize = true
|
|
mod_sweep.XOffset = 0
|
|
mod_sweep.YOffset = 0
|
|
|
|
addModifier m_SweepSpline mod_sweep
|
|
|
|
ConvertToPoly m_SweepSpline
|
|
delete ss
|
|
),
|
|
|
|
------------------------------------------------------------------------------------------------------
|
|
--Create he uvs for the spline object, umin, umax, vmin and vmax are all stored in m_SplineDetailObj read from an XML
|
|
------------------------------------------------------------------------------------------------------
|
|
fn CreateUvs =
|
|
(
|
|
--We need to fix the uvs now
|
|
uMin=m_SplineDetailObj.uMin
|
|
uMax=m_SplineDetailObj.uMax
|
|
vMin=m_SplineDetailObj.vMin
|
|
vMax=m_SplineDetailObj.vMax
|
|
|
|
local uSpace = uMax - uMin
|
|
local vSpace = vMax - vMin
|
|
|
|
local bIsVertical = if (vSpace > uSpace) then true else false
|
|
|
|
-- UVS DON'T WORK UNLESS SELECTED IN THE MOD PANAL
|
|
max modify mode
|
|
select m_SweepSpline
|
|
local mod_uv = unwrap_uvw()
|
|
addModifier m_SweepSpline mod_uv
|
|
|
|
-- SELECT VERTS
|
|
mod_uv.selectVertices ((getValidUvVerts mod_uv m_SweepSpline) as bitarray)
|
|
|
|
local bbox = rsta_uv.get_selBoundingBox mod_uv
|
|
local w = (bbox[2] - bbox[1]) as Float
|
|
local h = (bbox[4] - bbox[3]) as Float
|
|
|
|
-- ROTATE IF VERTICAL TEXTURE
|
|
if bIsVertical AND h < w do mod_uv.rotateSelectedVerticesCenter (pi/2)
|
|
if not(bIsVertical) AND h > w do mod_uv.rotateSelectedVerticesCenter (pi/2)
|
|
|
|
bbox = rsta_uv.get_selBoundingBox mod_uv
|
|
w = (bbox[2] - bbox[1]) as Float
|
|
h = (bbox[4] - bbox[3]) as Float
|
|
|
|
local s = if bIsVertical then (1/w)*(uMax - uMin) else (1/h)*(vMax - vMin)
|
|
|
|
mod_uv.scaleSelectedCenter s 0
|
|
|
|
bbox = rsta_uv.get_selBoundingBox mod_uv
|
|
|
|
mod_uv.unwrap2.snapPivot 2 -- BOTTOM LEFT
|
|
mod_uv.unwrap2.moveSelected [uMin-bbox[1],vMax-bbox[4],0]
|
|
),
|
|
|
|
------------------------------------------------------------------------------------------------------
|
|
--Create he shader for the new line object. This data is stored in the XML file but was read in C# and stored in m_SplineDetailObj
|
|
------------------------------------------------------------------------------------------------------
|
|
fn CreateShader =
|
|
(
|
|
line_shader = MultiMaterial()
|
|
line_shader.materiallist.count = 1
|
|
|
|
local newRage = Rage_Shader()
|
|
local SelectedShader = m_SplineDetailObj.ShaderType
|
|
if (RsShaderExists SelectedShader) do RstSetShaderName newRage (SelectedShader + ".sps")
|
|
|
|
line_shader.materiallist[1] = newRage
|
|
|
|
for i = 0 to m_SplineDetailObj.ShaderList.Count - 1 do
|
|
(
|
|
--This will return something like Diffuse_Texture
|
|
local shaderValue = m_SplineDetailObj.ShaderList.Item[i].ShaderValue
|
|
|
|
--We should find the underscore and replace it with a space
|
|
local underscoreIndex = findstring shaderValue "_"
|
|
if (underscoreIndex != undefined)do shaderValue = replace shaderValue underscoreIndex 1 " "
|
|
|
|
--get the texture path
|
|
local texturePath = m_SplineDetailObj.ShaderList.Item[i].TexturePath
|
|
|
|
-- set shader
|
|
rsta_rageMat.setVarByName newRage shaderValue texturePath
|
|
)
|
|
|
|
m_SweepSpline.mat = line_shader
|
|
),
|
|
|
|
------------------------------------------------------------------------------------------------------
|
|
--Create Selected Line click event
|
|
--Creates an object from the selected edge or spline
|
|
------------------------------------------------------------------------------------------------------
|
|
fn CreateLineButtonClicked =
|
|
(
|
|
if (selection.Count == 1) do
|
|
(
|
|
local obj = selection[1]
|
|
|
|
--2 options, either we have a spline selected or we are in edge mode
|
|
--Check Edge Mode
|
|
if (classof obj == Editable_Poly OR classof obj == Editable_Mesh) then
|
|
(
|
|
max modify mode
|
|
if (subobjectLevel == 2) do
|
|
(
|
|
--Initialiaze SweepSpline
|
|
MakeSplineFromSelection obj
|
|
)
|
|
)
|
|
else if (superclassof obj == shape) then
|
|
(
|
|
--No need to make it, we have it already
|
|
m_SweepSpline = obj
|
|
)
|
|
|
|
if (m_SweepSpline != undefined) do
|
|
(
|
|
CreateLine()
|
|
CreateUvs()
|
|
CreateShader()
|
|
|
|
--Push the line up
|
|
local pushModi = Push()
|
|
pushModi.Push_Value = 0.02
|
|
AddModifier m_SweepSpline pushModi
|
|
|
|
ConvertToPoly m_SweepSpline
|
|
)
|
|
)
|
|
),
|
|
|
|
------------------------------------------------------------------------------------------------------
|
|
--Sets the target surface. UpdateTargetSurfaceButton will return true or false depending on wether there was already an object set (return false) or not (return true)
|
|
--If UpdateTargetSurfaceButton returns false we unset the target (UnsetTargetSurface)
|
|
--If UpdateTargetSurfaceButton returns true we set the BaseObject (copy of the original)
|
|
------------------------------------------------------------------------------------------------------
|
|
fn SetTargetSurface =
|
|
(
|
|
if (selection.count == 1)then
|
|
(
|
|
if (classOf_Array #(Editable_Poly, Editable_mesh) selection[1])do
|
|
(
|
|
local success = vm.UpdateTargetSurfaceButton selection[1].Name
|
|
--print success
|
|
if (success) then
|
|
(
|
|
OriginalObject = selection[1]
|
|
BaseObject = copy OriginalObject
|
|
BaseObject.Name += "_WORKING"
|
|
hide OriginalObject
|
|
deselect OriginalObject
|
|
|
|
--Conver to Mesh
|
|
ConvertToMesh BaseObject
|
|
|
|
--Transform lock the object
|
|
SetTransformLockFlags BaseObject #All
|
|
|
|
--Set wireColor to red
|
|
BaseObject.wirecolor = color 255 0 0
|
|
)
|
|
else UnsetTargetSurface()
|
|
)
|
|
)
|
|
else
|
|
(
|
|
vm.UpdateTargetSurfaceButton ""
|
|
UnsetTargetSurface()
|
|
)
|
|
),
|
|
------------------------------------------------------------------------------------------------------
|
|
--returns the object on index we selected + 1 (0 / 1 based index)
|
|
------------------------------------------------------------------------------------------------------
|
|
fn GetDecalObj =
|
|
(
|
|
--print FeatureDecalIndex
|
|
return meshObjs[vm.FeatureDecalIndex + 1]
|
|
),
|
|
|
|
------------------------------------------------------------------------------------------------------
|
|
--No need to check if all objects are valid I think
|
|
------------------------------------------------------------------------------------------------------
|
|
fn StartPlaceTool =
|
|
(
|
|
print "place tool start"
|
|
startTool roadMarkings_feature
|
|
),
|
|
|
|
------------------------------------------------------------------------------------------------------
|
|
--Exports an XML file from the MasterFile (prefix skip are objects that will be ignored)
|
|
------------------------------------------------------------------------------------------------------
|
|
fn ExportXML =
|
|
(
|
|
local previewImagePath = RsConfigGetToolsDir() + "wildwest/assets/image_files/DecalThumbnails/"
|
|
|
|
vm.Start previewImagePath
|
|
|
|
--local objs = getCurrentSelection()
|
|
for obj in geometry where classOf_Array #(Editable_Poly, Editable_mesh) obj do
|
|
(
|
|
--"skip" prefix is used to exclude objects from "exporting"
|
|
if (toLower(substring obj.name 1 4) == "skip")do continue
|
|
|
|
local uniqueTVertArray = #()
|
|
local matID = undefined
|
|
|
|
--Center pivot and reset xforms
|
|
obj.pivot = obj.center
|
|
resetXform obj
|
|
ConvertToMesh obj
|
|
|
|
--set to false when we should skip a loop
|
|
canContinue = true
|
|
|
|
for faceIdx = 1 to (meshop.getNumFaces obj) do
|
|
(
|
|
-- TRY AND GET THE TEXTURE FACE
|
|
local textureFace = undefined
|
|
try (textureFace = getTVFace obj faceIdx)catch()
|
|
|
|
--if for some reason we have objects without a tvface we skip out of this loop (using canContinue so we skip out of the bigger for too)
|
|
if (textureFace == undefined)do canContinue = false
|
|
if (canContinue == false) do continue
|
|
|
|
-- GET THE UVW VERTS OF THE FACE
|
|
local tVert_1 = getTVert obj textureFace.x
|
|
local tVert_2 = getTVert obj textureFace.y
|
|
local tVert_3 = getTVert obj textureFace.z
|
|
|
|
--clamping
|
|
if (tVert_1.X > 1.0f) then tVert_1.X = 1.0f
|
|
else if (tVert_1.X < 0.0f) then tVert_1.X = 0.0f
|
|
|
|
if (tVert_2.X > 1.0f) then tVert_2.X = 1.0f
|
|
else if (tVert_2.X < 0.0f) then tVert_2.X = 0.0f
|
|
|
|
if (tVert_3.X > 1.0f) then tVert_3.X = 1.0f
|
|
else if (tVert_3.X < 0.0f) then tVert_3.X = 0.0f
|
|
|
|
--Save these verts if unique and then get the maximum and minimum position.
|
|
appendIfUnique uniqueTVertArray tVert_1
|
|
appendIfUnique uniqueTVertArray tVert_2
|
|
appendIfUnique uniqueTVertArray tVert_3
|
|
|
|
matID = getFaceMatID obj faceIdx
|
|
)
|
|
|
|
if (canContinue == false) do continue
|
|
|
|
--Find maximum and minimum in array
|
|
local maxPoint = copy uniqueTVertArray[1]
|
|
local minPoint = copy uniqueTVertArray[1]
|
|
for tPoint in uniqueTVertArray do
|
|
(
|
|
if (maxPoint.X < tPoint.X) do maxPoint.X = tPoint.X
|
|
if (minPoint.X > tPoint.X) do minPoint.X = tPoint.X
|
|
|
|
if (maxPoint.Y < tPoint.Y) do maxPoint.Y = tPoint.Y
|
|
if (minPoint.Y > tPoint.Y) do minPoint.Y = tPoint.Y
|
|
)
|
|
|
|
--Get the texture
|
|
local sDiffuseTexture = rsta_rageMat.getDiffuse obj.mat.materialList[matID]
|
|
|
|
--Check if this is a line or a feature (Lines start with "LINE")
|
|
if (toLower(substring obj.name 1 4) == "line") then
|
|
(
|
|
if not vm.CanLineObjectBeAdded obj.Name do
|
|
(
|
|
local sNewUniqueName = uniquename obj.Name
|
|
obj.Name = sNewUniqueName
|
|
)
|
|
|
|
local maxBB = obj.Max
|
|
local minBB = obj.Min
|
|
|
|
local width = 0.0f
|
|
if (maxBB.X - minBB.X < MaxBB.Y - minBB.Y) then width = maxBB.X - minBB.X else width = MaxBB.Y - minBB.Y
|
|
|
|
--Create preview image and store basic info (width, uv pos)
|
|
RSG_Struct.vm.CreateLinePreviewImage width maxPoint.X minPoint.X maxPoint.Y minPoint.Y obj.Name sDiffuseTexture
|
|
|
|
--Set shader type
|
|
local shadertype = rsta_rageMat.getShaderType obj.mat.materialList[matID] ext:false
|
|
RSG_Struct.vm.SetShaderType obj.Name shadertype
|
|
|
|
--Get all textures
|
|
local typeArray = rsta_rageMat.getAllTypes obj.mat.materialList[matID]
|
|
local nameArray = rsta_rageMat.getAllNames obj.mat.materialList[matID]
|
|
local valueArray = rsta_rageMat.getAllValues obj.mat.materialList[matID]
|
|
|
|
--Save all the textures
|
|
for i = 1 to typeArray.Count do
|
|
(
|
|
if (typeArray[i] == "texmap")do
|
|
(
|
|
RSG_Struct.vm.AddTexture obj.Name nameArray[i] valueArray[i]
|
|
)
|
|
)
|
|
)
|
|
else
|
|
(
|
|
--Check if we've already added an object with this name, in that case rename it
|
|
if not vm.CanFeatureObjectBeAdded obj.Name do
|
|
(
|
|
local sNewUniqueName = uniquename obj.Name
|
|
obj.Name = sNewUniqueName
|
|
)
|
|
|
|
--Create preview image
|
|
vm.CreateFeaturePreviewImage maxPoint.X maxPoint.Y minPoint.X minPoint.Y obj.Name sDiffuseTexture
|
|
)
|
|
)
|
|
|
|
local xmlSavePath = RsConfigGetToolsDir() + m_RelativeXmlPath
|
|
|
|
--Save XML file (this will get the latest and check out this XML file (in C#))
|
|
RSG_Struct.vm.CreateXML xmlSavePath
|
|
),
|
|
|
|
-------------------------------------------------------------------
|
|
fn init =
|
|
(
|
|
-- LOAD ASSEMBLY
|
|
--RELEASE
|
|
local dllPath = RsConfigGetToolsDir() + @"techart\dcc\3dsMax\RSG.TechArt.DecalPlacer.dll"
|
|
dotNet.loadAssembly dllPath
|
|
|
|
--DEBUG
|
|
--dotnet.loadAssembly @"X:\wildwest\src\Library\RSG.TechArt\RSG.TechArt.DecalPlacer\RSG.TechArt.DecalPlacer\RSG.TechArt.DecalPlacer\bin\Debug\RSG.TechArt.DecalPlacer.dll"
|
|
|
|
-- MAKE MAIN WINDOW INSTANCE
|
|
MainWindow = dotNetObject "RSG.TechArt.DecalPlacer.MainWindow"
|
|
dn_window.setup MainWindow
|
|
MainWindow.Tag = dotnetmxsvalue this
|
|
-- PARENTS THE WINDOW UNDER MAX, STOPS IT FROM DROPPING BEHIND
|
|
MainWindow.ChangeOwner (DotNetObject "System.IntPtr" (Windows.GetMAXHWND()))
|
|
-- WINDOW POS
|
|
settings.wpf_windowPos mainWindow #get
|
|
-- SHOW THE WINDOW
|
|
MainWindow.show()
|
|
vm = MainWindow.DataContext
|
|
|
|
|
|
--Current handy object file
|
|
local handyObjectRoadMarkingFile = RsConfigGetModelSourceDir() + @"handy objects/road_markings.max"
|
|
local baseFileName = "road_markings"
|
|
|
|
--Get current file path and name
|
|
local fileName = maxfilename
|
|
local filePath = maxfilePath
|
|
if (fileName != "") then
|
|
(
|
|
local currentFullPath = filePath + fileName
|
|
|
|
handyObjectRoadMarkingFile = rsMakeSafeSlashes handyObjectRoadMarkingFile
|
|
|
|
currentFullPath = rsMakeSafeSlashes currentFullPath
|
|
|
|
--check to see if there are any numbers behind it, maybe it's an incremental save
|
|
local extensionPos = findString fileName "."
|
|
local nameOnly = substring fileName 1 (extensionPos - 1)
|
|
--We know the name should be road_markings so substring the name again with the length of this string
|
|
local nameWithoutAnyPostfix = substring nameOnly 1 (baseFileName.count)
|
|
local onlyPostFixes = substring nameOnly (baseFileName.count + 1) -1
|
|
|
|
if (toLower(nameWithoutAnyPostFix) == toLower(baseFileName) AND onlyPostFixes != "") then
|
|
(
|
|
messageBox "You should rename the file back to road_markings before you can export the XML"
|
|
dispose
|
|
)
|
|
else if (toLower(currentFullPath) == toLower(handyObjectRoadMarkingFile))then
|
|
(
|
|
vm.IsInMasterFile = true
|
|
)
|
|
)
|
|
else
|
|
(
|
|
vm.IsInMasterFile = false
|
|
|
|
--sync xml file
|
|
gRsPerforce.sync(RsConfigGetToolsDir() + m_RelativeXmlPath)
|
|
--sync max file
|
|
gRsPerforce.sync(currentHandyObjectRoadMarkingFile)
|
|
|
|
FeatureFile = handyObjectRoadMarkingFile
|
|
|
|
--Empty array will be filled up by MergeFile. This is where we keep the mesh. It's on the same index as the Listview
|
|
MeshObjs = #()
|
|
|
|
--Merge the actual master max file
|
|
MergeFile()
|
|
|
|
--Sort the lists alphabetically
|
|
vm.SortLists()
|
|
)
|
|
|
|
|
|
),
|
|
-- EVENTS -----------------------------------------------------
|
|
on create do init()
|
|
)
|
|
RSG_Struct = RSG_Struct()
|
|
|
|
tool roadMarkings_feature
|
|
(
|
|
-- LOCALS ----------------------------------------------------------
|
|
local theMesh
|
|
local isMove = true
|
|
local m_BaseObject = RSG_Struct.BaseObject
|
|
local m_ProjectObject = undefined
|
|
|
|
|
|
-- FUNCTIONS ----------------------------------------------------
|
|
fn find_intersection sPnt =
|
|
(
|
|
local viewPos = (inverse(getViewTM())).row4
|
|
local v = sPnt - viewPos
|
|
local testRay = ray viewPos v
|
|
local intRay = intersectRay m_BaseObject testRay
|
|
|
|
if (intRay != undefined) then
|
|
(
|
|
local pReturnPos = copy intRay.pos
|
|
pReturnPos.z += 0.05
|
|
pReturnPos
|
|
)
|
|
else
|
|
(
|
|
sPnt
|
|
)
|
|
)
|
|
|
|
fn ProjectDown baseObject projectObject =
|
|
(
|
|
if (classof baseObject == Editable_Poly) do convertToMesh baseObject
|
|
if (classof projectObject == Editable_Poly) do convertToMesh projectObject
|
|
|
|
for idx = 1 to projectObject.numVerts do
|
|
(
|
|
local hitdata = intersectRayEx baseObject (ray ((getVert projectObject idx) + [0,0,10]) [0,0,-1])
|
|
if (hitdata != undefined) do
|
|
(
|
|
meshop.setVert projectObject idx (hitdata[1].pos + [0,0,0.02])
|
|
)
|
|
)
|
|
)
|
|
|
|
fn CreateTesselatedProjTempObj =
|
|
(
|
|
--Make tesselate modifier
|
|
local tesMod = (tessellate ())
|
|
tesMod.faceType = 1
|
|
tesMod.tension = 0
|
|
tesMod.iterations = 3
|
|
|
|
--Copy the original object and add tesselate modifier
|
|
tesModObject_temp = copy m_ProjectObject
|
|
addModifier tesModObject_temp tesMod
|
|
|
|
--Collapse to mesh
|
|
ConvertToMesh tesModObject_temp
|
|
|
|
tesModObject_temp
|
|
)
|
|
|
|
--http://www.illusioncatalyst.com/3dsmax_files/snippets/editable_poly_sub_obj.php
|
|
fn GetInnerEdgeSel obj polySel =
|
|
(
|
|
local baEdgeSet01 = polyOp.getEdgesUsingFace obj polySel
|
|
local baFaceSet01 = #{1..(polyOp.getNumFaces obj)} - polySel
|
|
local baEdgeSet02 = polyOp.getEdgesUsingFace obj baFaceSet01
|
|
|
|
local baEdgeSet03 = polyOp.getOpenEdges obj
|
|
|
|
return (baEdgeSet01 - baEdgeSet02 - baEdgeSet03)
|
|
)
|
|
|
|
fn CreateBooleanMesh =
|
|
(
|
|
oldsweepSpline = getnodebyname "testSpline_temp"
|
|
if (oldsweepSpline != undefined) do delete oldsweepSpline
|
|
|
|
--Create spline from edges
|
|
m_BaseObject.EditablePoly.createShape "testSpline_temp" false m_BaseObject
|
|
sweepSpline = getnodebyname "testSpline_temp"
|
|
|
|
--Extrude them
|
|
local extrudeMod = Extrude ()
|
|
extrudeMod.amount = 5
|
|
addModifier sweepSpline extrudeMod
|
|
|
|
--Conver to mesh
|
|
convertToMesh sweepSpline
|
|
|
|
local face_selection = #{}
|
|
for i = 1 to sweepSpline.numfaces do
|
|
(
|
|
if ((getFaceNormal sweepSpline i).z > 0.51) then
|
|
(
|
|
face_selection[i] = true
|
|
)
|
|
else if ((getFaceNormal sweepSpline i).z < -0.5) then
|
|
(
|
|
face_selection[i] = true
|
|
)
|
|
)
|
|
meshop.deleteFaces sweepSpline face_selection
|
|
|
|
sweepSpline.Pos.Z -= 2.5f
|
|
|
|
--reset xforms
|
|
resetXform sweepSpline
|
|
--Conver to mesh
|
|
convertToMesh sweepSpline
|
|
|
|
sweepSpline
|
|
)
|
|
|
|
fn RemoveExcessiveVerts epoly =
|
|
(
|
|
--Get list of verts shared by 2 edges
|
|
vList = for v=1 to epoly.GetNumVertices() where epoly.GetVertexEdgeCount v == 2 collect v
|
|
|
|
--Get border verts
|
|
local borderVerts = #()
|
|
openEdgesArr = polyOp.getOpenEdges epoly
|
|
for openEdge in openEdgesArr do ( join borderVerts ((polyop.getVertsUsingEdge epoly openEdge) as array))
|
|
|
|
--Remove border verts from first list
|
|
for i = vList.count to 1 by -1 do
|
|
(
|
|
for j = 1 to borderVerts.count do
|
|
(
|
|
if (vList[i] == borderVerts[j]) do
|
|
deleteItem vList i
|
|
)
|
|
)
|
|
|
|
--Remove them
|
|
epoly.SetSelection #Vertex (vList as BitArray)
|
|
epoly.Remove selLevel:#Vertex
|
|
)
|
|
|
|
-- EVENTS ----------------------------------------------------------
|
|
on mousePoint clickno do
|
|
(
|
|
if (clickno == 1) then
|
|
(
|
|
local newMesh = RSG_Struct.GetDecalObj()
|
|
m_ProjectObject = copy newMesh
|
|
)
|
|
else
|
|
(
|
|
isMove = not isMove
|
|
)
|
|
)
|
|
---------------------------------------------------------------------------
|
|
on mouseMove clickno do
|
|
(
|
|
if (isMove) then m_ProjectObject.rotation.Z_Rotation = worldAngle.z
|
|
else m_ProjectObject.pos = find_intersection worldPoint
|
|
)
|
|
---------------------------------------------------------------------------
|
|
on stop do
|
|
(
|
|
--print "stop"
|
|
|
|
if (RSG_Struct.vm.FollowTopology) do
|
|
(
|
|
local tesselatedObj = CreateTesselatedProjTempObj()
|
|
--print tesselatedObj
|
|
|
|
--Unique array of face indices our tesselated model hit
|
|
faceHitIndex = #()
|
|
|
|
for idx = 1 to tesselatedObj.numVerts do
|
|
(
|
|
local hitdata = intersectRayEx m_BaseObject (ray ((getVert tesselatedObj idx) + [0,0,10]) [0,0,-1])
|
|
if (hitdata != undefined) do
|
|
(
|
|
appendIfUnique faceHitIndex hitdata[2]
|
|
)
|
|
)
|
|
|
|
--Delete temp obj
|
|
delete tesselatedObj
|
|
|
|
-- Set face selection on road
|
|
setFaceSelection m_BaseObject (faceHitIndex as BitArray)
|
|
--Conver to poly
|
|
ConvertToPoly m_BaseObject
|
|
|
|
--Get the face selection to then only get the inner edge selection
|
|
local selectedPolys = polyop.GetFaceSelection m_BaseObject
|
|
|
|
--inner selection
|
|
local baInnerSel = GetInnerEdgeSel m_BaseObject selectedPolys
|
|
|
|
--Set edge selection to inner edges
|
|
polyOp.setEdgeSelection m_BaseObject baInnerSel
|
|
|
|
local booleanMesh = CreateBooleanMesh()
|
|
|
|
--Boolean operation
|
|
m_ProjectObject - booleanMesh
|
|
|
|
--Delete booleanMesh temp object
|
|
delete booleanMesh
|
|
|
|
--Convert back to poly to remove excessive verts created by the boolean operation
|
|
ConvertToPoly m_ProjectObject
|
|
RemoveExcessiveVerts m_ProjectObject
|
|
)
|
|
|
|
ProjectDown m_BaseObject m_ProjectObject
|
|
)
|
|
)
|
|
|
|
/*
|
|
try (destroyDialog RoadMarkingsRoll) catch()
|
|
rollout RoadMarkingsRoll "Road Markings" width:200
|
|
(
|
|
------------------------------------------------------------------
|
|
-- LOCALS
|
|
------------------------------------------------------------------
|
|
local settings = rsta_userSettings app:"RoadMarkings"
|
|
local originalTarget
|
|
local meshTarget
|
|
local featureFile = "X:/gta5_liberty/art/dev/models/Handy objects/road_markings04.max"
|
|
--"X:/gta5_liberty/art/dev/models/Handy objects/road_markings_TEST.max"
|
|
local xmlPath = @"X:\wildwest\etc\config\maps\RoadMarkings.xml"
|
|
local xml_io
|
|
|
|
local xml_features = #()
|
|
local useTemplates = true
|
|
|
|
local mergedObjs = #()
|
|
local meshObjs = #()
|
|
|
|
local layerProp = undefined
|
|
|
|
|
|
------------------------------------------------------------------
|
|
-- CONTROLS
|
|
------------------------------------------------------------------
|
|
dotNetControl rsBannerPanel "Panel" pos:[0,0] height:32 width:RoadMarkingsRoll.Width
|
|
local banner = makeRsBanner dn_Panel:rsBannerPanel versionNum:1.00 wiki:"" filename:(getThisScriptFilename())
|
|
|
|
button btn_setTarget "Set Target Surface" width:180
|
|
|
|
|
|
button btn_TestGetPreview "Export XML" width:180
|
|
|
|
group "Lines"
|
|
(
|
|
button btn_CreateFromSplineOrEdge_Struct "Create From Spline Or Edge" width:180
|
|
)
|
|
|
|
group "Features"
|
|
(
|
|
dropdownlist ddl_FeatureType ""
|
|
button btn_makeFeature "Place Feature" width:180
|
|
button btn_Test_MergeFile "Merge file" width:180
|
|
|
|
|
|
)
|
|
|
|
------------------------------------------------------------------
|
|
-- EVENTS
|
|
------------------------------------------------------------------
|
|
on btn_CreateFromSplineOrEdge_Struct pressed do
|
|
(
|
|
RSG_Struct.CreateLineButtonClicked()
|
|
)
|
|
|
|
|
|
on RoadMarkingsRoll open do
|
|
(
|
|
banner.setup()
|
|
)
|
|
|
|
--EXPORT---------------
|
|
on btn_TestGetPreview pressed do
|
|
(
|
|
RSG_Struct.ExportXML()
|
|
)
|
|
|
|
|
|
|
|
on btn_setTarget pressed do setTarget()
|
|
on btn_makeFeature pressed do startFeatureTool()
|
|
|
|
on btn_Test_mergeFile pressed do MergeFile()
|
|
|
|
)
|
|
createDialog RoadMarkingsRoll style:#(#style_titlebar, #style_border, #style_sysmenu,#style_toolwindow)
|
|
*/ |