1045 lines
29 KiB
Plaintext
Executable File
1045 lines
29 KiB
Plaintext
Executable File
global gRsZoneViewData, gRsZoneViewFuncs
|
|
|
|
callbacks.removeScripts id:#RsZoneView
|
|
|
|
if (gRsZoneViewData != undefined) do
|
|
(
|
|
RsZoneViewFuncs.CloseTool()
|
|
)
|
|
|
|
-- Struct holding data and control-links for tool:
|
|
struct RsZoneViewData
|
|
(
|
|
ToolName = "PopZone Viewer",
|
|
|
|
VersionNum = 1.06,
|
|
VersionName = "Rhetorical Sun",
|
|
|
|
ToolWidth = 700, ToolHeight = 400,
|
|
|
|
zoneDataFolder = (RsConfigGetCommonDir core:True) + "data/levels/" + (RsConfigGetProjectName core:True),
|
|
zonebindPath = zoneDataFolder + "/zonebind.meta",
|
|
popZonePath = zoneDataFolder + "/popzone.ipl",
|
|
|
|
ToolDialog = undefined,
|
|
ItemListCtrl = undefined,
|
|
SelectTimer = undefined,
|
|
|
|
DoObjects = True,
|
|
ViewLabels = True,
|
|
|
|
ShowPlantIdxClr = False,
|
|
ShowDirtClr = False,
|
|
ShowAreaClr = True,
|
|
|
|
DrawWireframe = False,
|
|
|
|
PopZonesList = #(),
|
|
|
|
ZoneTypeList = (filterString (GetControlData "RsPopZone" "Zone type") ","),
|
|
|
|
-- Colours to use when colouring zones by plantsMgrTxdIdx:
|
|
-- 0 = nothing - gray
|
|
-- 1 = countryside - green
|
|
-- 2 = ocean - so blue
|
|
-- 3 = Not used yet - bright pink
|
|
-- 4 = Not used yet - bright pink
|
|
-- 5 = Not used yet - bright pink
|
|
-- 6 = Not used yet - bright pink
|
|
-- 7 = Default, memory hungry, so RED
|
|
plantsMgrClrs = #((color 180 180 180), (color 0 180 0), (color 0 0 180), (red + blue), (red + blue), (red + blue), (red + blue), (red))
|
|
)
|
|
|
|
-- Struct used to hold data for individual popZones:
|
|
struct popZoneStruct
|
|
(
|
|
name, obj, meshNode, meta, boxMin, boxMax, boxSize, boxVol, boxArea, areaName, zoneType=0, dirtColour=(red + blue), subBoxes = #(),
|
|
vfxRegion="", plantsIdx=7,
|
|
listCtrlRow,
|
|
|
|
-- Return values for building list-rows:
|
|
fn GetListLabels = #("Zone Name", "Zone Type", "Area Name", "VFX Region", "PlantsMgrTxdIdx", "Has Metadata"),
|
|
fn GetRowStrings =
|
|
(
|
|
local zoneName = This.Name
|
|
local zoneTypeStr = gRsZoneViewData.ZoneTypeList[This.ZoneType + 1]
|
|
local zoneArea = This.AreaName
|
|
local hasMeta = (This.Meta != undefined)
|
|
|
|
return #(zoneName, zoneTypeStr, zoneArea, vfxRegion, plantsIdx, hasMeta)
|
|
),
|
|
|
|
fn getMetaAttrib attribName =
|
|
(
|
|
if (meta == undefined) or not (meta.ContainsKey attribName) do return undefined
|
|
return (meta.Item attribName).Value
|
|
),
|
|
|
|
fn getDirtColour useMeta:meta =
|
|
(
|
|
local vals = for attribName in #("dirtRed", "dirtGreen", "dirtBlue") collect
|
|
(
|
|
(useMeta.Item attribName).Value as integer
|
|
)
|
|
|
|
color vals[1] vals[2] vals[3]
|
|
),
|
|
|
|
-- Return colour to use for object:
|
|
fn UseObjColour =
|
|
(
|
|
case of
|
|
(
|
|
(gRsZoneViewData.ShowPlantIdxClr):(gRsZoneViewData.plantsMgrClrs[plantsIdx + 1])
|
|
(gRsZoneViewData.ShowDirtClr):(dirtColour)
|
|
Default: --(gRsZoneViewData.ShowAreaClr):
|
|
(
|
|
-- Set colour-seed based on area-name, to give each area same colour:
|
|
seed (getHashValue (toLower areaName) 1)
|
|
RsGetRandomColour()
|
|
)
|
|
)
|
|
),
|
|
|
|
fn generateObj = undo off
|
|
(
|
|
if (subBoxes.count == 0) do return undefined
|
|
|
|
local objName = (areaName + ":" + name)
|
|
|
|
local zoneSize = boxMax - boxMin
|
|
local zonePos = boxMin + [zoneSize.x / 2, zoneSize.y / 2, 0]
|
|
local colour = UseObjColour()
|
|
|
|
obj = (Editable_Mesh name:objName wireColor:colour pos:ZonePos backFaceCull:True)
|
|
|
|
-- Set transform-locks on obj:
|
|
setTransformLockFlags obj #{1..9}
|
|
|
|
if (meshNode == undefined) do
|
|
(
|
|
local vertPosList = #()
|
|
local faceVertLists = #()
|
|
|
|
for item in subBoxes do
|
|
(
|
|
local subBoxMin = item.boxMin
|
|
local subBoxMax = item.boxMax
|
|
local subBoxSize = (subBoxMax - subBoxMin)
|
|
|
|
subBoxMin.Z = 0
|
|
subBoxMax.Z = 0
|
|
|
|
local corners = #(subBoxMin, [subBoxMax.X, subBoxMin.Y, 0], subBoxMax, [subBoxMin.X, subBoxMax.Y, 0])
|
|
|
|
local faceVerts = for cornerPos in corners collect
|
|
(
|
|
local vertNum = findItem vertPosList cornerPos
|
|
|
|
if (vertNum == 0) do
|
|
(
|
|
append vertPosList cornerPos
|
|
vertNum = vertPosList.count
|
|
)
|
|
|
|
vertNum
|
|
)
|
|
|
|
append faceVertLists [faceVerts[1], faceVerts[2], faceVerts[3]]
|
|
append faceVertLists [faceVerts[1], faceVerts[3], faceVerts[4]]
|
|
)
|
|
|
|
-- Create a mesh from the loaded data:
|
|
local newMesh = TriMesh()
|
|
setMesh newMesh vertices:vertPosList faces:faceVertLists
|
|
|
|
if (subBoxes.count > 1) then
|
|
(
|
|
-- Optimise generated mesh:
|
|
meshop.optimize newMesh 0.1 1.0 0.0 0.0 saveMatBoundries:false saveSmoothBoundries:false autoEdge:true
|
|
)
|
|
else
|
|
(
|
|
-- Hide middle edges:
|
|
setEdgeVis newMesh 1 3 False
|
|
setEdgeVis newMesh 2 1 False
|
|
)
|
|
|
|
-- Move verts:
|
|
meshop.moveVert newMesh #all -ZonePos
|
|
|
|
-- Invert faces, if using wireframe-mode:
|
|
if gRsZoneViewData.DrawWireframe do
|
|
(
|
|
meshop.flipNormals newMesh #all
|
|
)
|
|
|
|
-- Store mesh seperately for easy retrieval:
|
|
meshNode = (createInstance Editable_Mesh)
|
|
meshNode.mesh = newMesh
|
|
)
|
|
|
|
-- Retrieve previously-generated mesh:
|
|
obj.mesh = (copy meshNode.mesh)
|
|
|
|
return objzZ
|
|
)
|
|
)
|
|
|
|
struct RsZoneViewFuncs
|
|
(
|
|
fn SetStatusTitle PromptText DoPushPrompt:False =
|
|
(
|
|
local NewText = gRsZoneViewData.ToolName + (if (PromptText == "") then "" else (": " + PromptText))
|
|
|
|
gRsZoneViewData.ToolDialog.Text = NewText
|
|
|
|
if DoPushPrompt do
|
|
(
|
|
PushPrompt PromptText
|
|
)
|
|
|
|
return OK
|
|
),
|
|
|
|
fn SelectCallback =
|
|
(
|
|
--print "SELECTY"
|
|
-- Focus on ItemList control:
|
|
local ItemListCtrl = gRsZoneViewData.ItemListCtrl
|
|
ItemListCtrl.Focus()
|
|
|
|
-- Make sure deferred-selection timer is stopped:
|
|
gRsZoneViewData.SelectTimer.Stop()
|
|
|
|
-- Update list-selections:
|
|
local showFirstRow = True
|
|
for item in gRsZoneViewData.PopZonesList do
|
|
(
|
|
local newSel = (isValidNode item.obj) and (item.obj.isSelected)
|
|
|
|
if (item.listCtrlRow.Selected != newSel) do
|
|
(
|
|
item.listCtrlRow.Selected = newSel
|
|
|
|
if newSel and showFirstRow do
|
|
(
|
|
ItemListCtrl.CurrentCell = item.listCtrlRow.Cells.Item[0]
|
|
showFirstRow = False
|
|
)
|
|
)
|
|
)
|
|
|
|
-- Stop timer again (it'll have been started by the selection-changing above)
|
|
gRsZoneViewData.SelectTimer.Stop()
|
|
|
|
return OK
|
|
),
|
|
|
|
fn genMissingObjs popZones: =
|
|
(
|
|
if (popZones == unsupplied) do
|
|
(
|
|
popZones = gRsZoneViewData.PopZonesList
|
|
)
|
|
|
|
local regenItems = for item in popZones where (not isValidNode item.obj) collect item
|
|
|
|
if (regenItems.count != 0) do
|
|
(
|
|
SetStatusTitle "Generating Zone Meshes..." DoPushPrompt:True
|
|
|
|
--local TimeStart = TimeStamp()
|
|
for item in regenItems do
|
|
(
|
|
item.generateObj()
|
|
)
|
|
completeRedraw()
|
|
--format "Time to generate: %s\n" ((TimeStamp() - TimeStart) / 1000)
|
|
|
|
popPrompt()
|
|
)
|
|
|
|
return OK
|
|
),
|
|
|
|
fn deleteObjs = undo off
|
|
(
|
|
local popZones = gRsZoneViewData.PopZonesList
|
|
|
|
local delObjs = for item in popZones where (isValidNode item.obj) collect item.obj
|
|
if (delObjs.count != 0) do
|
|
(
|
|
delete delObjs
|
|
)
|
|
),
|
|
|
|
fn preSaveCallback =
|
|
(
|
|
-- Remove callbacks and objects during save:
|
|
gRsZoneViewFuncs.RemoveCallbacks()
|
|
gRsZoneViewFuncs.DeleteObjs()
|
|
callbacks.addScript #filePostSaveProcess "gRsZoneViewFuncs.postSaveCallback()" id:#RsZoneView
|
|
),
|
|
fn postSaveCallback =
|
|
(
|
|
gRsZoneViewFuncs.GenMissingObjs()
|
|
gRsZoneViewFuncs.AddCallbacks()
|
|
),
|
|
|
|
-- Called to close the dialog and clear data-struct:
|
|
fn CloseTool =
|
|
(
|
|
--print "CloseTool"
|
|
if (gRsZoneViewData != undefined) and (gRsZoneViewData.ToolDialog != undefined) do
|
|
(
|
|
gRsZoneViewData.ToolDialog.Close()
|
|
)
|
|
|
|
gRsZoneViewData = undefined
|
|
|
|
return OK
|
|
),
|
|
|
|
-- Called when viewport redraws:
|
|
fn viewportDraw =
|
|
(
|
|
local ToolDialog = if (gRsZoneViewData == undefined) then undefined else gRsZoneViewData.ToolDialog
|
|
|
|
if (ToolDialog == undefined) or (not ToolDialog.Visible) do
|
|
(
|
|
gRsZoneViewFuncs.removeCallbacks()
|
|
)
|
|
|
|
if not (gRsZoneViewData.ViewLabels) do return False
|
|
|
|
local drawClr = White
|
|
gw.setTransform (Matrix3 1)
|
|
|
|
for item in gRsZoneViewData.PopZonesList where (isValidNode item.obj) and (item.listCtrlRow.Selected) do
|
|
(
|
|
local pos = (gw.wtransPoint item.obj.pos)
|
|
|
|
gw.wMarker pos #hollowBox color:drawClr
|
|
pos.X += 2
|
|
pos.Y += 8
|
|
gw.wtext pos (" zone: " + item.name) color:drawClr
|
|
pos.X += 2
|
|
pos.Y += 12
|
|
gw.wtext pos (" area: " + item.areaName) color:drawClr
|
|
)
|
|
|
|
gw.enlargeUpdateRect #whole
|
|
gw.updateScreen()
|
|
|
|
return OK
|
|
),
|
|
|
|
fn RemoveCallbacks =
|
|
(
|
|
callbacks.removeScripts id:#RsZoneView
|
|
unregisterRedrawViewsCallback viewportDraw
|
|
),
|
|
|
|
fn AddCallbacks =
|
|
(
|
|
RemoveCallbacks()
|
|
|
|
callbacks.addScript #selectionSetChanged "gRsZoneViewFuncs.SelectCallback()" id:#RsZoneView
|
|
callbacks.addScript #nodePostDelete "gRsZoneViewFuncs.genMissingObjs()" id:#RsZoneView
|
|
callbacks.addScript #filePreSaveProcess "gRsZoneViewFuncs.preSaveCallback()" id:#RsZoneView
|
|
|
|
callbacks.addScript #filePreOpenProcess "gRsZoneViewFuncs.closeTool()" id:#RsZoneView
|
|
callbacks.addScript #preSystemShutdown "gRsZoneViewFuncs.closeTool()" id:#RsZoneView
|
|
callbacks.addScript #systemPreReset "gRsZoneViewFuncs.closeTool()" id:#RsZoneView
|
|
callbacks.addScript #systemPreNew "gRsZoneViewFuncs.closeTool()" id:#RsZoneView
|
|
|
|
registerRedrawViewsCallback viewportDraw
|
|
),
|
|
|
|
fn LoadPopZones =
|
|
(
|
|
gRsZoneViewData.popZonesList = #()
|
|
local popZonesList = gRsZoneViewData.popZonesList
|
|
|
|
local zonebindPath = gRsZoneViewData.zonebindPath
|
|
local popZonePath = gRsZoneViewData.popZonePath
|
|
|
|
local doObjects = gRsZoneViewData.doObjects
|
|
|
|
format "%\n" zonebindPath
|
|
format "%\n" popZonePath
|
|
SetStatusTitle "Perforce Sync..."
|
|
gRsPerforce.sync #(zonebindPath, popZonePath)
|
|
|
|
if not doesFileExist zonebindPath do
|
|
(
|
|
print ("zonebind.meta doesn't exist!\n" + zonebindPath)
|
|
return false
|
|
)
|
|
if not doesFileExist popZonePath do
|
|
(
|
|
print ("popzone.ipl doesn't exist!\n" + popZonePath)
|
|
return false
|
|
)
|
|
|
|
-- Read in PopZone.ipl:
|
|
(
|
|
SetStatusTitle "Reading PopZone.ipl..." DoPushPrompt:True
|
|
|
|
local popzoneFile = openFile popZonePath
|
|
skipToString popzoneFile "zone"
|
|
|
|
local continueReading = True
|
|
while continueReading and (not eof popzoneFile) do
|
|
(
|
|
local thisLine = readline popzoneFile
|
|
local lineTokens = filterString thisLine ", \t"
|
|
|
|
case of
|
|
(
|
|
(lineTokens.count == 0):()
|
|
(lineTokens[1] == "end"):(continueReading = False)
|
|
Default:
|
|
(
|
|
local zoneName = (toLower lineTokens[1])
|
|
|
|
local popZone = popZoneStruct name:zoneName
|
|
|
|
-- Load sizes:
|
|
popZone.boxMin = [lineTokens[2] as float, lineTokens[3] as float, lineTokens[4] as float]
|
|
popZone.boxMax = [lineTokens[5] as float, lineTokens[6] as float, lineTokens[7] as float]
|
|
|
|
popZone.areaName = (lineTokens[8] as string)
|
|
popZone.zoneType = (lineTokens[9] as integer)
|
|
|
|
local boxSize = (popZone.boxMax - popZone.boxMin)
|
|
popZone.boxVol = (boxSize.X * boxSize.Y * boxSize.Z)
|
|
popZone.boxArea = (boxSize.X * boxSize.Y)
|
|
|
|
-- Add popzone to list:
|
|
append popZonesList popZone
|
|
)
|
|
)
|
|
)
|
|
|
|
close popzoneFile
|
|
|
|
popPrompt()
|
|
)
|
|
|
|
-- Read in ZoneBind.meta:
|
|
if doObjects do
|
|
(
|
|
SetStatusTitle "Reading ZoneBind.meta..." DoPushPrompt:True
|
|
|
|
local metaManager = RsGetMetaDataManager()
|
|
metaManager.LoadWithMetaFile zonebindPath
|
|
|
|
local zoneList = metaManager.FindFirstStructureNamed "zones"
|
|
for zoneIdx = 0 to (zoneList.length - 1) do
|
|
(
|
|
local zoneNode = zoneList.Item zoneIdx
|
|
local zoneName = toLower (zoneNode.Item "zoneName").Value
|
|
|
|
-- Find PopZone(s) with matching name:
|
|
local theseZones = for popZone in popZonesList where (popZone.name == zoneName) collect popZone
|
|
|
|
if (theseZones.count != 0) do
|
|
(
|
|
local dirtColour = popZoneStruct.getDirtColour useMeta:zoneNode
|
|
|
|
theseZones.meta = zoneNode
|
|
theseZones.dirtColour = dirtColour
|
|
)
|
|
|
|
if (zoneNode.ContainsKey "vfxRegion") do
|
|
(
|
|
theseZones.vfxRegion = (zoneNode.Item "vfxRegion").Value
|
|
)
|
|
if (zoneNode.ContainsKey "plantsMgrTxdIdx") do
|
|
(
|
|
theseZones.plantsIdx = (zoneNode.Item "plantsMgrTxdIdx").Value
|
|
)
|
|
)
|
|
|
|
popPrompt()
|
|
)
|
|
|
|
-- Sorts zones from smallest to largest (smallest one is used in-game when zones overlap)
|
|
fn sortZoneVols v1 v2 =
|
|
(
|
|
case of
|
|
(
|
|
(v1.boxVol < v2.boxVol):-1
|
|
(v1.boxVol > v2.boxVol):1
|
|
Default:0
|
|
)
|
|
)
|
|
|
|
local BoxHashes = #()
|
|
|
|
-- Find groups of intersecting zones, and chop those up into sub-zone boxes:
|
|
if doObjects do
|
|
(
|
|
local intersectZones = #()
|
|
local intersectTested = #{}
|
|
intersectTested.count = popZonesList.count
|
|
|
|
local Cancelled = False
|
|
|
|
local zoneCount = popZonesList.count
|
|
|
|
for initialZoneNum = 1 to zoneCount where not intersectTested[initialZoneNum] while (not Cancelled) do
|
|
(
|
|
SetStatusTitle "Finding intersecting zones..." DoPushPrompt:True
|
|
|
|
local theseIntersectNums = #(initialZoneNum)
|
|
local theseIntersectBits = #{initialZoneNum}
|
|
local intersectZoneIdx = 0
|
|
|
|
while (intersectZoneIdx < theseIntersectNums.count) and (not Cancelled) do
|
|
(
|
|
--format "% < %; %\n" intersectZoneIdx theseIntersectNums.count (intersectTested as string)
|
|
intersectZoneIdx += 1
|
|
|
|
local intersectZoneNum = theseIntersectNums[intersectZoneIdx]
|
|
local thisIntersectZone = popZonesList[intersectZoneNum]
|
|
intersectTested[intersectZoneNum] = True
|
|
|
|
-- Test 'thisIntersectZone' against all zones that haven't been tested yet:
|
|
for testZoneNum = 1 to zoneCount where not (intersectTested[testZoneNum] or theseIntersectBits[testZoneNum]) do
|
|
(
|
|
local testZone = popZonesList[testZoneNum]
|
|
|
|
-- If zones intersect, add it to 'theseIntersectNums':
|
|
if (
|
|
(testZone.boxMin.X < thisIntersectZone.boxMax.X) and (testZone.boxMax.X > thisIntersectZone.boxMin.X) and
|
|
(testZone.boxMin.Y < thisIntersectZone.boxMax.Y) and (testZone.boxMax.Y > thisIntersectZone.boxMin.Y)
|
|
) do
|
|
(
|
|
append theseIntersectNums testZoneNum
|
|
theseIntersectBits[testZoneNum] = True
|
|
)
|
|
)
|
|
|
|
Cancelled = keyboard.escPressed
|
|
)
|
|
|
|
PopPrompt()
|
|
|
|
if (theseIntersectNums.count == 1) then
|
|
(
|
|
-- Single box that doesn't intersect anything:
|
|
local thisZone = popZonesList[initialZoneNum]
|
|
append thisZone.subBoxes (dataPair boxMin:thisZone.boxMin boxMax:thisZone.boxMax)
|
|
)
|
|
else
|
|
(
|
|
SetStatusTitle "Gridding Zones into sub-boxes..." DoPushPrompt:True
|
|
|
|
-- Sort cluster of intersecting zones by volume:
|
|
-- (smaller zone is used if point is in multiple zones)
|
|
local foundZones = for zoneNum in theseIntersectNums collect popZonesList[zoneNum]
|
|
qsort foundZones sortZoneVols
|
|
|
|
-- Build lists of box-edge x/y values:
|
|
local xEdges = #()
|
|
local yEdges = #()
|
|
|
|
for popZone in foundZones do
|
|
(
|
|
join xEdges #(popZone.boxMin.X, popZone.boxMax.X)
|
|
join yEdges #(popZone.boxMin.Y, popZone.boxMax.Y)
|
|
)
|
|
|
|
-- Make values unique, sort:
|
|
xEdges = (makeUniqueArray xEdges)
|
|
yEdges = (makeUniqueArray yEdges)
|
|
sort xEdges
|
|
sort yEdges
|
|
|
|
-- Chop each zone up into unique sub-boxes:
|
|
for ThisZone in FoundZones while (not Cancelled) do
|
|
(
|
|
local ZoneMinX = ThisZone.boxMin.X
|
|
local ZoneMaxX = ThisZone.boxMax.X
|
|
local ZoneMinY = ThisZone.boxMin.Y
|
|
local ZoneMaxY = ThisZone.boxMax.Y
|
|
|
|
local ZoneXEdges = for Val in xEdges where (Val >= ZoneMinX) while (Val <= ZoneMaxX) collect Val
|
|
local ZoneYEdges = for Val in yEdges where (Val >= ZoneMinY) while (Val <= ZoneMaxY) collect Val
|
|
|
|
for y = 1 to (ZoneYEdges.count - 1) do
|
|
(
|
|
local minVal = [0, ZoneYEdges[y], 0]
|
|
local maxVal = [0, ZoneYEdges[y + 1], 0]
|
|
|
|
for x = 1 to (ZoneXEdges.count - 1) do
|
|
(
|
|
minVal.x = ZoneXEdges[x]
|
|
maxVal.x = ZoneXEdges[x + 1]
|
|
|
|
local hashArrayIdx = ((abs (0.1 * minVal.X) as integer) + 1)
|
|
local hashArray = boxHashes[hashArrayIdx]
|
|
|
|
-- Collect box, if similar one hasn't already been used:
|
|
local isUnique = True
|
|
local boxHash = GetHashValue #(minVal, maxVal) 1
|
|
local hashArray = boxHashes[hashArrayIdx]
|
|
|
|
if (hashArray == undefined) then
|
|
(
|
|
boxHashes[hashArrayIdx] = #(boxHash)
|
|
)
|
|
else
|
|
(
|
|
isUnique = (appendIfUnique hashArray boxHash)
|
|
)
|
|
|
|
if isUnique do
|
|
(
|
|
append ThisZone.SubBoxes (DataPair boxMin:(copy minVal) boxMax:(copy maxVal))
|
|
)
|
|
)
|
|
)
|
|
|
|
Cancelled = keyboard.escPressed
|
|
)
|
|
|
|
-- Dispose of hash-array data...
|
|
for Item in boxHashes where (isKindOf Item Array) do
|
|
(
|
|
Item.Count == 0
|
|
)
|
|
|
|
PopPrompt()
|
|
)
|
|
|
|
PopPrompt()
|
|
)
|
|
)
|
|
|
|
BoxHashes.Count = 0
|
|
|
|
return True
|
|
),
|
|
|
|
-----------------------------
|
|
-- CONTROL EVENTS: --
|
|
-----------------------------
|
|
|
|
-- Event: Triggered by "Draw Labels" tickybox
|
|
fn ShowLabel_Changed Sender Args =
|
|
(
|
|
gRsZoneViewData.ViewLabels = Sender.Checked
|
|
CompleteRedraw()
|
|
|
|
-- Make sure list-selection is retained:
|
|
gRsZoneViewFuncs.SelectCallback()
|
|
),
|
|
|
|
-- Event: Triggered by "Wireframe" tickybox
|
|
fn Wireframe_Changed Sender Args =
|
|
(
|
|
gRsZoneViewData.DrawWireframe = Sender.Checked
|
|
|
|
-- Flip faces to show Wireframe border:
|
|
for ThisZone in gRsZoneViewData.PopZonesList do
|
|
(
|
|
Meshop.FlipNormals ThisZone.MeshNode.Mesh #all
|
|
ThisZone.Obj.Mesh = (copy ThisZone.MeshNode.Mesh)
|
|
)
|
|
|
|
-- Inverted-faces trick needs 'Edge Faces' to be active:
|
|
if gRsZoneViewData.DrawWireframe do
|
|
(
|
|
viewport.SetShowEdgeFaces True
|
|
)
|
|
|
|
CompleteRedraw()
|
|
|
|
-- Make sure list-selection is retained:
|
|
gRsZoneViewFuncs.SelectCallback()
|
|
),
|
|
|
|
-- Event: Triggered when radiobuttons are clicked:
|
|
fn ShowClrBtn_Changed Sender Args =
|
|
(
|
|
-- Which button was clicked?
|
|
local btnList = Sender.Tag.Value
|
|
local btnIdx = (findItem btnList Sender)
|
|
|
|
local newStates = #{btnIdx}
|
|
|
|
-- Set states:
|
|
gRsZoneViewData.ShowPlantIdxClr = newStates[1]
|
|
gRsZoneViewData.ShowDirtClr = newStates[2]
|
|
gRsZoneViewData.ShowAreaClr = newStates[3]
|
|
|
|
-- Set object wirecolours to match new state:
|
|
for Item in gRsZoneViewData.PopZonesList where (isValidNode Item.Obj) do
|
|
(
|
|
Item.Obj.WireColor = (Item.UseObjColour())
|
|
)
|
|
),
|
|
|
|
-- Event: Selects objects after timer interval:
|
|
fn SelectTimer_Tick Sender Args =
|
|
(
|
|
--print "SelectTimer_Tick"
|
|
Sender.Stop()
|
|
|
|
gRsZoneViewFuncs.removeCallbacks()
|
|
|
|
local zoneList = gRsZoneViewData.PopZonesList
|
|
|
|
local selObjs = for item in zoneList where (item.listCtrlRow.Selected) and (isValidNode item.obj) collect (item.obj)
|
|
|
|
if (selObjs.count != 0) do
|
|
(
|
|
select selObjs
|
|
max tool ZoomExtents
|
|
)
|
|
|
|
gRsZoneViewFuncs.addCallbacks()
|
|
),
|
|
|
|
-- Event: Called when ItemListCtrl is clicked - brings up rightclick menu:
|
|
fn ItemList_Clicked Sender Args =
|
|
(
|
|
if (args.RowIndex < 0) do return false
|
|
|
|
local rightClick = args.button.equals args.button.right
|
|
|
|
if rightClick do
|
|
(
|
|
-- Exclusive-select row if it's not currently selected:
|
|
local clickRow = Sender.Rows.Item[args.RowIndex]
|
|
if not clickRow.Selected do
|
|
(
|
|
sender.ClearSelection()
|
|
clickRow.Selected = true
|
|
)
|
|
|
|
-- Rightclick menu:
|
|
rcmenu RSmenu_dialogList
|
|
(
|
|
local ItemListCtrl, SelRows
|
|
fn HasSel = (SelRows.Count != 0)
|
|
|
|
menuItem itmCopy "Copy selected to clipboard" filter:HasSel
|
|
|
|
on itmCopy picked do
|
|
(
|
|
-- Build text-list for copying to clipboard:
|
|
local copyText = stringStream ""
|
|
|
|
for SelRowNum = 1 to SelRows.Count do
|
|
(
|
|
local Row = SelRows[SelRowNum]
|
|
|
|
for ColNum = 1 to Row.Cells.Count do
|
|
(
|
|
format "%" row.cells.item[ColNum - 1].value to:copyText
|
|
|
|
if (ColNum != Row.Cells.Count) do
|
|
(
|
|
format ", " to:copyText
|
|
)
|
|
)
|
|
|
|
if selRowNum != SelRows.Count do
|
|
(
|
|
format "\n" to:copyText
|
|
)
|
|
)
|
|
|
|
setclipboardText (copyText as string)
|
|
)
|
|
|
|
on RSmenu_dialogList open do
|
|
(
|
|
ItemListCtrl = gRsZoneViewData.ItemListCtrl
|
|
|
|
SelRows = (for n = 0 to (ItemListCtrl.SelectedRows.count - 1) collect ItemListCtrl.SelectedRows.Item[n])
|
|
)
|
|
)
|
|
popUpMenu RSmenu_dialogList
|
|
)
|
|
),
|
|
|
|
-- Event: Triggered when list-selection changes:
|
|
fn ItemList_SelChanged Sender Args =
|
|
(
|
|
--print "ItemList_SelChanged"
|
|
|
|
-- Reset/start action-deferrer timer:
|
|
local selectTimer = gRsZoneViewData.SelectTimer
|
|
selectTimer.Stop()
|
|
selectTimer.Start()
|
|
),
|
|
|
|
-- Event: Clears list-selection when the form is activated:
|
|
fn ToolDialog_Activated sender args =
|
|
(
|
|
gRsZoneViewData.ItemListCtrl.clearSelection()
|
|
),
|
|
|
|
-- Event: Triggered when ToolDialog is closed
|
|
fn ToolDialog_Close Sender Args =
|
|
(
|
|
--print "ToolDialog_Close"
|
|
gRsZoneViewFuncs.RemoveCallbacks()
|
|
|
|
-- Kill deferred-selection timer:
|
|
gRsZoneViewData.SelectTimer.Dispose()
|
|
|
|
gRsZoneViewFuncs.deleteObjs()
|
|
|
|
gRsZoneViewData.ToolDialog.Dispose()
|
|
gRsZoneViewData.ToolDialog = undefined
|
|
),
|
|
|
|
-----------------------------
|
|
-- /CONTROL EVENTS --
|
|
-----------------------------
|
|
|
|
fn CreateTool =
|
|
(
|
|
-- Add deferred-action selector-timer:
|
|
(
|
|
local SelectTimer = dotNetObject "Timer"
|
|
gRsZoneViewData.SelectTimer = SelectTimer
|
|
SelectTimer.Tag = ItemListCtrl
|
|
SelectTimer.interval = 200
|
|
dotNet.addEventHandler SelectTimer "Tick" SelectTimer_Tick
|
|
)
|
|
|
|
-- Define form:
|
|
(
|
|
--DotNet properties
|
|
local DockStyle_Fill = (dotNetClass "DockStyle").Fill
|
|
local SizeType_Absolute = (dotNetClass "SizeType").Absolute
|
|
local SizeType_Percent = (dotNetClass "SizeType").Percent
|
|
|
|
local ToolDialog = (dotNetObject "MaxCustomControls.MaxForm")
|
|
gRsZoneViewData.ToolDialog = ToolDialog
|
|
|
|
SetStatusTitle ""
|
|
ToolDialog.Width = gRsZoneViewData.ToolWidth
|
|
ToolDialog.Height = gRsZoneViewData.ToolHeight
|
|
|
|
-- Make list-dialog resizable:
|
|
ToolDialog.FormBorderStyle = ToolDialog.FormBorderStyle.Sizable
|
|
|
|
ToolDialog.MinimizeBox = false
|
|
ToolDialog.MaximizeBox = false
|
|
ToolDialog.StartPosition = ToolDialog.StartPosition.CenterScreen
|
|
|
|
dotNet.addEventHandler ToolDialog "Activated" ToolDialog_Activated
|
|
dotNet.addEventHandler ToolDialog "FormClosing" ToolDialog_Close
|
|
dotNet.setLifetimeControl ToolDialog #dotnet
|
|
|
|
-- Main layout-table:
|
|
(
|
|
-- Set up main layout-table, with three rows: Banner, list, extra bits:
|
|
local MainTable = dotNetObject "TableLayoutPanel"
|
|
MainTable.Dock = DockStyle_Fill
|
|
ToolDialog.Controls.Add MainTable
|
|
|
|
MainTable.cellBorderStyle = MainTable.CellBorderStyle.None
|
|
MainTable.RowCount = 3
|
|
|
|
-- TechArt Banner:
|
|
(
|
|
MainTable.RowStyles.Add (dotNetObject "RowStyle" SizeType_Absolute 40)
|
|
|
|
local BannerPanel = dotNetObject "Panel"
|
|
BannerPanel.dock = DockStyle_Fill
|
|
MainTable.Controls.Add BannerPanel 0 0
|
|
|
|
|
|
local VerNum = gRsZoneViewData.VersionNum
|
|
local VerName = gRsZoneViewData.VersionName
|
|
|
|
local TheBanner = MakeRsBanner dn_Panel:BannerPanel wiki:"PopZone Viewer" versionNum:VerNum versionName:VerName filename:(getThisScriptFilename())
|
|
TheBanner.Setup()
|
|
)
|
|
|
|
-- Set up ItemListCtrl:
|
|
(
|
|
MainTable.RowStyles.Add (dotNetObject "RowStyle" SizeType_Percent 100)
|
|
|
|
-- Make sure "RsCustomDataGridView" is defined:
|
|
RS_CustomDataGrid()
|
|
|
|
local ItemListCtrl = dotNetObject "RsCustomDataGridView"
|
|
gRsZoneViewData.ItemListCtrl = ItemListCtrl
|
|
ItemListCtrl.dock = DockStyle_Fill
|
|
MainTable.Controls.Add ItemListCtrl 0 1
|
|
|
|
dotNet.addEventHandler ItemListCtrl "CellMouseUp" ItemList_Clicked
|
|
dotNet.addEventHandler ItemListCtrl "SelectionChanged" ItemList_SelChanged
|
|
dotNet.setLifetimeControl ItemListCtrl #dotnet
|
|
|
|
ItemListCtrl.ReadOnly = False
|
|
ItemListCtrl.SelectionMode = ItemListCtrl.SelectionMode.FullRowSelect
|
|
ItemListCtrl.AllowUserToAddRows = False
|
|
ItemListCtrl.AllowUserToDeleteRows = False
|
|
ItemListCtrl.AllowUserToOrderColumns = False
|
|
ItemListCtrl.AllowUserToResizeColumns = True
|
|
ItemListCtrl.AllowUserToResizeRows = False
|
|
ItemListCtrl.AllowDrop = False
|
|
ItemListCtrl.MultiSelect = True
|
|
|
|
ItemListCtrl.DefaultCellStyle.WrapMode = ItemListCtrl.DefaultCellStyle.WrapMode.True
|
|
ItemListCtrl.AutoSizeRowsMode = ItemListCtrl.AutoSizeRowsMode.AllCells
|
|
|
|
local textClr = (colorMan.getColor #windowText) * 255
|
|
local windowClr = (colorMan.getColor #window) * 255
|
|
ItemListCtrl.DefaultCellStyle.backColor = (dotNetClass "System.Drawing.Color").FromArgb windowClr[1] windowClr[2] windowClr[3]
|
|
ItemListCtrl.DefaultCellStyle.foreColor = (dotNetClass "System.Drawing.Color").FromArgb textClr[1] textClr[2] textClr[3]
|
|
ItemListCtrl.AutoSizeColumnsMode = ItemListCtrl.AutoSizeColumnsMode.Fill
|
|
ItemListCtrl.ColumnHeadersVisible = True
|
|
|
|
-- Add text-columns:
|
|
local listLabels = popZoneStruct.GetListLabels()
|
|
for n = 1 to listLabels.count do
|
|
(
|
|
local textCol = dotNetObject "DataGridViewTextBoxColumn"
|
|
textCol.ReadOnly = true
|
|
|
|
-- Set last column-size to fill:
|
|
textCol.AutoSizeMode = if (n == listLabels.count) then textCol.AutoSizeMode.Fill else textCol.AutoSizeMode.AllCells
|
|
|
|
local newColNum = ItemListCtrl.Columns.Add textCol
|
|
|
|
textCol.HeaderText = listLabels[newColNum + 1]
|
|
)
|
|
)
|
|
|
|
-- Set up the rest of the option-controls:
|
|
(
|
|
MainTable.RowStyles.Add (dotNetObject "RowStyle" SizeType_Absolute 30)
|
|
|
|
local OptionPanel = dotNetObject "FlowLayoutPanel"
|
|
OptionPanel.dock = DockStyle_Fill
|
|
MainTable.Controls.Add OptionPanel 0 2
|
|
|
|
-- "Draw Labels" button
|
|
(
|
|
local NewCtrl = dotNetObject "CheckBox"
|
|
NewCtrl.Text = "Draw Labels for Selected"
|
|
NewCtrl.checked = gRsZoneViewData.ViewLabels
|
|
NewCtrl.FlatStyle = NewCtrl.FlatStyle.System
|
|
NewCtrl.AutoSize = True
|
|
|
|
dotNet.addEventHandler NewCtrl "CheckedChanged" ShowLabel_Changed
|
|
dotNet.setLifetimeControl NewCtrl #dotnet
|
|
|
|
OptionPanel.Controls.Add NewCtrl
|
|
)
|
|
|
|
-- 'Wireframe' button
|
|
(
|
|
local NewCtrl = dotNetObject "CheckBox"
|
|
NewCtrl.Text = "Wireframe"
|
|
NewCtrl.checked = gRsZoneViewData.DrawWireframe
|
|
NewCtrl.FlatStyle = NewCtrl.FlatStyle.System
|
|
NewCtrl.AutoSize = True
|
|
|
|
dotNet.addEventHandler NewCtrl "CheckedChanged" Wireframe_Changed
|
|
dotNet.setLifetimeControl NewCtrl #dotnet
|
|
|
|
OptionPanel.Controls.Add NewCtrl
|
|
)
|
|
|
|
-- Label:
|
|
(
|
|
local NewCtrl = dotNetObject "Label"
|
|
NewCtrl.Text = "Show Colours:"
|
|
NewCtrl.AutoSize = True
|
|
NewCtrl.Margin = dotNetObject "Padding" 0 4 0 0
|
|
|
|
OptionPanel.Controls.Add NewCtrl
|
|
)
|
|
|
|
-- Object-colour radiobuttons
|
|
local ShowClrBtns = #()
|
|
for Item in #(dataPair Text:"PlantIdx" Val:gRsZoneViewData.ShowPlantIdxClr, dataPair Text:"Dirt" Val:gRsZoneViewData.ShowDirtClr, dataPair Text:"Area Name" Val:gRsZoneViewData.ShowAreaClr) collect
|
|
(
|
|
local NewCtrl = dotNetObject "RadioButton"
|
|
NewCtrl.Text = Item.Text
|
|
NewCtrl.Checked = Item.Val
|
|
NewCtrl.Tag = (dotNetMXSValue ShowClrBtns)
|
|
|
|
NewCtrl.AutoSize = True
|
|
|
|
dotNet.addEventHandler NewCtrl "CheckedChanged" ShowClrBtn_Changed
|
|
dotNet.setLifetimeControl NewCtrl #dotnet
|
|
|
|
OptionPanel.Controls.Add NewCtrl
|
|
append ShowClrBtns NewCtrl
|
|
)
|
|
)
|
|
)
|
|
|
|
ToolDialog.ShowModeless()
|
|
)
|
|
|
|
-- Force UI to draw:
|
|
Windows.ProcessPostedMessages()
|
|
|
|
-- Load and show data:
|
|
(
|
|
-- Load data:
|
|
SetStatusTitle "Loading Data..."
|
|
if (not LoadPopZones()) do
|
|
(
|
|
RsZoneViewFuncs.CloseTool()
|
|
return False
|
|
)
|
|
|
|
-- Add data to list:
|
|
(
|
|
SetStatusTitle "Showing List..."
|
|
local showListData = for item in gRsZoneViewData.popZonesList collect (dataPair zoneData:Item rowStrings:(Item.GetRowStrings()))
|
|
local ItemListCtrl = gRsZoneViewData.ItemListCtrl
|
|
|
|
-- Add list-rows:
|
|
for Item in ShowListData do
|
|
(
|
|
local rowIdx = ItemListCtrl.Rows.Add Item.RowStrings
|
|
local ThisRow = ItemListCtrl.Rows.Item[rowIdx]
|
|
|
|
-- Add number to row's tag, so it remembers it if reordered:
|
|
ThisRow.tag = (rowIdx + 1)
|
|
|
|
-- Link row-control to ZoneData struct:
|
|
Item.ZoneData.ListCtrlRow = ThisRow
|
|
)
|
|
)
|
|
)
|
|
|
|
-- Trigger object-generation:
|
|
if gRsZoneViewData.doObjects and (gRsZoneViewData.popZonesList.count != 0) do
|
|
(
|
|
genMissingObjs popZones:gRsZoneViewData.popZonesList
|
|
|
|
-- Set up Max callbacks:
|
|
addCallbacks()
|
|
completeRedraw()
|
|
)
|
|
|
|
SetStatusTitle ""
|
|
|
|
return OK
|
|
)
|
|
)
|
|
|
|
gRsZoneViewData = RsZoneViewData()
|
|
gRsZoneViewFuncs = RsZoneViewFuncs()
|
|
|
|
gRsZoneViewFuncs.CreateTool()
|