996 lines
27 KiB
Plaintext
Executable File
996 lines
27 KiB
Plaintext
Executable File
filein (RsConfigGetWildWestDir() + "script/3dsMax/_config_files/Wildwest_header.ms")
|
|
|
|
struct proceduralMapperStruct
|
|
(
|
|
tileSize,
|
|
worldMapSize = [9150, 12450],
|
|
worldBottomCorner = [-4000, -4950],
|
|
worldOffset = [4000, 4950],
|
|
tileSize = 50.0,
|
|
tileCount = [(worldMapSize.x / tileSize), (worldMapSize.y / tileSize)],
|
|
maxTileIdx = (worldMapSize.x / tileSize) as Integer,
|
|
maxTileIdy = (worldMapSize.y / tileSize) as Integer,
|
|
|
|
containerPositions = #(),
|
|
containerBounds,
|
|
|
|
windowsTEMPDir = systemTools.getEnvVariable "TEMP",
|
|
mapTileArchivePath = (RsConfigGetAssetsDir() + "reports/heightmap/images_4_5/materialmasks.zip"),
|
|
extractPath = windowsTEMPDir + "/ProcMasks",
|
|
maskPaths = extractPath + "/materialmasks/",
|
|
tempMaskPath = windowsTEMPDir + "/TempMaterialMasks/",
|
|
tempProcPaintPath = windowsTEMPDir + "/ProcPaint/",
|
|
procPaintPath = (RsConfigGetAssetsDir() + "maps/procPaint/"),
|
|
|
|
borderDist = 4, --border tiles around a bounds selection
|
|
cellBounds,
|
|
|
|
containerTiles,
|
|
--tileRect,
|
|
|
|
UIEditLayers = #(),
|
|
UIMaskLayers = #(),
|
|
|
|
editLayers = #((tempProcPaintPath + "Procedural Sets")),
|
|
maskLayers = #(),
|
|
|
|
editTypes = #("Procedural_Sets"),
|
|
procMaskImages = #(),
|
|
collProcMaskImages = #(),
|
|
maskTypes = #(),
|
|
|
|
editProcessList = #("ProceduralSetMap"),
|
|
maskProcessList = #(),
|
|
|
|
procedural_meta = (RsConfigGetCommonDir() + "data/materials/procedural.meta"),
|
|
procedural_metaTypes = #(),
|
|
|
|
containerProcTypes = #(),
|
|
|
|
rolloutUI = undefined,
|
|
|
|
--/////////////////////////////////////////
|
|
-- Send a message to the status UI
|
|
--/////////////////////////////////////////
|
|
fn updateUIStatus msg =
|
|
(
|
|
if rolloutUI != undefined then
|
|
(
|
|
rolloutUI.edtStatus.text = msg
|
|
)
|
|
),
|
|
|
|
--/////////////////////////////////////////
|
|
-- Set progress bar status UI
|
|
--/////////////////////////////////////////
|
|
fn setProgress val =
|
|
(
|
|
if rolloutUI != undefined then
|
|
(
|
|
rolloutUI.prgBar.value = val
|
|
)
|
|
),
|
|
|
|
--/////////////////////////////////////////
|
|
-- Set the options for saving png images in the application
|
|
--/////////////////////////////////////////
|
|
fn setPNGOpts type =
|
|
(
|
|
case type of
|
|
(
|
|
#editLayer:portable_network_graphics.setType #true24
|
|
#maskLayer:portable_network_graphics.setType #true24
|
|
)
|
|
|
|
portable_network_graphics.setAlpha false
|
|
portable_network_graphics.setInterlaced false
|
|
),
|
|
|
|
--/////////////////////////////////////////
|
|
--
|
|
--/////////////////////////////////////////
|
|
fn getTileByPos pos =
|
|
(
|
|
local offsetX = worldOffset.x + pos.x
|
|
if offsetX > worldMapSize.x then format "Out of map bounds X: %\n" offsetX
|
|
local offsetY = worldOffset.y + pos.y
|
|
if offsetY > worldMapSize.y then format "Out of map bounds Y: %\n" offsetY
|
|
|
|
local x = (offsetX - (mod offsetX tileSize)) / tileSize
|
|
local y = (offsetY - (mod offsetY tileSize)) / tileSize
|
|
|
|
format "tile from pos:% \n" [x, y]
|
|
return [x, y]
|
|
),
|
|
|
|
--/////////////////////////////////////////
|
|
--tile is a Point2
|
|
--dir is a Point2
|
|
--/////////////////////////////////////////
|
|
fn getTileByAdjacency tile dir =
|
|
(
|
|
[(tile.x + dir.x), (tile.y + dir.y)]
|
|
),
|
|
|
|
--/////////////////////////////////////////
|
|
--
|
|
--/////////////////////////////////////////
|
|
fn getBorderTiles tile border =
|
|
(
|
|
tileBorder = #()
|
|
for x = -border to border do
|
|
(
|
|
for y = -border to border do
|
|
(
|
|
local newX = tile.x + x
|
|
local newY = tile.y + y
|
|
|
|
if (x != 0 or y != 0) and (newX > -1 and newX < maxTileIdx and newY > -1 and newY < maxTileIdy) then
|
|
(
|
|
append tileBorder [newX, newY]
|
|
)
|
|
)
|
|
)
|
|
|
|
--return
|
|
tileBorder
|
|
),
|
|
|
|
--/////////////////////////////////////////
|
|
--
|
|
--/////////////////////////////////////////
|
|
fn tileBounds tileArray =
|
|
(
|
|
bounds = undefined
|
|
|
|
local xRange = for item in tileArray collect item.x
|
|
local yRange = for item in tileArray collect item.y
|
|
|
|
local minX = amin xRange as Integer
|
|
local maxX = amax xRange as Integer
|
|
local minY = amin yRange as Integer
|
|
local maxY = amax yRange as Integer
|
|
|
|
--return
|
|
bounds = #([minX, minY], [maxX, maxY])
|
|
),
|
|
|
|
--/////////////////////////////////////////
|
|
--
|
|
--/////////////////////////////////////////
|
|
fn getTilesByBounds =
|
|
(
|
|
if containerBounds == undefined then return false
|
|
|
|
--using the bounds find all the tiles it covers and return a tileRect
|
|
local minBoundsTile = getTileByPos containerBounds[1]
|
|
local maxBoundsTile = getTileByPos containerBounds[2]
|
|
|
|
containerTiles = tileBounds #(minBoundsTile, maxBoundsTile)
|
|
|
|
--expand the selection to all the tiles within the bounds
|
|
),
|
|
|
|
--/////////////////////////////////////////
|
|
--
|
|
--/////////////////////////////////////////
|
|
fn expandBounds minBB maxBB currentBounds =
|
|
(
|
|
local minBounds = currentBounds[1]
|
|
local maxBounds = currentBounds[2]
|
|
|
|
if ( minBB.x < minBounds.x ) then
|
|
(
|
|
minBounds.x = minBB.x
|
|
)
|
|
|
|
if ( minBB.y < minBounds.y ) then
|
|
(
|
|
minBounds.y = minBB.y
|
|
)
|
|
|
|
if ( maxBB.x > maxBounds.x ) then
|
|
(
|
|
maxBounds.x = maxBB.x
|
|
)
|
|
|
|
if ( maxBB.y > maxBounds.y ) then
|
|
(
|
|
maxBounds.y = maxBB.y
|
|
)
|
|
|
|
#(minBounds, maxBounds)
|
|
),
|
|
|
|
--/////////////////////////////////////////
|
|
-- For all the containers in the scene determine the bounds that cover all
|
|
--/////////////////////////////////////////
|
|
fn getAggregateContainerBounds =
|
|
(
|
|
local conts = RsMapGetMapContainers()
|
|
if conts.count == 0 then
|
|
(
|
|
messagebox "No containers loaded to work with." title:"ERROR"
|
|
return false
|
|
)
|
|
|
|
containerBounds = nodeGetBoundingBox conts[1].cont (matrix3 1)
|
|
|
|
for c in conts do
|
|
(
|
|
local thisContainer = c.cont
|
|
local bounds = nodeGetBoundingBox thisContainer (matrix3 1)
|
|
containerBounds = expandBounds bounds[1] bounds[2] containerBounds
|
|
)
|
|
|
|
),
|
|
|
|
--/////////////////////////////////////////
|
|
-- Check the bounds do not go out of range and trim them if they do
|
|
--/////////////////////////////////////////
|
|
fn checkTileBounds =
|
|
(
|
|
local minBounds = containerTiles[1]
|
|
local maxBounds = containerTiles[2]
|
|
|
|
--check and trim bounds
|
|
|
|
--min
|
|
if minBounds.x < 0 then containerTiles[1].x = 0
|
|
if minBounds.x > tileCount.x then containerTiles[1].x = tileCount.x
|
|
if minBounds.y < 0 then containerTiles[1].y = 0
|
|
if minBounds.y > tileCount.y then containerTiles[1].y = tileCount.y
|
|
|
|
--max
|
|
if maxBounds.x < 0 then containerTiles[2].x = 0
|
|
if maxBounds.x > tileCount.x then containerTiles[2].x = tileCount.x
|
|
if maxBounds.y < 0 then containerTiles[2].y = 0
|
|
if maxBounds.y > tileCount.y then containerTiles[2].y = tileCount.y
|
|
|
|
--check min < max
|
|
if containerTiles[2].x < containerTiles[1].x then containerTiles[2].x = containerTiles[1].x + 1
|
|
if containerTiles[2].y < containerTiles[1].y then containerTiles[2].y = containerTiles[1].y + 1
|
|
|
|
--check for degenerate bounds
|
|
if containerTiles[1].x == containerTiles[2].x then containerTiles[2].x += 1
|
|
if containerTiles[1].y == containerTiles[2].y then containerTiles[2].y += 1
|
|
|
|
ok
|
|
),
|
|
|
|
--/////////////////////////////////////////
|
|
--
|
|
--/////////////////////////////////////////
|
|
fn getContainerPositions =
|
|
(
|
|
local conts = RsMapGetMapContainers()
|
|
containerPositions = for item in conts collect item.cont.pos
|
|
if containerPositions.count == 0 then containerPositions = #([0,0,0])
|
|
),
|
|
|
|
--/////////////////////////////////////////
|
|
-- get the tile maps surrounfing a given tile and merge the images into
|
|
-- one combined map for editing
|
|
--/////////////////////////////////////////
|
|
fn combineTileMaps tile =
|
|
(
|
|
local cellTiles = getBorderTiles tile borderDist
|
|
|
|
),
|
|
|
|
--/////////////////////////////////////////
|
|
-- Extract the materialmask archive
|
|
--/////////////////////////////////////////
|
|
fn extractMaskMaps =
|
|
(
|
|
--Clean the old ones out first
|
|
for filename in (getFiles (extractPath + "*.png")) do deleteFile filename
|
|
|
|
--check for newest version
|
|
local fstat = ( gRsPerforce.getFileStats mapTileArchivePath )[ 1 ]
|
|
local haveRev = fstat.Item[ "haveRev" ]
|
|
local headRev = fstat.Item[ "headRev" ]
|
|
local doUpDateMasks = false
|
|
|
|
|
|
if (haveRev == undefined) or ((haveRev as Integer) < (headRev as Integer)) then
|
|
(
|
|
print "Syncing to head revision"
|
|
|
|
gRsPerforce.sync mapTileArchivePath
|
|
doUpDateMasks = true
|
|
)
|
|
|
|
--check we have the archive
|
|
if (doesFileExist mapTileArchivePath ) or doUpDateMasks then
|
|
(
|
|
--extract to the temp dir
|
|
if (getDirectories extractPath).count == 0 then makeDir (RsMakeSafeSlashes(extractPath))
|
|
zipFile = (dotNetClass "Ionic.Zip.ZipFile").Read mapTileArchivePath
|
|
zipFile.TempFileFolder = extractPath
|
|
zipFile.ExtractSelectedEntries "name = *.png" "materialmasks" extractPath (dotNetClass "Ionic.Zip.ExtractExistingFileAction").OverwriteSilently
|
|
--zipFile.ExtractAll extractPath (dotNetClass "Ionic.Zip.ExtractExistingFileAction").OverwriteSilently
|
|
|
|
--clean
|
|
zipFile.dispose()
|
|
)
|
|
|
|
OK
|
|
|
|
),
|
|
|
|
--/////////////////////////////////////////
|
|
-- using a tile index with bottom left being 0,0
|
|
-- return the top left corner in bitmap coords
|
|
-- bmSize is the size of the bitmap - [x, y]
|
|
-- tileSize is the size of a tile in pixels
|
|
-- tile is the tile index of interest
|
|
-- return a Point2 coord [x, y]
|
|
--/////////////////////////////////////////
|
|
fn getTileBitmapOrigin bmSize tileSize tileRect =
|
|
(
|
|
local pixelTileSize = bmSize / tileCount
|
|
|
|
--tileRect is #([x,y], [x,y])
|
|
local imageX = tileRect[1].x * pixelTileSize.x
|
|
local imageY = tileRect[1].y * pixelTileSize.y
|
|
|
|
--return
|
|
format "image xy:% \n" [imageX, imageY]
|
|
return [imageX, imageY]
|
|
|
|
),
|
|
|
|
--/////////////////////////////////////////
|
|
-- get the size in pixels of the tile Rectangle
|
|
-- unsing the supplied bitmap dimensions
|
|
--/////////////////////////////////////////
|
|
fn getTileBitmapDimensions bmSize tileRect =
|
|
(
|
|
local pixelTileSize = bmSize / tileCount
|
|
|
|
(pixelTileSize * [(tileRect[2].x - tileRect[1].x), (tileRect[2].y - tileRect[1].y)])
|
|
),
|
|
|
|
--/////////////////////////////////////////
|
|
--
|
|
--/////////////////////////////////////////
|
|
fn getTileFilePath tile =
|
|
(
|
|
local tilePath = extractPath + "materialmasks/"
|
|
),
|
|
|
|
--/////////////////////////////////////////
|
|
-- extract a section from an image
|
|
-- and paste it into a new bitmap object to be returned
|
|
--/////////////////////////////////////////
|
|
fn copyBitmapRegion imagePath tileRect =
|
|
(
|
|
if (not (doesFileExist imagePath)) then return undefined
|
|
|
|
local sourceBMP = openBitmap imagePath
|
|
|
|
local tilePixelsOrigin = getTileBitmapOrigin [sourceBMP.Width, sourceBMP.Height] tileSize tileRect
|
|
local tilePixelsDim = getTileBitmapDimensions [sourceBMP.Width, sourceBMP.Height] tileRect
|
|
|
|
local compBm = bitmap tilePixelsDim.x tilePixelsDim.y color:black
|
|
|
|
pasteBitmap sourceBMP compBm (box2 tilePixelsOrigin.x tilePixelsOrigin.y tilePixelsDim.x tilePixelsDim.y) [0, 0]
|
|
|
|
close sourceBMP
|
|
free sourceBMP
|
|
|
|
--debug
|
|
--display compBm
|
|
|
|
--return
|
|
compBm
|
|
),
|
|
|
|
--/////////////////////////////////////////
|
|
--
|
|
--/////////////////////////////////////////
|
|
fn prepareMap type bmpName =
|
|
(
|
|
case type of
|
|
(
|
|
#editLayer:
|
|
(
|
|
local topLeftTileName = "_" + (containerTiles[1].x as Integer) as String + "_" + (containerTiles[1].y as Integer) as String
|
|
local bmpPath = procPaintPath + bmpName + ".png"
|
|
|
|
if (not (doesFileExist bmpPath)) then --try to sync it
|
|
(
|
|
gRsPerforce.sync #(bmpPath)
|
|
)
|
|
if (not (doesFileExist bmpPath)) then --missing
|
|
(
|
|
messageBox ("Cant find file:" + bmpPath) title:"Missing File"
|
|
return false
|
|
)
|
|
|
|
local regionBmp = copyBitmapRegion bmpPath containerTiles
|
|
local outPath = tempProcPaintPath + bmpName + topLeftTileName + ".png"
|
|
regionBmp.filename = outPath
|
|
|
|
setPNGOpts #editLayer
|
|
|
|
save regionBmp
|
|
free regionBmp
|
|
|
|
append editLayers outPath
|
|
)
|
|
|
|
#maskLayer:
|
|
(
|
|
local bmpPath = maskPaths + bmpName + ".png"
|
|
local regionBmp = copyBitmapRegion bmpPath containerTiles
|
|
local outPath = tempProcPaintPath + bmpName + ".png"
|
|
regionBmp.filename = outPath
|
|
|
|
setPNGOpts #maskLayer
|
|
|
|
save regionBmp
|
|
free regionBmp
|
|
|
|
append maskLayers outPath
|
|
)
|
|
)
|
|
),
|
|
|
|
--/////////////////////////////////////////
|
|
--
|
|
--/////////////////////////////////////////
|
|
fn constructMaps =
|
|
(
|
|
updateUIStatus "Constructing working images"
|
|
|
|
--check dirs exist, create if need be
|
|
for dir in #(extractPath, maskPaths, tempMaskPath, tempProcPaintPath) where (not (doesFileExist dir)) do
|
|
(
|
|
makeDir dir
|
|
)
|
|
|
|
|
|
--check if file exists already, prompt for update
|
|
for filename in (getFiles (tempProcPaintPath + "*.png")) do deleteFile filename
|
|
|
|
--process maps
|
|
updateUIStatus "Processing masks..."
|
|
setProgress 0
|
|
local prgMax = maskProcessList.count
|
|
|
|
for i=1 to maskProcessList.count do
|
|
(
|
|
local thisItem = maskProcessList[i]
|
|
local bmpName = getFilenameFile thisItem
|
|
|
|
prepareMap #maskLayer bmpName
|
|
|
|
setProgress (100.0 * ( i as float / prgMax))
|
|
)
|
|
setProgress 0
|
|
|
|
updateUIStatus "Processing edit maps..."
|
|
prgMax = editProcessList.count
|
|
for i=1 to editProcessList.count do
|
|
(
|
|
local thisItem = editProcessList[i]
|
|
local bmpName = getFilenameFile thisItem
|
|
|
|
prepareMap #editLayer bmpName
|
|
setProgress (100.0 * ( i as float / prgMax))
|
|
)
|
|
setProgress 0
|
|
|
|
updateUIStatus "."
|
|
),
|
|
|
|
--/////////////////////////////////////////
|
|
-- Find all the extracted mask images
|
|
--/////////////////////////////////////////
|
|
fn discoverProceduralMaskImages =
|
|
(
|
|
local files = getFiles (maskPaths + "*.png")
|
|
if files.count == 0 then return false
|
|
|
|
-- 'ALL_' type procedural images
|
|
procMaskImages = getFiles (maskPaths + "ALL_*.png")
|
|
|
|
-- collision/procedural combinations
|
|
collProcMaskImages = for name in files where (MatchPattern (getFilenameFile name) pattern:"ALL_*") == false collect name
|
|
|
|
OK
|
|
),
|
|
|
|
--/////////////////////////////////////////
|
|
--Break up the collProcMaskImages list into lists by category
|
|
--/////////////////////////////////////////
|
|
fn categoriseMasks =
|
|
(
|
|
----------------------------------
|
|
-- procMaskImages
|
|
----------------------------------
|
|
if procMaskImages.count != 0 then
|
|
(
|
|
--determine types
|
|
local scratchMaskTypes = #()
|
|
for item in procMaskImages do
|
|
(
|
|
local nameBits = filterString (getFileNameFile item) "_"
|
|
if nameBits.count > 0 then appendIfUnique scratchMaskTypes nameBits[1]
|
|
)
|
|
|
|
--now create lists of mask images under these types
|
|
for type in scratchMaskTypes do
|
|
(
|
|
local maskList = for item in procMaskImages where MatchPattern (getFilenameFile item) pattern:(type + "*") collect item
|
|
append maskTypes (DataPair type:type masks:maskList)
|
|
)
|
|
)
|
|
|
|
----------------------------------
|
|
-- collProcMaskImages
|
|
----------------------------------
|
|
if collProcMaskImages.count != 0 then
|
|
(
|
|
--determine types
|
|
local scratchMaskTypes = #()
|
|
for item in collProcMaskImages do
|
|
(
|
|
local nameBits = filterString (getFileNameFile item) "_"
|
|
if nameBits.count > 0 then appendIfUnique scratchMaskTypes nameBits[1]
|
|
)
|
|
|
|
--now create lists of mask images under these types
|
|
for type in scratchMaskTypes do
|
|
(
|
|
local maskList = for item in collProcMaskImages where MatchPattern (getFilenameFile item) pattern:(type + "*") collect item
|
|
append maskTypes (DataPair type:type masks:maskList)
|
|
)
|
|
)
|
|
|
|
OK
|
|
|
|
),
|
|
|
|
--/////////////////////////////////////////
|
|
--
|
|
--/////////////////////////////////////////
|
|
fn processScene =
|
|
(
|
|
--get the containers positions
|
|
--getContainerPositions()
|
|
--get the containers bounds
|
|
getAggregateContainerBounds()
|
|
|
|
--find the tiles
|
|
--containerTiles = for cPos in containerPositions collect (getTileByPos cPos)
|
|
getTilesByBounds()
|
|
|
|
--grow the border
|
|
local minBorder = [(containerTiles[1].x - borderDist), (containerTiles[1].y - borderDist)]
|
|
local maxBorder = [(containerTiles[2].x + borderDist), (containerTiles[2].y + borderDist)]
|
|
containerTiles = expandBounds minBorder maxBorder containerTiles
|
|
|
|
--trim the bounds if they go out of range
|
|
checkTileBounds()
|
|
|
|
--get the bounds of the tiles to make a rectangular area
|
|
--tileRect = tileBounds containerTiles
|
|
format "containerBounds: % \n" containerBounds
|
|
|
|
--extract the map archive to build the composite image from
|
|
print "extractMaskMaps"
|
|
discoverProceduralMaskImages()
|
|
--extractMaskMaps()
|
|
|
|
--build a composite image for each mask and the edit layer
|
|
print "ConstructMaps"
|
|
constructMaps()
|
|
|
|
--send to photoshop for editing
|
|
|
|
),
|
|
|
|
--//////////////////////////////////////////////////////////////////////
|
|
-- Get all the types defined in procedural.meta
|
|
--//////////////////////////////////////////////////////////////////////
|
|
fn parseProcedural_meta =
|
|
(
|
|
local xmlDoc = XmlDocument()
|
|
xmlDoc.load procedural_meta
|
|
local procTags = xmlDoc.document.selectNodes "./CProceduralInfo/procObjInfos/Item/Tag"
|
|
procedural_metaTypes = #()
|
|
|
|
for i=0 to (procTags.count - 1) do
|
|
(
|
|
appendIfUnique procedural_metaTypes procTags.itemOf[i].InnerText
|
|
)
|
|
sort procedural_metaTypes
|
|
),
|
|
|
|
--/////////////////////////////////////////
|
|
--
|
|
--/////////////////////////////////////////
|
|
fn discoverProcedural_metaTypes =
|
|
(
|
|
for item in collProcMaskImages do
|
|
(
|
|
stringBits = filterString (getFilenameFile item) "[*]"
|
|
|
|
if (stringBits[2] != undefined) then
|
|
(
|
|
appendIfUnique procedural_metaTypes stringBits[2]
|
|
)
|
|
)
|
|
|
|
sort procedural_metaTypes
|
|
),
|
|
|
|
--/////////////////////////////////////////
|
|
-- Analyse all the collision meshes
|
|
-- in the scene and collect all the proctypes from the assigned materials
|
|
-- Then tag the tree mask items that match against those.
|
|
--/////////////////////////////////////////
|
|
fn collectSceneProcTypes =
|
|
(
|
|
for obj in objects where (isKindOf obj col_mesh) do
|
|
(
|
|
--get the applied material IDs
|
|
--copyMesh = copy obj
|
|
local objMesh = getColMesh obj
|
|
|
|
local materialIDs = for face in objMesh.faces collect (getFaceMatID objMesh face.index)
|
|
materialIDs = sort(makeUniqueArray materialIDs)
|
|
|
|
for id in materialIDs do
|
|
(
|
|
local procType = RexGetProceduralName obj.material.materialList[id]
|
|
if procType != "" then
|
|
(
|
|
append containerProcTypes procType
|
|
)
|
|
)
|
|
|
|
--clean up
|
|
--delete copyMesh
|
|
--delete objMesh
|
|
|
|
)
|
|
|
|
containerProcTypes = makeUniqueArray containerProcTypes
|
|
|
|
),
|
|
|
|
--/////////////////////////////////////////
|
|
--
|
|
--/////////////////////////////////////////
|
|
on create do
|
|
(
|
|
--discover if we have the latest materialmasks zip
|
|
|
|
extractMaskMaps()
|
|
discoverProceduralMaskImages()
|
|
categoriseMasks()
|
|
discoverProcedural_metaTypes()
|
|
collectSceneProcTypes()
|
|
--parseProcedural_meta()
|
|
)
|
|
|
|
)
|
|
|
|
--/////////////////////////////////////////
|
|
-- UI
|
|
--/////////////////////////////////////////
|
|
rollout InitMessageUI "Initialising.." width:200 height:60
|
|
(
|
|
label lblInitMsg "Initialising Procedural Mapper" align:#left
|
|
label lblWait "Please Wait..." align:#left
|
|
)
|
|
createDialog InitMessageUI
|
|
|
|
try(destroyDialog ProceduralMapperUI)catch()
|
|
rollout ProceduralMapperUI "Procedural Mapper" width:400 height:725
|
|
(
|
|
--/////////////////////////////////////////
|
|
-- VARIABLES
|
|
--/////////////////////////////////////////
|
|
local procMapper = proceduralMapperStruct()
|
|
local nodeActionList = #()
|
|
|
|
--/////////////////////////////////////////
|
|
-- CONTROLS
|
|
--/////////////////////////////////////////
|
|
dotNetControl rsBannerPanel "Panel" pos:[0,0] height:32 width:400
|
|
local banner = makeRsBanner dn_Panel:rsBannerPanel wiki:"ProceduralMapper" filename:(getThisScriptFilename())
|
|
|
|
dropdownlist ddlProcTypes items:procMapper.procedural_metaTypes width:(ProceduralMapperUI.width - 110) across:2
|
|
button btnSelectMasks "Select Masks" align:#right
|
|
|
|
dotNetControl dnTreeView "System.Windows.Forms.TreeView" width:(ProceduralMapperUI.width - 25) height:(ProceduralMapperUI.height - 145)
|
|
|
|
button btnEditMaps "Edit Maps" width:(ProceduralMapperUI.width - 25)
|
|
|
|
progressBar prgBar
|
|
|
|
editText edtStatus text:"Status" enabled:false
|
|
|
|
--/////////////////////////////////////////
|
|
-- FUNCTIONS
|
|
--/////////////////////////////////////////
|
|
|
|
--/////////////////////////////////////////
|
|
-- Populates the tree control with content
|
|
--/////////////////////////////////////////
|
|
fn buildTree =
|
|
(
|
|
--editLayers
|
|
editLayersNode = dnTreeView.nodes.Add "Edit Layers"
|
|
editLayersNode.checked = true
|
|
|
|
--add the child nodes
|
|
for item in procMapper.editTypes do
|
|
(
|
|
local newNode = editLayersNode.nodes.add item
|
|
newNode.tag = item
|
|
newNode.checked = true
|
|
)
|
|
|
|
--maskLayers
|
|
maskLayersNode = dnTreeView.nodes.Add "Mask Layers"
|
|
maskLayersNode.expand()
|
|
|
|
--add the child nodes
|
|
--first by category
|
|
local maskTypeNodes = #()
|
|
for item in procMapper.maskTypes do
|
|
(
|
|
append maskTypeNodes (maskLayersNode.nodes.add item.type)
|
|
)
|
|
|
|
--then the children for each category
|
|
for i = 1 to maskTypeNodes.count do
|
|
(
|
|
for childMask in procMapper.maskTypes[i].masks do
|
|
(
|
|
local aNode = maskTypeNodes[i].nodes.add (getFileNameFile childMask)
|
|
aNode.tag = childMask
|
|
|
|
--tick it on if it matches to a proctype in the scene
|
|
local childMaskProcType = FilterString childMask "[]"
|
|
if childMaskProcType.count > 1 then
|
|
(
|
|
if (findItem procMapper.containerProcTypes childMaskProcType[2]) != 0 then
|
|
(
|
|
aNode.checked = true
|
|
|
|
local root = false
|
|
local parentNode = aNode.parent
|
|
while (parentNode != undefined) do
|
|
(
|
|
parentNode.Expand()
|
|
parentNode = parentNode.parent
|
|
)
|
|
)
|
|
)
|
|
)
|
|
)
|
|
)
|
|
|
|
|
|
--/////////////////////////////////////////
|
|
-- setup the dotnet UI
|
|
--/////////////////////////////////////////
|
|
fn init =
|
|
(
|
|
procMapper.rolloutUI = ProceduralMapperUI
|
|
dnTreeView.CheckBoxes = true
|
|
|
|
buildTree()
|
|
|
|
)
|
|
|
|
--/////////////////////////////////////////
|
|
-- Traverse up the tree to the root
|
|
--/////////////////////////////////////////
|
|
fn findRoot node =
|
|
(
|
|
if node.parent != undefined then
|
|
(
|
|
findRoot node.parent
|
|
)
|
|
else
|
|
(
|
|
return node
|
|
)
|
|
)
|
|
|
|
--/////////////////////////////////////////
|
|
-- update the nodeActionList
|
|
-- when a node is check or not
|
|
--/////////////////////////////////////////
|
|
fn updateMaskProcessList item state =
|
|
(
|
|
--add checked nodes to the list for processing
|
|
|
|
local treeRoot = findRoot item
|
|
|
|
if treeRoot.text == "Mask Layers" then
|
|
(
|
|
if state == true then
|
|
(
|
|
appendIfUnique procMapper.maskProcessList item.tag
|
|
)
|
|
else --remove them
|
|
(
|
|
--print "remove"
|
|
local id = findItem procMapper.maskProcessList item.tag
|
|
if id != 0 then deleteItem procMapper.maskProcessList id
|
|
)
|
|
)
|
|
)
|
|
|
|
--/////////////////////////////////////////
|
|
-- Get the root mask treeview nodes list
|
|
--/////////////////////////////////////////
|
|
fn getMaskLayerRootNodes =
|
|
(
|
|
local maskLayersNodeChildren = #()
|
|
|
|
local maskLayersNode = for t=0 to (dnTreeView.nodes.count - 1) \
|
|
where (MatchPattern dnTreeView.nodes.item[t].text pattern:"Mask Layers" ) \
|
|
collect dnTreeView.nodes.item[t]
|
|
|
|
if maskLayersNode.count != 0 then
|
|
(
|
|
maskLayersNodeChildren = for t=0 to (maskLayersNode[1].nodes.count - 1) collect maskLayersNode[1].nodes.item[t]
|
|
)
|
|
|
|
--retval
|
|
maskLayersNodeChildren
|
|
)
|
|
|
|
--//////////////////////////////////////////////////////////////////////////////////////
|
|
--switch all treeNode child nodes to checkbox state
|
|
--//////////////////////////////////////////////////////////////////////////////////////
|
|
fn checkTreeNodeChildren treeNodes state =
|
|
(
|
|
for thisNode in treeNodes do
|
|
(
|
|
--thisNode = treeNodes.item[n]
|
|
thisNode.checked = state
|
|
|
|
--add checked nodes to the list for processing
|
|
updateMaskProcessList thisNode state
|
|
|
|
--recurse?
|
|
if thisNode.nodes.count > 0 then
|
|
(
|
|
newNodes = for t=0 to (thisNode.nodes.count - 1) collect thisNode.nodes.item[t]
|
|
checkTreeNodeChildren newNodes state
|
|
)
|
|
)
|
|
)
|
|
|
|
--/////////////////////////////////////////
|
|
--
|
|
--/////////////////////////////////////////
|
|
fn findMatchingNode maskName treeNodes &nodes =
|
|
(
|
|
local found = False
|
|
for thisNode in treeNodes while not found do
|
|
(
|
|
--format "node: % mask: % \n" (tolower thisNode.text) (tolower maskName)
|
|
if (tolower thisNode.text) == (tolower maskName) then
|
|
(
|
|
found = True
|
|
append nodes thisNode
|
|
)
|
|
|
|
--recurse?
|
|
if thisNode.nodes.count > 0 then
|
|
(
|
|
newNodes = for t=0 to (thisNode.nodes.count - 1) collect thisNode.nodes.item[t]
|
|
findMatchingNode maskName newNodes &nodes
|
|
)
|
|
)
|
|
)
|
|
|
|
--/////////////////////////////////////////
|
|
-- Search for nodes matching names and Switch
|
|
--/////////////////////////////////////////
|
|
fn checkMatchingNodes namesList =
|
|
(
|
|
for maskName in namesList do
|
|
(
|
|
local nodes = #()
|
|
findMatchingNode (getFilenameFile maskName) (getMaskLayerRootNodes()) &nodes
|
|
--print nodes
|
|
|
|
--set node to checked
|
|
if nodes != undefined then
|
|
(
|
|
for node in nodes do node.checked = True
|
|
)
|
|
)
|
|
)
|
|
|
|
|
|
--/////////////////////////////////////////
|
|
-- EVENTS
|
|
--/////////////////////////////////////////
|
|
|
|
--/////////////////////////////////////////
|
|
-- Select any mask items in the list
|
|
-- matching the currently selected Procedural from the dropdown
|
|
--/////////////////////////////////////////
|
|
on btnSelectMasks pressed do
|
|
(
|
|
local procFromList = tolower ddlProcTypes.selected
|
|
--local masksArray = for item in procMapper.maskTypes collect item.masks
|
|
local matchingMasks = #()
|
|
|
|
for item in procMapper.collProcMaskImages do
|
|
(
|
|
if MatchPattern (getFilenameFile item) pattern:("*["+procFromList+"]*") ignoreCase:true then append matchingMasks item
|
|
)
|
|
|
|
if matchingMasks.count != 0 then
|
|
(
|
|
--clear any checked selection first
|
|
checkTreeNodeChildren (for t=0 to (dnTreeView.nodes.count - 1) collect dnTreeView.nodes.item[t]) False
|
|
|
|
--take the matches and set the tree nodes
|
|
checkMatchingNodes matchingMasks
|
|
)
|
|
)
|
|
|
|
--/////////////////////////////////////////
|
|
--
|
|
--/////////////////////////////////////////
|
|
on dnTreeView AfterCheck sender ev do
|
|
(
|
|
--print "check"
|
|
--print ev
|
|
--print sender
|
|
|
|
if ev.node.nodes.count > 0 then
|
|
(
|
|
childNodes = for n=0 to (ev.node.nodes.count - 1) collect ev.node.nodes.item[n]
|
|
checkTreeNodeChildren childNodes ev.node.checked
|
|
)
|
|
|
|
|
|
if ev.node.nodes.count == 0 then
|
|
(
|
|
updateMaskProcessList ev.node ev.node.checked
|
|
)
|
|
)
|
|
|
|
--/////////////////////////////////////////
|
|
--
|
|
--/////////////////////////////////////////
|
|
on btnEditMaps pressed do
|
|
(
|
|
--From the checked tree nodes build a list of mask maps to process for working with
|
|
|
|
|
|
--Now process them
|
|
procMapper.processScene()
|
|
)
|
|
|
|
--/////////////////////////////////////////
|
|
--
|
|
--/////////////////////////////////////////
|
|
on ProceduralMapperUI open do
|
|
(
|
|
banner.setup()
|
|
init()
|
|
try(DestroyDialog InitMessageUI)catch()
|
|
)
|
|
|
|
)
|
|
|
|
createDialog ProceduralMapperUI
|