884 lines
29 KiB
Plaintext
Executable File
884 lines
29 KiB
Plaintext
Executable File
-- VegetationTools.ms
|
|
-- 2013 Andy Davis
|
|
-- Rockstar London
|
|
-- Description: Collection of tools to manage vegetation related geometry tasks
|
|
|
|
filein (RsConfigGetWildWestDir() + "script/3dsMax/_config_files/Wildwest_header.ms") --wildwest header
|
|
filein (RsConfigGetWildWestDir() + "script/3dsMax/_common_functions/RSL_dotNetUIOps.ms") --RS_dotNetPreset structure
|
|
RsCollectToolUsageData (getThisScriptFilename())
|
|
|
|
global VegToolsUI
|
|
|
|
struct CustomTreeData
|
|
(
|
|
ObjectName, --the RSRefObject.objectName value
|
|
PivotOffset = [0,0,0], --the value to offset the pivot so that it is placed at the base of the tree
|
|
Radius --radius of the base of the tree
|
|
)
|
|
|
|
struct TreePlacementStruct
|
|
(
|
|
tolerance = 0.5,
|
|
maxTrunkRadius = 1,
|
|
padding = 0.01,
|
|
groundPlane = undefined,
|
|
objSet = #(),
|
|
debug = false,
|
|
progress = 0,
|
|
CustomTreeList = #(),
|
|
|
|
fn PlaceObjects =
|
|
(
|
|
local originalSelection = selection as array
|
|
|
|
for obj in originalSelection do
|
|
(
|
|
if (classOf obj.baseObject == RSrefObject) and (obj != this.groundPlane) then
|
|
(
|
|
local numModifiers = obj.modifiers.count
|
|
|
|
this.FixRSRef obj
|
|
append this.objSet obj
|
|
)
|
|
)
|
|
|
|
select objSet
|
|
local GroundPlanes = this.GetGroundPlanes selection
|
|
|
|
for obj in objSet do
|
|
(
|
|
|
|
local ZRotation = this.GetZRotation obj
|
|
local RandomRotation = VegToolsUI.RandomSpinner.text as float
|
|
|
|
if (RandomRotation > 0.0) then
|
|
ZRotation += (random -180 180) * RandomRotation
|
|
|
|
this.SetRotation obj (eulerAngles 0 0 0)
|
|
local downVector = [0,0,-1]
|
|
local verticalPad = 3 --height to add to the z value of the ray in order to replant trees
|
|
local PivotOffset = [0,0,0]
|
|
local treeRadius = 0.03
|
|
local IsCustom = false
|
|
|
|
--check to see if the object is in the CustomTreeList
|
|
for item in this.CustomTreeList do
|
|
(
|
|
if obj.objectName == item.ObjectName then
|
|
(
|
|
PivotOffset = item.PivotOffset
|
|
treeRadius = item.Radius
|
|
IsCustom = true
|
|
)
|
|
)
|
|
|
|
if (IsCustom) then
|
|
(
|
|
obj.pivot -= PivotOffset
|
|
)
|
|
|
|
local PivotRay = ray [obj.pivot.x, obj.pivot.y, (obj.pivot.z + verticalPad)] downVector --used to calculate slope angle
|
|
local intersection = this.GetIntersection GroundPlanes PivotRay
|
|
|
|
if intersection != undefined then
|
|
(
|
|
local ZPoint = intersection.pos.z
|
|
local dropHeight = obj.pivot.z - ZPoint + 0.15
|
|
--rotate the object to fit it in the direction of the slope
|
|
--get the slope angle
|
|
local slopeRay = intersection.dir
|
|
local slantVector = this.GetProportionalVector slopeRay [0,0,1] (VegToolsUI.slopeSpinner.text as float)
|
|
-- print slopeRay
|
|
local slantAngle = this.GetAngleFromVector slantVector
|
|
|
|
rotate obj slantAngle
|
|
this.SetZRotation obj ZRotation
|
|
--angle between two vectors for slant vector and vertical to determine the extra drop height
|
|
|
|
obj.position.z -= (dropHeight + this.GetDropHeight slopeRay treeRadius)
|
|
)
|
|
else
|
|
(
|
|
local infoString = ("No ground plane found for " + obj.name)
|
|
messagebox infoString title:"Tree Placement"
|
|
)
|
|
|
|
--reset the pivot to the original position if the pivot has been offset
|
|
if (IsCustom) then
|
|
(
|
|
local RotationBuffer = obj.rotation as eulerAngles
|
|
this.SetRotation obj (eulerAngles 0 0 0)
|
|
obj.Pivot += PivotOffset
|
|
this.SetRotation obj RotationBuffer
|
|
)
|
|
|
|
this.progress += 100 / objSet.count
|
|
)
|
|
|
|
return objSet.count
|
|
),
|
|
|
|
fn InitCustomTreeList =
|
|
(
|
|
append this.CustomTreeList (CustomTreeData ObjectName:"Prop_Bush_Lrg_04b" PivotOffset:[-1.0, -0.45, 2.3] Radius:1.65)
|
|
-- print this.CustomTreeList
|
|
),
|
|
|
|
--calculates the vertical shift an object must drop by to compensate for a tilt from the vertical
|
|
fn GetDropHeight SlopeVector Radius =
|
|
(
|
|
local AngleToVertical = acos(dot (normalize SlopeVector) [0,0,1])
|
|
local DropHeight = sin(AngleToVertical) * Radius
|
|
return DropHeight
|
|
),
|
|
|
|
fn GetZRotation InObject =
|
|
(
|
|
toolMode.coordsys #world
|
|
rot = InObject.Rotation as eulerangles
|
|
-- messagebox (rot.z as string)
|
|
return rot.z
|
|
),
|
|
|
|
fn SetZRotation InObject ZValue =
|
|
(
|
|
toolMode.coordsys #world
|
|
rot = InObject.Rotation as eulerangles
|
|
pos = InObject.Position
|
|
InObject.Rotation = (eulerangles rot.x rot.y ZValue)
|
|
InObject.Position = pos
|
|
),
|
|
|
|
fn GetIntersection TestPlanes InRay =
|
|
(
|
|
local numPlanes = TestPlanes.count
|
|
local found = false
|
|
local intersection = undefined
|
|
|
|
for thisPlane in TestPlanes where found == false do
|
|
(
|
|
intersection = intersectRay thisPlane InRay
|
|
if (intersection != undefined) then found = true
|
|
)
|
|
|
|
return intersection
|
|
),
|
|
|
|
--function collects candidates for ground planes to match a set of passed in nodes
|
|
fn GetGroundPlanes InObject =
|
|
(
|
|
GroundPlanes = for item in geometry where ClassOf item != RSrefObject collect item
|
|
GroundPlanes = for item in GroundPlanes where (item.max.x > InObject.min.x) and (item.max.y > InObject.min.y) collect item
|
|
GroundPlanes = for item in GroundPlanes where (item.min.x < InObject.max.x) and (item.min.y < InObject.max.y) collect item
|
|
GroundPlanes = for item in GroundPlanes where not (getAttr item (getAttrIndex "Gta Object" "Dont Export")) collect item
|
|
GroundPlanes = for item in GroundPlanes where not (RSIsLod item) collect item
|
|
|
|
return GroundPlanes
|
|
),
|
|
|
|
fn SetRotation obj eulerRotation =
|
|
(
|
|
local objPosition = obj.position
|
|
obj.rotation = eulerRotation
|
|
obj.position = objPosition
|
|
),
|
|
|
|
fn FixRSRef rsref =
|
|
(
|
|
local numModifiers = rsref.modifiers.count
|
|
|
|
if numModifiers > 0 then
|
|
(
|
|
for i = 1 to numModifiers do
|
|
(
|
|
deleteModifier rsref rsref.modifiers[1]
|
|
)
|
|
)
|
|
),
|
|
|
|
--function gets an eulerAngles value for a corresponding vector
|
|
fn GetAngleFromVector theNormal =
|
|
(
|
|
local theZ = normalize theNormal --this is the original vector
|
|
|
|
if (dot theZ [0,0,1]) > 0.99999 then --if the vector is nearly parallel to Z, assume 0
|
|
eulerangles 0 0 0
|
|
else
|
|
(
|
|
local theY = normalize (cross [0,0,1] theZ ) --this is the Y axis orthogonal to the Normal and Up
|
|
local theX = normalize (cross theY theZ) --this is the X orthogonal to Normal and Y
|
|
local theTM = matrix3 theX theY theZ [0,0,0] --this is the matrix3 describing the orientation of the Normal
|
|
theTM.rotationpart as eulerangles --return its Euler rotation
|
|
)
|
|
),
|
|
|
|
--finds the vector that is proportionally aligned to the targetVector from a starting reference vector
|
|
--amount: number from 0 to 1 representing the proportion
|
|
--amount 0 is the refVector, amount 1 is the targetVector
|
|
fn GetProportionalVector targetVector refVector amount =
|
|
(
|
|
return (normalize (amount * targetVector + (1 - amount) * refVector))
|
|
),
|
|
|
|
fn IsNoExportSet obj =
|
|
(
|
|
local noExport = false
|
|
|
|
if (getAttr obj (getAttrIndex "Gta Object" "Dont Export")) or (getAttr $ (getAttrIndex "Gta Object" "Dont Add To IPL")) then
|
|
noExport = true
|
|
|
|
return noExport
|
|
),
|
|
|
|
--function prints out the parameters of the struc
|
|
fn PrintDetails =
|
|
(
|
|
clearListener()
|
|
format "Tolerance: %\n" this.tolerance
|
|
|
|
if (this.GroundPlane == undefined) then
|
|
format "Ground Plane: undefined\n"
|
|
else
|
|
format "Ground Plane: %\n" this.groundPlane.name
|
|
)
|
|
)
|
|
|
|
--struct to handle the geometry operations
|
|
struct TreeBaseGeneratorStruct
|
|
(
|
|
--treegen varaibles
|
|
size = 2,
|
|
numSides = 8, --must be 4 or more sides
|
|
fill = 0.75,
|
|
inset = 0.125,
|
|
devMode = false,
|
|
jig = undefined,
|
|
refPoly = undefined,
|
|
topObj = undefined,
|
|
infoString,
|
|
|
|
--function returns the closest of the four edge verts to the mid-point of verts a and b
|
|
fn GetClosestEdgeVert obj a b =
|
|
(
|
|
local midPoint = (obj.verts[a].position + obj.verts[b].position) / 2
|
|
|
|
local closestVert = 1
|
|
local vertDist = distance midPoint obj.verts[1].position
|
|
|
|
for i = 2 to 4 do
|
|
(
|
|
if (distance midPoint obj.verts[i].position) < vertDist then
|
|
(
|
|
closestVert = i
|
|
vertDist = distance midPoint obj.verts[i].position
|
|
)
|
|
)
|
|
|
|
return closestVert
|
|
),
|
|
|
|
--places the jig to the location of the selected polygon
|
|
fn PlaceTreeBase =
|
|
(
|
|
--Check that selection matches criteria
|
|
local objList = for this in selection where superClassOf this == GeometryClass collect this
|
|
|
|
if (objList.count == 1) then
|
|
(
|
|
local obj = objList[1]
|
|
|
|
if obj.modifiers.count > 0 then print "Warning - about to collapse stack"
|
|
convertToPoly objList[1]
|
|
subObjectLevel = 4
|
|
|
|
if (obj.selectedFaces.count == 1) then
|
|
(
|
|
local faceID = obj.selectedFaces[1].index
|
|
local vertIDs = polyOp.GetFaceVerts obj faceID
|
|
|
|
if vertIDs.count == 4 then
|
|
(
|
|
this.CreateBaseMesh()
|
|
select this.jig
|
|
|
|
--set the smoothing groups
|
|
local smoothingGroups = RSGeom_GetSmoothingGroups obj faceID
|
|
for face = 1 to this.jig.faces.count do
|
|
RSGeom_SetSmoothingGroups this.jig face smoothingGroups
|
|
|
|
--set the order for the ffd control points to be translated to match the polygon
|
|
local ffdCPPairs = #(#(1,2), #(5,6), #(7,8), #(3,4))
|
|
local ffd = FFD_2x2x2()
|
|
|
|
addModifier this.jig ffd
|
|
animateAll ffd --required to get access to ffd control points
|
|
clearListener()
|
|
-- ffdOps = FFDWrapper()
|
|
|
|
for i = 1 to 4 do
|
|
(
|
|
RSFFD_SetWorldPos this.jig this.jig.FFD_2x2x2 ffdCPPairs[i][1] obj.verts[vertIDs[i]].position
|
|
RSFFD_SetWorldPos this.jig this.jig.FFD_2x2x2 ffdCPPairs[i][2] obj.verts[vertIDs[i]].position
|
|
)
|
|
|
|
|
|
--extract quad from mesh
|
|
polyop.detachFaces obj obj.faces[faceID] delete:true asNode:true name:"transfer"
|
|
this.topObj = obj
|
|
this.infoString = "Polygon processed."
|
|
true
|
|
)
|
|
else
|
|
(
|
|
this.infoString = "Please select a quad."
|
|
false
|
|
)
|
|
)
|
|
else
|
|
(
|
|
this.infoString = "Please select a single face."
|
|
false
|
|
)
|
|
)
|
|
else
|
|
(
|
|
this.infoString = "Please select a polygon on an object."
|
|
false
|
|
)
|
|
),
|
|
|
|
--callback script for the projection modifier used to transfer the mapping data to the treeBase
|
|
fn ProjectionCallback =
|
|
(
|
|
local hwnd = dialogMonitorOps.getWindowHandle()
|
|
|
|
if (uiAccessor.getWindowText hwnd == "Add Objects") then
|
|
(
|
|
--the control IDs below are correct for 3dsMax 2012
|
|
--may need to refigure the IDs if the dialog box changes in future versions
|
|
--use windows.getChildHWND <hwnd> to get a list of controls
|
|
|
|
local dotNetPressEnter = dotNetClass "System.Windows.Forms.SendKeys"
|
|
local toolStripID = 5
|
|
local addButtonID = 19
|
|
local editButtonID = 12
|
|
local VK_RETURN = 0x0D
|
|
local MAXHWND = windows.getMAXHWND()
|
|
local AddObjectsHWNDList = UIAccessor.GetChildWindows hwnd
|
|
local AddObjectsControls = windows.getChildrenHWND hwnd
|
|
local toolStripHWNDControls = windows.getChildrenHWND AddObjectsHWNDList[toolStripID]
|
|
|
|
UIAccessor.SetWindowText toolStripHWNDControls[editButtonID][1] this.jig.name
|
|
dotNetPressEnter.Send "{ENTER}"
|
|
)
|
|
|
|
true
|
|
),
|
|
|
|
--attach the jig to the original object, after transferring the material and mapping
|
|
fn AttachTreeBase =
|
|
(
|
|
local source = objects[objects.count]
|
|
--copy materials and transfer mapping
|
|
this.jig.material = source.material
|
|
addModifier source (Projection())
|
|
select source
|
|
|
|
dialogMonitorOps.unRegisterNotification id:#test
|
|
dialogMonitorOps.enabled = true
|
|
dialogMonitorOps.interactive = false
|
|
dialogMonitorOps.registerNotification ProjectionCallback id:#test
|
|
commandHWND = (windows.getChildHWND #max "Pick List")
|
|
UIAccessor.pressButtonByName commandHWND[2] "Pick List"
|
|
commandHWND = (windows.GetChildHWND #max "Add")
|
|
UIAccessor.pressButtonByName commandHWND[2] "Add"
|
|
commandHWND = (windows.GetChildHWND #max "Project All")
|
|
UIAccessor.pressButtonByName commandHWND[2] "Project All"
|
|
dialogMonitorOps.enabled = false
|
|
|
|
--combine base mesh with original mesh
|
|
convertToMesh #(this.topObj, this.jig)
|
|
meshop.attach this.topObj this.jig
|
|
convertToPoly this.topObj
|
|
|
|
--weld the vertices
|
|
this.topObj.weldThreshold = 0.01
|
|
local outerEdges = polyop.getOpenEdges this.topObj
|
|
local edgeVerts = polyop.getVertsUsingEdge this.topObj outerEdges
|
|
polyop.weldVertsByThreshold this.topObj edgeVerts
|
|
delete source
|
|
select this.topobj
|
|
),
|
|
|
|
fn CreateBaseMesh =
|
|
(
|
|
local originalSelection = selection as array
|
|
local selectionMode = subObjectLevel
|
|
|
|
this.CreateJig()
|
|
|
|
try
|
|
(
|
|
select originalSelection
|
|
subObjectLevel = selectionMode
|
|
)
|
|
catch(clearSelection())
|
|
),
|
|
|
|
fn CreateJig =
|
|
(
|
|
if (devMode) then
|
|
for this in objects where (this.name == "jig") do delete this
|
|
|
|
this.jig = Plane width:this.size length:this.size name:"jig" lengthsegs:1 widthsegs:1
|
|
local radiusValue = this.jig.width * this.fill * 0.5
|
|
local insetValue = radiusValue * this.inset
|
|
local base = Cylinder radius:radiusValue height:0.5 sides:this.numSides
|
|
|
|
convertToMesh base
|
|
local baseVerts = for item in base.verts where item.position.z == 0 and item.position != [0,0,0] collect item.position
|
|
append baseVerts [0,0,0]
|
|
delete base
|
|
select this.jig
|
|
this.jig.backfacecull = true
|
|
convertToMesh this.jig
|
|
meshop.setNumVerts this.jig (5 + numSides)
|
|
|
|
for i = 1 to (numSides + 1) do
|
|
(
|
|
this.jig.verts[i + 4].position = baseVerts[i]
|
|
)
|
|
|
|
subObjectLevel = 1
|
|
|
|
for i = 1 to (numSides - 1) do
|
|
(
|
|
meshop.createPolygon this.jig #(i+4, i+5, numSides + 5)
|
|
local edgeVert = GetClosestEdgeVert this.jig (i+4) (i+5)
|
|
meshop.createPolygon this.jig #(i+5, i+4, edgeVert)
|
|
)
|
|
|
|
-- create the final center poly
|
|
meshop.createPolygon this.jig #(numSides + 4, 5, numSides + 5)
|
|
meshOp.createPolygon this.jig #(5, numSides + 4, (GetClosestEdgeVert jig 5 (numSides + 4)))
|
|
meshop.deleteFaces this.jig #{1,2} --delete the initial two faces
|
|
|
|
-- create the final edge polys
|
|
-- first get the vertex ids for each of the four triangles
|
|
local openEdgeList = meshop.GetOpenEdges this.jig
|
|
local nonCornerVerts = #()
|
|
local finalEdgePolys = #()
|
|
|
|
for item in openEdgeList as array do
|
|
(
|
|
local verts = (meshop.getVertsUsingEdge this.jig item) as array
|
|
local innerVert, outerVert
|
|
|
|
if (verts[1] > 4) then
|
|
(
|
|
innerVert = verts[1]
|
|
outerVert = verts[2]
|
|
)
|
|
else
|
|
(
|
|
innerVert = verts[2]
|
|
outerVert = verts[1]
|
|
)
|
|
|
|
if finalEdgePolys.count > 0 then
|
|
(
|
|
local found = false
|
|
|
|
for poly in finalEdgePolys do
|
|
(
|
|
if innerVert == poly[1] then
|
|
(
|
|
found = true
|
|
append poly outerVert
|
|
)
|
|
)
|
|
|
|
if (not found) then
|
|
(
|
|
append finalEdgePolys #(innerVert, outerVert)
|
|
)
|
|
)
|
|
|
|
else
|
|
(
|
|
append finalEdgePolys #(innerVert, outerVert)
|
|
)
|
|
)
|
|
|
|
-- now create the polys
|
|
for item in finalEdgePolys do
|
|
(
|
|
if (item[1] == 5) then
|
|
meshop.createPolygon jig #(item[1], item[3], item[2])
|
|
else
|
|
meshop.createPolygon jig item
|
|
)
|
|
|
|
--translate the centre vertex so that the ffd is not flat
|
|
--this is necessary so that the ffd is not 2-dimensional
|
|
jig.verts[jig.verts.count].position.z += 0.2
|
|
|
|
--inset the centre
|
|
convertToPoly jig
|
|
subObjectLevel = 4
|
|
local centerFaces = polyop.getFacesUsingVert jig #{jig.verts.count}
|
|
polyop.setFaceSelection jig centerFaces
|
|
jig.insetAmount = insetValue
|
|
jig.buttonOp #Inset
|
|
polyop.setFaceSelection jig #{}
|
|
jig
|
|
),
|
|
|
|
fn SetCommandPanelRedraw State =
|
|
(
|
|
Args = 0
|
|
if( State == on ) then Args = 1
|
|
|
|
WM_SETREDRAW=0xB
|
|
CommandHWND = (Windows.GetChildHWND #Max "Command Panel")
|
|
Windows.Sendmessage (CommandHWND[1]) WM_SETREDRAW Args 0
|
|
),
|
|
|
|
fn Process =
|
|
(
|
|
with undo off
|
|
(
|
|
this.SetCommandPanelRedraw false
|
|
try
|
|
(
|
|
local success = this.PlaceTreeBase()
|
|
if (success) then this.AttachTreeBase()
|
|
this.SetCommandPanelRedraw true
|
|
)
|
|
catch
|
|
(
|
|
format "Error: problem during execution"
|
|
this.SetCommandPanelRedraw true
|
|
)
|
|
)
|
|
|
|
return this.infoString
|
|
)
|
|
)
|
|
|
|
--struct for the UI
|
|
struct VegetationToolsUI
|
|
(
|
|
Form,
|
|
ToolTip,
|
|
InfoPanel,
|
|
NumSidesSpinner,
|
|
FillSpinner,
|
|
InsetSpinner,
|
|
SlopeSpinner,
|
|
RandomSpinner,
|
|
ProgBar,
|
|
IniFilePath = (RsConfigGetWildWestDir() + "script/3dsMax/_config_files/RSL_Tools.ini"),
|
|
TreeGen = TreeBaseGeneratorStruct(),
|
|
TreePlacement = TreePlacementStruct(),
|
|
numSidesMin = 4,
|
|
fillMin = 0.25,
|
|
insetMin = 0.05,
|
|
ProcessingRollout,
|
|
TitleColor = RS_dotNetPreset.ARGB 48 48 48,
|
|
ButtonPadding = dotNetObject "System.Windows.Forms.Padding" 2,
|
|
|
|
------------------------------------------------------------------------------------------------------------------------------------------
|
|
--GENERAL FUNCTIONS
|
|
------------------------------------------------------------------------------------------------------------------------------------------
|
|
|
|
fn GenerateTreeBase s e =
|
|
(
|
|
rollout temprollout "Tree Base Generator"
|
|
(
|
|
label myLabel "Processing"
|
|
)
|
|
|
|
VegToolsUI.TreeGen.numsides = VegToolsUI.NumSidesSpinner.Text as integer
|
|
VegToolsUI.TreeGen.fill = VegToolsUI.FillSpinner.Text as float
|
|
VegToolsUI.TreeGen.inset = VegToolsUI.InsetSpinner.Text as float
|
|
theNewFloater = createDialog temprollout 200 30
|
|
VegToolsUI.InfoPanel.Text = "Processing..."
|
|
VegToolsUI.InfoPanel.Text = VegToolsUI.TreeGen.Process()
|
|
destroyDialog temprollout
|
|
),
|
|
|
|
fn PlaceTrees s e =
|
|
(
|
|
rollout temprollout "Tree Placement"
|
|
(
|
|
label myLabel "Processing"
|
|
)
|
|
|
|
theNewFloater = createDialog temprollout 200 30
|
|
VegToolsUI.TreePlacement.objSet = #()
|
|
|
|
local time = TimeStamp()
|
|
local numTrees = VegToolsUI.TreePlacement.PlaceObjects()
|
|
local timeTaken = (TimeStamp() - time) / 1000.0
|
|
|
|
-- print ("Time taken is " + timeTaken as string + " seconds")
|
|
|
|
if numTrees != undefined then
|
|
(
|
|
if numTrees == 1 then VegToolsUI.InfoPanel.Text = "1 tree placed."
|
|
else
|
|
VegToolsUI.InfoPanel.Text = (numTrees as string + " trees placed.")
|
|
)
|
|
|
|
destroyDialog temprollout
|
|
),
|
|
|
|
------------------------------------------------------------------------------------------------------------------------------------------
|
|
--LOAD/SAVE FUNCTIONS
|
|
------------------------------------------------------------------------------------------------------------------------------------------
|
|
|
|
fn SaveIniFile =
|
|
(
|
|
setINISetting VegToolsUI.IniFilePath "VegToolsUI" "WinLocX" (VegToolsUI.Form.Location.x as string)
|
|
setINISetting VegToolsUI.IniFilePath "VegToolsUI" "WinLocY" (VegToolsUI.Form.Location.y as string)
|
|
setINISetting VegToolsUI.IniFilePath "VegToolsUI" "WinWidth" (VegToolsUI.Form.Width as string)
|
|
setINISetting VegToolsUI.IniFilePath "VegToolsUI" "WinHeight" (VegToolsUI.Form.Height as string)
|
|
setINISetting VegToolsUI.IniFilePath "VegToolsUI" "NumSides" (VegToolsUI.NumSidesSpinner.Text as string)
|
|
setINISetting VegToolsUI.IniFilePath "VegToolsUI" "Fill" (VegToolsUI.FillSpinner.Text as string)
|
|
setINISetting VegToolsUI.IniFilePath "VegToolsUI" "Inset" (VegToolsUI.InsetSpinner.Text as string)
|
|
setINISetting VegToolsUI.IniFilePath "VegToolsUI" "Slope" (VegToolsUI.SlopeSpinner.Text as string)
|
|
setINISetting VegToolsUI.IniFilePath "VegToolsUI" "RandomRotation" (VegToolsUI.RandomSpinner.Text as string)
|
|
),
|
|
|
|
fn LoadIniFile =
|
|
(
|
|
--default values
|
|
local WinLocX = 100
|
|
local WinLocY = 100
|
|
local WinWidth = 200
|
|
local WinHeight = 200
|
|
local NumSides = 8
|
|
local Fill = 0.8
|
|
local Inset = 0.15
|
|
local Slope = 0.0
|
|
local RandomRotation = 0.0
|
|
|
|
try
|
|
(
|
|
WinLocX = getINISetting VegToolsUI.IniFilePath "VegToolsUI" "WinLocX" as integer
|
|
WinLocY = getINISetting VegToolsUI.IniFilePath "VegToolsUI" "WinLocY" as integer
|
|
WinWidth = getINISetting VegToolsUI.IniFilePath "VegToolsUI" "WinWidth" as integer
|
|
WinHeight = getINISetting VegToolsUI.IniFilePath "VegToolsUI" "WinHeight" as integer
|
|
NumSides = getINISetting VegToolsUI.IniFilePath "VegToolsUI" "NumSides" as integer
|
|
Fill = getINISetting VegToolsUI.IniFilePath "VegToolsUI" "Fill" as float
|
|
Inset = getINISetting VegToolsUI.IniFilePath "VegToolsUI" "Inset" as float
|
|
Slope = getINISetting VegToolsUI.IniFilePath "VegToolsUI" "Slope" as float
|
|
RandomRotation = getINISetting VegToolsUI.IniFilePath "VegToolsUI" "RandomRotation" as float
|
|
)
|
|
|
|
catch()
|
|
|
|
VegToolsUI.Form.Location = dotNetObject "system.drawing.point" WinLocX WinLocY
|
|
VegToolsUI.Form.Size = dotNetObject "System.Drawing.Size" WinWidth WinHeight
|
|
|
|
-- print VegToolsUI.numSidesMin
|
|
-- print VegToolsUI.fillMin
|
|
-- print VegToolsUI.insetMin
|
|
|
|
if (NumSides < VegToolsUI.numSidesMin) then NumSides = 8
|
|
if (Fill < VegToolsUI.fillMin) then Fill = 0.75
|
|
if (Inset < VegToolsUI.insetMin) then Inset = 0.1
|
|
|
|
VegToolsUI.NumSidesSpinner.Value = NumSides
|
|
VegToolsUI.FillSpinner.Value = Fill
|
|
VegToolsUI.InsetSpinner.Value = Inset
|
|
VegToolsUI.SlopeSpinner.Value = Slope
|
|
VegToolsUI.RandomSpinner.Value = RandomRotation
|
|
VegToolsUI.TreePlacement.InitCustomTreeList()
|
|
),
|
|
|
|
------------------------------------------------------------------------------------------------------------------------------------------
|
|
--UI
|
|
------------------------------------------------------------------------------------------------------------------------------------------
|
|
|
|
fn CreateUI =
|
|
(
|
|
-- form setup
|
|
Form = dotNetObject "maxCustomControls.maxForm"
|
|
Form.Text = "Vegetation Tools"
|
|
Form.StartPosition = (dotNetClass "System.Windows.Forms.FormStartPosition").manual
|
|
Form.Location = dotNetObject "system.drawing.point" 200 200
|
|
Form.MaximumSize = dotNetObject "System.Drawing.Size" 230 376
|
|
Form.MinimumSize = dotNetObject "System.Drawing.Size" 230 376
|
|
Form.FormBorderStyle = RS_dotNetPreset.FB_Sizable
|
|
dotNet.AddEventHandler Form "Load" LoadIniFile
|
|
dotNet.AddEventHandler Form "Closing" SaveIniFile
|
|
|
|
--content
|
|
ToolTip = dotnetobject "ToolTip"
|
|
Table = dotNetObject "TableLayoutPanel"
|
|
Table.Dock = RS_dotNetPreset.DS_Fill
|
|
Table.RowCount = 3
|
|
Table.RowStyles.add (RS_dotNetObject.rowStyleObject "absolute" 40) --banner
|
|
Table.RowStyles.add (RS_dotNetObject.rowStyleObject "absolute" 135) --tree base generator
|
|
Table.RowStyles.add (RS_dotNetObject.rowStyleObject "absolute" 116) --tree placement
|
|
Table.RowStyles.add (RS_dotNetObject.rowStyleObject "percent" 100) --info panel
|
|
Table.ColumnCount = 1
|
|
Table.ColumnStyles.add (RS_dotNetObject.columnStyleObject "absolute" 160)
|
|
Table.ColumnStyles.add (RS_dotNetObject.columnStyleObject "percent" 100)
|
|
Table.Margin = RS_dotNetPreset.Padding_None
|
|
Form.Controls.Add Table
|
|
|
|
RSBannerPanel = dotNetObject "System.Windows.Forms.Panel"
|
|
RSBannerPanel.borderstyle = RS_dotNetClass.borderStyleClass.FixedSingle
|
|
RSBannerPanel.dock = RS_dotNetPreset.DS.Fill
|
|
|
|
local banner = makeRsBanner dn_Panel:RSBannerPanel width:395 studio:"london" mail:"andy.davis@rockstarlondon.com" wiki:"Map_Art_Tech"
|
|
banner.setup()
|
|
Table.Controls.Add RSBannerPanel 0 0
|
|
Table.SetColumnSpan RSBannerPanel 2
|
|
|
|
RS_dotNetPreset.Font_Main = dotNetObject "System.Drawing.Font" "Futura" 10
|
|
|
|
-------------------------------------------------------------------------------
|
|
--TREE BASE GENERATOR
|
|
-------------------------------------------------------------------------------
|
|
TreeGenTable = dotNetObject "TableLayoutPanel"
|
|
TreeGenTable.Dock = RS_dotNetPreset.DS_Fill
|
|
TreeGenTable.RowCount = 5
|
|
TreeGenTable.RowStyles.add (RS_dotNetObject.rowStyleObject "absolute" 25)
|
|
TreeGenTable.RowStyles.add (RS_dotNetObject.rowStyleObject "absolute" 25)
|
|
TreeGenTable.RowStyles.add (RS_dotNetObject.rowStyleObject "absolute" 25)
|
|
TreeGenTable.RowStyles.add (RS_dotNetObject.rowStyleObject "absolute" 25)
|
|
TreeGenTable.RowStyles.add (RS_dotNetObject.rowStyleObject "absolute" 25)
|
|
TreeGenTable.ColumnCount = 2
|
|
TreeGenTable.ColumnStyles.add (RS_dotNetObject.columnStyleObject "absolute" 160)
|
|
TreeGenTable.ColumnStyles.add (RS_dotNetObject.columnStyleObject "percent" 100)
|
|
|
|
Table.Controls.Add TreeGenTable 0 1
|
|
|
|
TreeGenLabel = RS_dotNetUI.InitLabel "Tree Base Generator" RS_dotNetPreset.TA.MiddleLeft
|
|
TreeGenLabel.BackColor = this.TitleColor
|
|
TreeGenLabel.Padding = dotNetObject "System.Windows.Forms.Padding" 4
|
|
ToolTip.SetToolTip TreeGenLabel "Create radial geometry for tree bases."
|
|
TreeGenTable.Controls.Add TreeGenLabel 0 0
|
|
TreeGenTable.SetColumnSpan TreeGenLabel 2
|
|
|
|
NumSidesLabel = RS_dotNetUI.InitLabel "Number Of sides" RS_dotNetPreset.TA.MiddleLeft
|
|
NumSidesLabel.Padding = dotNetObject "System.Windows.Forms.Padding" 4
|
|
TreeGenTable.Controls.Add NumSidesLabel 0 1
|
|
|
|
NumSidesSpinner = dotNetObject "NumericUpDown"
|
|
NumSidesSpinner.Dock = RS_dotNetPreset.DS.Fill
|
|
NumSidesSpinner.value = 4
|
|
NumSidesSpinner.Minimum = VegToolsUI.numSidesMin
|
|
NumSidesSpinner.Maximum = 32
|
|
TreeGenTable.Controls.Add NumSidesSpinner 1 1
|
|
|
|
FillLabel = RS_dotNetUI.InitLabel "Fill" RS_dotNetPreset.TA.MiddleLeft
|
|
FillLabel.Padding = dotNetObject "System.Windows.Forms.Padding" 4
|
|
TreeGenTable.Controls.Add FillLabel 0 2
|
|
|
|
FillSpinner = dotNetObject "NumericUpDown"
|
|
FillSpinner.Dock = RS_dotNetPreset.DS.Fill
|
|
FillSpinner.Minimum = VegToolsUI.fillMin
|
|
FillSpinner.Maximum = 0.95
|
|
FillSpinner.Increment = 0.05
|
|
FillSpinner.Value = 0.75
|
|
FillSpinner.DecimalPlaces = 2
|
|
TreeGenTable.Controls.Add FillSpinner 1 2
|
|
|
|
InsetLabel = RS_dotNetUI.InitLabel "Inset" RS_dotNetPreset.TA.MiddleLeft
|
|
InsetLabel.Padding = dotNetObject "System.Windows.Forms.Padding" 4
|
|
TreeGenTable.Controls.Add InsetLabel 0 3
|
|
|
|
InsetSpinner = dotNetObject "NumericUpDown"
|
|
InsetSpinner.Dock = RS_dotNetPreset.DS.Fill
|
|
InsetSpinner.Minimum = VegToolsUI.insetMin
|
|
InsetSpinner.Maximum = 0.2
|
|
InsetSpinner.Increment = 0.05
|
|
InsetSpinner.Value = 0.1
|
|
InsetSpinner.DecimalPlaces = 2
|
|
TreeGenTable.Controls.Add InsetSpinner 1 3
|
|
|
|
TreeGenButton = RS_dotNetUI.InitButton "Generate Tree Base"
|
|
TreeGenButton.Margin = this.ButtonPadding
|
|
dotNet.AddEventHandler TreeGenButton "Click" GenerateTreeBase
|
|
TreeGenTable.SetColumnSpan TreeGenButton 2
|
|
TreeGenTable.Controls.Add TreeGenButton 0 4
|
|
|
|
-------------------------------------------------------------------------------
|
|
--TREE PLACEMENT
|
|
-------------------------------------------------------------------------------
|
|
TreePlacementTable = dotNetObject "TableLayoutPanel"
|
|
TreePlacementTable.Dock = RS_dotNetPreset.DS_Fill
|
|
TreePlacementTable.RowCount = 4
|
|
TreePlacementTable.RowStyles.add (RS_dotNetObject.rowStyleObject "absolute" 28)
|
|
TreePlacementTable.RowStyles.add (RS_dotNetObject.rowStyleObject "absolute" 28)
|
|
TreePlacementTable.RowStyles.add (RS_dotNetObject.rowStyleObject "absolute" 28)
|
|
TreePlacementTable.RowStyles.add (RS_dotNetObject.rowStyleObject "absolute" 28)
|
|
TreePlacementTable.ColumnCount = 2
|
|
TreePlacementTable.ColumnStyles.add (RS_dotNetObject.columnStyleObject "absolute" 160)
|
|
TreePlacementTable.ColumnStyles.add (RS_dotNetObject.columnStyleObject "percent" 100)
|
|
Table.Controls.Add TreePlacementTable 0 2
|
|
|
|
TreePlacementLabel = RS_dotNetUI.InitLabel "Tree Placement" RS_dotNetPreset.TA.MiddleLeft
|
|
TreePlacementLabel.Padding = dotNetObject "System.Windows.Forms.Padding" 4
|
|
TreePlacementLabel.BackColor = this.TitleColor
|
|
ToolTip.SetToolTip TreePlacementLabel "Vertically place trees on ground planes below."
|
|
TreePlacementTable.Controls.Add TreePlacementLabel 0 0
|
|
TreePlacementTable.SetColumnSpan TreePlacementLabel 2
|
|
|
|
SlopeLabel = RS_dotNetUI.InitLabel "Inherit Slope Angle" RS_dotNetPreset.TA.MiddleLeft
|
|
SlopeLabel.Padding = dotNetObject "System.Windows.Forms.Padding" 4
|
|
TreePlacementTable.Controls.Add SlopeLabel 0 1
|
|
|
|
SlopeSpinner = dotNetObject "NumericUpDown"
|
|
SlopeSpinner.Dock = RS_dotNetPreset.DS.Fill
|
|
SlopeSpinner.value = 0
|
|
SlopeSpinner.Minimum = 0
|
|
SlopeSpinner.Maximum = 1
|
|
SlopeSpinner.Increment = 0.1
|
|
SlopeSpinner.DecimalPlaces = 2
|
|
TreePlacementTable.Controls.Add SlopeSpinner 1 1
|
|
|
|
RandomLabel = RS_dotNetUI.InitLabel "Random Rotation" RS_dotNetPreset.TA.MiddleLeft
|
|
RandomLabel.Padding = dotNetObject "System.Windows.Forms.Padding" 4
|
|
TreePlacementTable.Controls.Add RandomLabel 0 2
|
|
|
|
RandomSpinner = dotNetObject "NumericUpDown"
|
|
RandomSpinner.Dock = RS_dotNetPreset.DS.Fill
|
|
RandomSpinner.value = 0
|
|
RandomSpinner.Minimum = 0
|
|
RandomSpinner.Maximum = 1
|
|
RandomSpinner.Increment = 0.1
|
|
RandomSpinner.DecimalPlaces = 2
|
|
TreePlacementTable.Controls.Add RandomSpinner 1 2
|
|
|
|
TreePlacementButton = RS_dotNetUI.InitButton "Place Selected Trees"
|
|
TreePlacementButton.Margin = this.ButtonPadding
|
|
dotNet.AddEventHandler TreePlacementButton "Click" PlaceTrees
|
|
TreePlacementTable.Controls.Add TreePlacementButton 0 3
|
|
TreePlacementTable.SetColumnSpan TreePlacementButton 2
|
|
|
|
-------------------------------------------------------------------------------
|
|
--INFO PANEL
|
|
-------------------------------------------------------------------------------
|
|
|
|
InfoPanel = RS_dotNetUI.InitLabel "Vegetation tools" RS_dotNetPreset.TA.MiddleLeft
|
|
InfoPanel.Padding = dotNetObject "System.Windows.Forms.Padding" 8
|
|
InfoPanel.BackColor = RS_dotNetPreset.ColorClass.black
|
|
Table.Controls.Add InfoPanel 0 3
|
|
|
|
--draw form
|
|
Form.ShowModeless()
|
|
Form
|
|
)
|
|
)
|
|
|
|
if VegToolsUI != undefined then
|
|
VegToolsUI.Form.Close()
|
|
|
|
VegToolsUI = VegetationToolsUI()
|
|
VegToolsUI.CreateUI() |