Files
gtav-src/tools_ng/wildwest/script/3dsMax/Maps/Materials/terrain_helperFunctions.ms
T
2025-09-29 00:52:08 +02:00

1541 lines
50 KiB
Plaintext
Executable File

-- terrain_helperfunctions.ms
-- created by Gunnar Droege
-- written by Luke Openshaw
-- ripped out of the collision set tool for general use
-- 10/06/2010
--
-- Neal D Corbett 05/2014 - Rewritten as generalised methods for processing terrain-shaders
fileIn (RsConfigGetWildWestDir() + "script/3dsMax/_common_functions/FN_RSTA_string.ms")
global gRsTerrainHelpers
-- Returns value used to match two colours together; the higher the value, the better the match:
-- (ClrA/B should be normalised point3 values)
fn RsGetAlphaVal ClrA ClrB =
(
-- Alpha corresponds to r/g/b matches:
local Alph = (ClrA * ClrB) + (1.0 - ClrA) * (1.0 - ClrB)
-- Return combined alpha-value:
return (Alph.X * Alph.Y * Alph.Z)
)
-- Descriptor for a terrain-material shader-type:
-- (Default settings are for GTA5-style 'Terrain_Cb_*' blended shaders)
struct RsTerrainShaderType
(
-- Flags for quickly checking shader-type:
isUberTerrain = False,
isStandard2lyr = False,
-- The behaviour of a terrain-material depends on which type of terrain-shader it's using:
Type = #Terrain_Cb,
-- String-pattern for distiguishing shader-types via their names:
pattern = "Terrain_Cb_*",
-- Colours used to denote which diffuse-texture should be used where:
LookupColours = #(Black, Blue, Green, (color 0 255 255), Red, (color 255 0 255), Yellow, White),
LookupColourNames = #("black", "blue", "green", "turquoise", "red", "purple", "yellow", "white"),
NormLookupColours,
-- Colour-indices that are safe to blend to from the colour with a given index:
LookupSafeCombos = #(#{1,2,3,5},#{1,2,4,6},#{1,3,4,7},#{2,3,4,8},#{1,5,6,7},#{2,5,6,8},#{3,5,7,8},#{4,6,7,8}),
-- UV-channels used to place Texmaps/Lookup-maps/Tint-maps:
-- (default Texmap/LookupUVchans can be changed per-material for some shaders)
texmapUVchan = 1, lookupUVchan = 2, tintUVchan = 3,
-- Will be set to list of channels that LookupUVchan can be set to:
LookupUVchans = #{},
-- Lookup/Tint vertex-colour channels:
LookupClrChan = 9, TintClrChan = 0,
-- Channels used to blend between Texture/Vertex-Colour versions of Lookup/Tint:
-- Lookup is masked on vertex-alpha channel by default
maskChan = -2, lookupMaskSubChan, tintMaskSubChan,
-- Channels for masking displacement/curvature effects:
effectsMaskChan, displaceMaskSubChan, curvatureMaskSubChan,
-- Default mask-values, to be used on slider-controls:
DefLookupMaskVal = 1.0, DefTintMaskVal = 0.0, DefDisplaceMaskVal = 0.0,
-- Text description of mask-channels:
lookupMaskChanText = "Vertex Alpha", tintMaskChanText = "", displaceMaskChanText = "",
-- Text description of mask min/max values:
LookupMaskRangeText = DataPair Min:"Texture" Max:"Vertex",
TintMaskRangeText = DataPair Min:"Texture" Max:"Vertex",
DisplaceMaskRangeText = DataPair Min:"Show" Max:"Hide",
-- Function for deconstructing a given normalised colour-value to texmap-blend weights: (this alias is set by 'On Create')
GetWeightsFromClr,
-- Returns value used to match two colours together; the higher the value, the better the match:
-- (ClrA/B should be normalised point3 values)
fn GetAlphaVal clrA clrB =
(
-- Alpha corresponds to r/g/b matches:
local alph = (clrA * clrB) + (1.0 - clrA) * (1.0 - clrB)
-- Return combined alpha-value:
return (alph.x * alph.y * alph.z)
),
-- (converted from 'BlendTerrainColor' in 'terrain_cb_common.fxh')
fn GetWeightsFromClr_Terrain_Cb clrVal texCount: =
(
if (texCount == unsupplied) do
(
texCount = normLookupColours.count
)
for idx = 1 to texCount collect
(
GetAlphaVal clrVal normLookupColours[idx]
)
),
-- (converted from 'cpvBlendWeights' in 'terrain_uber_common.fxh')
fn GetWeightsFromClr_Terrain_Uber clrVal =
(
local rVal = clrVal[1]
local gVal = clrVal[2]
local bVal = clrVal[3]
local blackVal = (1.0 - (rVal + gVal + bVal))
if (blackVal < 0) do (blackVal = 0)
-- Return blend-weights calculated for clrVal.
-- Uber lookup-colours are red/green/blue/black:
return #(rVal, gVal, bVal, blackVal)
),
-- Greyscale values:
fn GetWeightsFromClr_Standard2Lyr clrVal =
(
local whiteVal = clrVal[1]
local blackVal = (1.0 - whiteVal)
return #(blackVal, whiteVal)
),
-- Function for constructing colour-value from given blend-weights:
-- (inverse function to 'GetWeightsFromClr')
GetClrFromWeights,
fn GetClrFromWeights_Terrain_Cb blends =
(
-- Construct blend-colour colour up by adding weighted lookup-colours:
local OutClr = [0,0,0]
for Idx = 1 to 4 do
(
OutClr += (Blends[Idx] * NormLookupColours[Idx])
)
return OutClr
),
fn GetClrFromWeights_Terrain_Uber blends =
(
-- Just return first three blend-weights as rgb values:
return [Blends[1],Blends[2],Blends[3]]
),
fn GetClrFromWeights_Standard2Lyr blends =
(
-- Just return white-value:
local whiteVal = blends[2]
return [whiteVal, whiteVal, whiteVal]
),
on Create do
(
-- Convert lookup-colours to normalised point3 values:
this.normLookupColours = for clr in this.lookupColours collect ((clr as Point3) / 255.0)
-- Choose appropriate blend-weight function for shader:
this.GetWeightsFromClr = case type of
(
#Terrain_Uber:(this.GetWeightsFromClr_Terrain_Uber)
#Standard_2lyr:(this.GetWeightsFromClr_Standard2Lyr)
Default:(this.GetWeightsFromClr_Terrain_Cb)
)
this.GetClrFromWeights = case type of
(
#Terrain_Uber:(this.GetClrFromWeights_Terrain_Uber)
#Standard_2lyr:(this.GetClrFromWeights_Standard2Lyr)
Default:(this.GetClrFromWeights_Terrain_Cb)
)
-- Get list of Lookup UV channels this shadertype might use:
this.lookupUVchans = case type of
(
#Terrain_Uber:(#{1..3})
#Standard_2lyr:(#{1..2})
Default:(#{this.lookupUVchan})
)
)
)
-- TTN shaders are like default Terrain_Cb, but with Tint-texmap,
-- and mask-channel to blend between using Lookup/Tint texmaps or vertex-colours:
global RsTerrainShaderType_TTN =
(
RsTerrainShaderType Type:#Terrain_Cb_Ttn \
Pattern:"Terrain_Cb_*_Ttn"
)
-- Default: GTA5-style terrain-shaders:
-- (only 'cm' versions have the 'Lookup texture' slot)
global RsTerrainShaderType_CB =
(
RsTerrainShaderType()
)
-- RDR3/Americas-style terrain-shaders:
global RsTerrainShaderType_Uber =
(
RsTerrainShaderType Type:#Terrain_Uber \
Pattern:"Terrain_Uber_*" \
LookupColours:#(Red, Green, Blue, Black) \
LookupColourNames:#("red", "green", "blue", "black") \
LookupSafeCombos:#() \ -- (Uber doesn't appear to show blending-artifacts)
LookupUVchan:1 TintUVchan:1 \ -- Lookup/Tint textures use same UVs as diffuse-maps (diffuse-tiling is changed via shader values)
MaskChan:5 \ -- Lookup/Tint are both masked by this vert-channel
TintMaskSubChan:1 TintMaskChanText:"Vert-Channel 5: Red" \ -- Tint is masked on red sub-channel
LookupMaskSubChan:2 LookupMaskChanText:"Vert-Channel 5: Green" \ -- Lookup is masked on green sub-channel
DisplaceMaskSubChan:3 DisplaceMaskChanText:"Vert-Channel 5: Blue" -- Displacement is masked on blue sub-channel
)
-- List of differences between terrain-shader types:
global RsTerrainShaderTypes =
#(
RsTerrainShaderType_TTN,
RsTerrainShaderType_CB,
RsTerrainShaderType_Uber
)
-- Descriptor for a terrain-material.
-- Should be initialised with 'TerrainMat' argument.
struct RsTerrainMatInfo
(
Private
-- Faces this material and its diffuse-texmaps are used on:
-- 'MatFaces' is set up by 'GetObjTerrainFaceData', 'DiffuseFaces' by 'FindDominantFaceTextures'
MatFaces = #{}, DiffuseFaces = #(),
Public
TerrainMat,
-- 'PresetName' is the value in material's 'Preset' slot, which will be the shader-name or a Material Preset.
-- If this is a Material Preset, the name of the actual shader will be saved to ShaderName.
-- 'ShaderName' is matched against RsTerrainShaderTypes:
PresetName, ShaderName, TypeDef,
DiffuseTexPaths = #(), BumpTexPaths = #(), TexCount = 0,
LookupTexPath, TintTexPath,
-- The material-slots containing this material's diffuse/bump texmaps:
DiffSlotNums = #(), BumpSlotNums = #(),
-- Object and MatId this material is used on:
Obj, MatId = undefined,
-- Material's shader-values, updated by 'UpdateVals':
VarNames = #(), VarTypes = #(), VarNums = #(), VarVals = #(),
-- Track tool-selection of texmap-indices:
Selected = #{},
------------------------------------------------------------------------------------------------------
-- Accessor-functions for private arrays:
------------------------------------------------------------------------------------------------------
fn GetMatFaces = (return MatFaces),
fn GetDiffuseFaces = (return DiffuseFaces),
------------------------------------------------------------------------------------------------------
-- GetLookupUVchan:
-- Returns the Lookup UV channel for this descriptor's material.
-- This can currently only be changed on a per-material basis for Terrain_Uber shaders.
------------------------------------------------------------------------------------------------------
fn GetLookupUVchan =
(
-- Default value
local uvChan = typeDef.lookupUVchan
-- Get channel-value from material, where supported:
local matChan = case of
(
(typeDef.isUberTerrain):(RstGetVariableByName this.terrainMat "Lookup UV Set")
(typeDef.isStandard2lyr):(RstGetVariableByName this.terrainMat "Control UV Set")
Default:Undefined
)
-- Use channel from material:
if (matChan != undefined) do
(
uvChan = (Integer matChan)
)
return uvChan
),
------------------------------------------------------------------------------------------------------
-- GetTexmapUVchan:
-- Returns the UV channel used to map a materials texmap.
-- This can currently only be changed on a per-texmap basis for Terrain_Uber shaders.
------------------------------------------------------------------------------------------------------
fn GetTexmapUVchan texNum =
(
-- Default mapping-channel:
local uvChan = typeDef.texmapUVchan
case of
(
(typeDef.isUberTerrain):
(
-- PXM shaders will use the default UV channel (1)
if (not isPxmShader) do
(
-- Use material's 'UV Set' variable, if supported by shader:
local texChans = (RstGetVariableByName this.terrainMat "UV Set")
if (texChans != undefined) do
(
uvChan = (Integer texChans[texNum])
)
)
)
(typeDef.isStandard2lyr):
(
local varName = case texNum of
(
1:"Lyr1 UV Set"
2:"Lyr2 UV Set"
)
uvChan = Integer (RstGetVariableByName this.terrainMat varName)
)
)
return uvChan
),
------------------------------------------------------------------------------------------------------
-- UpdateVals:
-- Get/update Material info:
------------------------------------------------------------------------------------------------------
fn UpdateVals =
(
-- Get material's current preset/shader-name:
local NewPresetName = (RstGetShaderName TerrainMat)
-- Clear path-arrays/values:
(
for ThisArray in #(DiffuseTexPaths, BumpTexPaths) do
(
ThisArray.Count = 0
)
LookupTexPath = undefined
TintTexPath = undefined
)
-- Update details if shadername has changed since:
if (NewPresetName != PresetName) do
(
-- Clear various values/arrays:
(
for ThisArray in #(VarNames, VarTypes, VarNums, VarVals, Selected, DiffuseFaces) do
(
ThisArray.Count = 0
)
TexCount = 0
)
-- Update shader-name stuff:
(
PresetName = NewPresetName
-- Get shadername for preset,if used:
-- ('RstGetMaterialPresetShaderName' isn't currently defined in GTA5 tools)
if (RstGetMaterialPresetShaderName != undefined) do
(
ShaderName = (RstGetMaterialPresetShaderName TerrainMat)
)
-- If material isn't using a Preset, use 'PresetName' as 'ShaderName':
if (ShaderName == undefined) do
(
ShaderName = PresetName
)
-- Strip extension from ShaderName:
ShaderName = (GetFilenameFile ShaderName)
-- Find matching terrain-type for material:
TypeDef = undefined
for ThisType in RsTerrainShaderTypes while (TypeDef == undefined) do
(
if (MatchPattern ShaderName Pattern:ThisType.Pattern) do
(
TypeDef = ThisType
)
)
)
-- Update attribute-names/types if this is a valid terrain-shader:
if (TypeDef != undefined) do
(
local NumVars = (RstGetVariableCount TerrainMat)
-- Find shader's texmap-slots, used for texmap-swapping:
local TexSlotNum = 0
for VarNum = 1 to NumVars do
(
local VarType = (RstGetVariableType TerrainMat VarNum)
-- We're only interested in Texmap and Vector4 attributes:
if (varType == "texmap") or (varType == "vector4") or (varType == "float") do
(
local VarName = (RstGetVariableName TerrainMat VarNum)
append VarNames VarName
append VarNums VarNum
append VarTypes VarType
if (VarType == "texmap") do
(
TexSlotNum += 1
case of
(
-- Get diffuse-maps:
((matchpattern VarName pattern:"Diffuse*") or (matchpattern VarName pattern:"Color Texture*")):
(
append DiffuseFaces #{}
append DiffSlotNums TexSlotNum
)
-- Remember bump slot-numbers:
(matchPattern VarName pattern:"Bump *"):
(
append BumpSlotNums TexSlotNum
)
)
)
)
)
-- Get diffusemap-slot count:
TexCount = DiffSlotNums.Count
)
)
-- Stop processing if this isn't a valid terrain-shader:
if (TypeDef == undefined) do return OK
-- Collect updated attribute-values:
for VarIdx = 1 to VarNums.Count do
(
local VarNum = VarNums[VarIdx]
local ThisVal = (RstGetVariable TerrainMat VarNum)
VarVals[VarIdx] = ThisVal
-- Collect updated texturemap-name data:
if (VarTypes[VarIdx] == "texmap") do
(
local VarName = VarNames[VarIdx]
case of
(
-- Get diffuse-maps:
((matchpattern VarName pattern:"Diffuse*") or (matchpattern VarName pattern:"Color Texture*")):
(
append DiffuseTexPaths ThisVal
)
-- Remember bump slot-numbers:
(matchPattern VarName pattern:"Bump *"):
(
append BumpTexPaths ThisVal
)
-- Get lookup-texture path, if used:
(matchpattern VarName pattern:"Lookup texture"):
(
LookupTexPath = ThisVal
)
-- Get tint-texture path, if used:
(matchpattern VarName pattern:"Tint"):
(
TintTexPath = ThisVal
)
)
)
)
return OK
),
------------------------------------------------------------------------------------------------------
-- GetTexPath:
-- Returns diffuse/bump-map path with specific index:
------------------------------------------------------------------------------------------------------
fn GetTexPath TexNum Bump:False =
(
local TexArray = if Bump then BumpTexPaths else DiffuseTexPaths
local ThisPath = TexArray[TexNum]
if (ThisPath == undefined) do
(
ThisPath = ""
)
return ThisPath
),
-------------------------------------------------------------------------------------------
-- GetFaceVertTexWeights:
-- Returns lists of blend-weights for each vert on each face in 'MatFaces',
-- Lookup-bitmaps and masks are ignored if 'IgnoreBitmaps' is true,
-------------------------------------------------------------------------------------------
fn GetFaceVertTexWeights faceLookupClrVerts: ignoreBitmaps:False quiet:False escToAbort:False perFace:False =
(
-- Abort if material has no faces, or is an invalid object:
if (this.matFaces.numberSet == 0) or not ((IsValidNode obj) or (IsKindOf obj TriMesh)) do return OK
local faceLookupClrVertsUnsupplied = (faceLookupClrVerts == Unsupplied)
if faceLookupClrVertsUnsupplied do
(
faceLookupClrVerts = #()
)
local promptMsg = ("Collecting texmap blend-weights... [matId: " + (matId as String) + "]")
if escToAbort do
(
Append promptMsg " [Esc to Cancel]"
)
PushPrompt (RsProgressString PromptMsg 0)
-- Set up aliases to appropriate functions for this object:
local ObjOp = RsMeshPolyOp Obj
local isMeshObj = (ObjOp == MeshOp)
local ObjGetFace = RsGetFaceFunc obj
local ObjGetMapFace = RsGetMapFaceFunc obj
local ObjGetMapVert = ObjOp.GetMapVert
-- Get appropriate vert-channels from the TypeDef:
local LookupClrChan = TypeDef.LookupClrChan
local LookupMapChan = This.GetLookupUVchan()
local MaskChan = TypeDef.MaskChan
local LookupMaskSubChan = TypeDef.LookupMaskSubChan
-- Are we processing Standard_2lyr shader?
local isStandard2lyr = typeDef.isStandard2lyr
-- Do we need to get pixels and mask for Lookup texture?
-- (non-vertcolour channels are ignored for 'IgnoreBitmaps' mode)
local HasLookupTex = (not IgnoreBitmaps) and (LookupTexPath != undefined)
local UsesMask = (not isStandard2lyr) and (not IgnoreBitmaps) and (HasLookupTex) and (TypeDef.MaskChan != undefined)
local UsesLookupClr = (LookupClrChan != undefined)
local UsesLookupMap = (not IgnoreBitmaps) and (LookupMapChan != undefined)
-- Get typedef's function for finding a colour's texmap-blend weights:
local GetWeightsFromClr = TypeDef.GetWeightsFromClr
-- Are required channels actually available?
local LookupClrChanAvailable = (UsesLookupClr and (ObjOp.GetMapSupport Obj LookupClrChan))
local LookupMapChanAvailable = (UsesLookupMap and (ObjOp.GetMapSupport Obj LookupMapChan))
local MaskChanAvailable = (UsesMask and (ObjOp.GetMapSupport Obj MaskChan))
-- Get blend-value stuff for Standard_2lyr shader:
if isStandard2lyr do
(
local blendSoftness = (RstGetVariableByName this.terrainMat "Blend Softness")
local controlFilter = (RstGetVariableByName this.terrainMat "Control Filter")
local invertControl = ((RstGetVariableByName this.terrainMat "Invert Control") == 1.0)
-- This needs to be a Point3 to be used with Point3 colours
if (IsKindOf controlFilter Point4) do
controlFilter = controlFilter as Point3
-- Find blend-exponent:
local blendExp = (blendSoftness ^ 2)
if (blendExp < 0.00001) do
(
blendExp = 0.00001
)
blendExp = (1.0 / blendExp)
)
-- Standard_2lyr needs to load alpha from Control Texture:
local texClrClass = if isStandard2lyr then Point4 else Point3
-- Warn about missing channels, where required:
if (not Quiet) do
(
for Item in
#(
DataPair Text:("Lookup-colour (channel " + (LookupClrChan as string) + ")") Error:(UsesLookupClr and not LookupClrChanAvailable),
DataPair Text:("Lookup-texture UVs (channel " + (LookupMapChan as string) + ")") Error:(UsesLookupMap and not LookupMapChanAvailable),
DataPair Text:("Mask-colour (channel " + (MaskChan as string) + ")") Error:(UsesMask and not MaskChanAvailable)
) where Item.Error do
(
format "WARNING: % is missing on object" Item.Text
if (isValidNode Obj) do (format " '%'" Obj.Name) -- Don't print name for TriMesh Obj-values
format " - this is required by material ID % (we'll assume channel is black)\n" matId
)
)
-- Lookup-bitmap data will be loaded to here, if required:
local LookupBmp, BmpMaxX, BmpMaxY
local BmpLoadFailed = False
-- Don't bother attempting to load lookup-bitmap if the relevant uv-channel is missing:
-- (lookup-bitmap will be assumed to be all black)
if (not LookupMapChanAvailable) do
(
BmpLoadFailed = True
)
-- Use arbitrary rgb subchannel for lookup-mask if subchannel was unspecified...
local UseLookupMaskSubChan = LookupMaskSubChan
if (UseLookupMaskSubChan == undefined) do
(
UseLookupMaskSubChan = 1
)
-- UV/colour vert-data for this material, so we'll only need to probe each vert once:
local LookupMapVertClrs = #()
if LookupMapChanAvailable do (LookupMapVertClrs.Count = (ObjOp.GetNumMapVerts Obj LookupMapChan))
-- Collect UV face-vert lists - these are used by other functions too:
if LookupClrChanAvailable do
(
join FaceLookupClrVerts (for FaceNum in MatFaces collect (ObjGetMapFace Obj LookupClrChan FaceNum))
)
-- Get number of faces used by material:
local MatFacesCount = (this.matFaces.numberSet)
-- We expect this operation will require about this much memory:
local blendsCount = this.texCount
local FaceVertsEstimate = if isMeshObj then 3 else 4
local MemReq = (Integer64 MatFacesCount * FaceVertsEstimate * BlendsCount * 32)
local MemDiff = (HeapFree - MemReq)
--format "MemReq:% HeapFree:% MemDiff: %\n" MemReq HeapFree MemDiff
-- Increase heapsize if we think it's going to be too small:
-- (otherwise Max may auto-increase it thousands of times during loop, very slow)
if (MemDiff < 0) do
(
HeapSize += (abs MemDiff)
)
-- Predefine array:
local FaceBlendWeights = for n = 1 to MatFacesCount collect #()
-- Update prompt: (overriding any heap-resize messages)
ReplacePrompt (RsProgressString PromptMsg 0)
-- We'll update the status-prompt every so often:
local PromptUpdateInterval = (MatFacesCount / 21)
-- Find dominant lookup-weightings for each material's faces' verts:
local Success = True
local FaceIdx = 0
for FaceNum in This.MatFaces while (Success = not (EscToAbort and Keyboard.EscPressed)) do
(
FaceIdx += 1
-- Update statusprompt progressbar every so often:
if ((Mod FaceIdx PromptUpdateInterval) == 0) do
(
ReplacePrompt (RsProgressString PromptMsg (1.0 * FaceIdx / MatFacesCount))
)
-- This empty blendweights-array will be initially filled with lookup-colours...
local FaceLookupClrs = FaceBlendWeights[FaceIdx]
local FaceLookupMask = #()
-- Set to False if all vert-colours are to be taken from lookup-bitmap:
local HasLookupVertClrs = True
-- Get mask-values for face's verts, if shader uses Lookup-mask:
if HasLookupTex do
(
-- Default this to false for Terrain (for shaders that have Lookup-texture but no masking feature)
-- Standard_2lyr uses both texture and vertex values, and has no masking
hasLookupVertClrs = if isStandard2lyr then True else False
local hasLookupTexClrs = True
-- Get data from mask-channel, if used by this terrain-shader type:
if usesMask do
(
-- Only process mask-channel if it's actually active - otherwise, we'll default to assuming it is white
if MaskChanAvailable then
(
-- Get verts used on mask-channel face:
local FaceMaskVerts = (ObjGetMapFace Obj MaskChan FaceNum)
-- Get mask-values for each of mask-face's verts:
faceLookupMask = for mapVertNum in faceMaskVerts collect
(
-- Get colour-value from mask-channel:
local maskClr = (ObjGetMapVert obj maskChan mapVertNum)
-- Get mask-values for Lookup-texture:
maskClr[useLookupMaskSubChan]
)
faceMaskVerts.count = 0
-- Do we need to load colours from texture or vertcolours or both for this face?
HasLookupVertClrs = False
HasLookupTexClrs = False
for VertMask in FaceLookupMask do
(
if (VertMask > 0) do
(
-- This face takes some colours from Lookup vertex-channel:
HasLookupVertClrs = True
)
if (VertMask < 1) do
(
-- This face takes some colours from Lookup texture:
HasLookupTexClrs = True
)
)
)
else
(
-- If mask-channel is missing, we'll assume it's default white:
HasLookupTexClrs = False
HasLookupVertClrs = True
)
)
-- Collect unmasked colours, from lookup-bitmap:
if hasLookupTexClrs do
(
-- Load bitmap, it will be needed:
-- (this will happen once per material)
if (not BmpLoadFailed) and (LookupBmp == undefined) do
(
LookupBmp = OpenBitmap LookupTexPath
-- Check to see if bitmap failed to load:
if (LookupBmp == undefined) then
(
BmpLoadFailed = True
)
else
(
BmpMaxX = (LookupBmp.Width - 1)
BmpMaxY = (LookupBmp.Height - 1)
)
)
-- Collect lookup-colours for this face's verts:
-- Use black as default if lookup-bitmap failed to load:
local LookupClrs = if (BmpLoadFailed) then
(
-- This works even if the mapping-channel is inactive:
for ThisVert in (ObjGetFace Obj FaceNum) collect [0,0,0]
)
else
(
-- Get verts used on lookup-texture's map-face:
local FaceMapVerts = ObjGetMapFace Obj LookupMapChan FaceNum
-- Collect bitmap-colours for each unmasked vert:
for VertIdx = 1 to FaceMapVerts.Count collect
(
-- Get mask-value for vert (zero (black) if shader doesn't do masking, or 1 (white) if mask-channel is missing)
local VertMask = case of
(
(UsesMask and MaskChanAvailable):FaceLookupMask[VertIdx]
UsesMask:1
Default:0
)
-- Collect undefined if bitmap is masked for this vert...
local LookupClr = undefined
-- Get bitmap-colour from texturemap if vert is unmasked:
if (vertMask < 1) do
(
-- Get vertex-number from mapping-face vert-list:
local MapVertNum = FaceMapVerts[VertIdx]
-- Get cached colour for vert:
LookupClr = LookupMapVertClrs[MapVertNum]
-- If not cached, get UVs from, mesh, and colour from bitmap:
if (LookupClr == undefined) do
(
local UvPos = ObjGetMapVert Obj LookupMapChan MapVertNum
-- Convert UV-coords to texture-coords:
local BmpPos = [integer (abs (mod UvPos.x 1.0) * BmpMaxX), integer ((1 - (abs (mod UvPos.y 1.0))) * BmpMaxY)]
-- Get pixel-colour:
LookupClr = (GetPixels LookupBmp BmpPos 1)[1]
-- Convert to nomalised Point3/Point4:
LookupClr = (LookupClr as texClrClass) / 255
-- Cache pixel-colour:
LookupMapVertClrs[MapVertNum] = LookupClr
)
)
-- Collect colour from bitmap:
LookupClr
)
)
-- Join colours-array to this empty array (this maintains array-references)
join FaceLookupClrs LookupClrs
)
-- (Finished loading face's colours from Lookup-texture)
)
-- Get colours from Lookup vert-colours, if face's mask allows this:
if hasLookupVertClrs do
(
local ThisFaceLookupClrVerts
if LookupClrChanAvailable do
(
-- Get vert-indices for face's vert-colour Lookup-colours:
ThisFaceLookupClrVerts = FaceLookupClrVerts[FaceIdx]
-- Expand face's colours-array if it is still empty:
FaceLookupClrs.Count = ThisFaceLookupClrVerts.Count
)
-- Get vert-colours for verts that aren't masked to use Lookup texture:
for VertIdx = 1 to FaceLookupClrs.Count do
(
local VertMask = if (UsesMask and MaskChanAvailable) then FaceLookupMask[VertIdx] else 1
-- Only bother getting vert-colour if this vert was masked at all - otherwise we just use colour from Lookup texture.
if (VertMask > 0) do
(
local VertClr
if (LookupClrChanAvailable) then
(
local MapVertNum = ThisFaceLookupClrVerts[VertIdx]
-- Get normalised Lookup vertex-colour: (on 0-1 scale)
vertClr = ObjGetMapVert obj lookupClrChan mapVertNum
case of
(
-- Apply Control Texture values to Standard_2lyr vertex-blend:
isStandard2lyr:
(
-- Get 'Control Amount' from texmap:
local bmpVertClr = faceLookupClrs[vertIdx]
local controlAmount = (Dot controlFilter bmpVertClr)
if invertControl do
(
controlAmount = (1.0 / controlAmount)
)
-- Find blend-value:
local vertClrVal = vertClr[1]
local blendBase = (vertClrVal * controlAmount) + vertClrVal
if (blendBase > 1.0) do
(
blendBase = 1.0
)
local blendVal = (blendBase ^ blendExp)
vertClr = [blendVal,blendVal,blendVal]
)
-- If vert isn't fully-masked, mix it with the colour taken from the lookup-texture:
(vertMask < 1):
(
local bmpVertClr = faceLookupClrs[vertIdx]
-- Combine texmap/vertex lookup-colours using mask-value as alpha:
vertClr = (vertMask * vertClr) + ((1 - vertMask) * bmpVertClr)
)
)
)
else
(
-- Default to black if lookup-channel is missing:
VertClr = [0,0,0]
)
FaceLookupClrs[VertIdx] = VertClr
)
)
)
-- This array is no longer needed:
FaceLookupMask.Count = 0
-- Now we have the colours for each of face's verts (blended between Lookup-vertcolours and texturemap as required)
-- Extract texmap blend-weights for each vert:
for VertIdx = 1 to FaceLookupClrs.Count do
(
local vertClr = FaceLookupClrs[VertIdx]
-- Replace array-colour with its corresponding blend-weights:
FaceLookupClrs[VertIdx] = (GetWeightsFromClr vertClr texCount:texCount)
)
)
-- All done! Now close lookup-bitmap, if one has been opened:
if (LookupBmp != undefined) do
(
Close LookupBmp
)
-- Clear finished arrays:
lookupMapVertClrs.count = 0
-- Only clear this array if it was created inside this function:
if (faceLookupClrVertsUnsupplied) do
(
for item in faceLookupClrVerts do
(
item.count = 0
)
faceLookupClrVerts.count = 0
)
PopPrompt()
if Success then (return FaceBlendWeights) else (return False)
),
-------------------------------------------------------------------------------------------
-- GetFaceTexWeights:
-- Returns lists of blend-weights for each face in 'MatFaces',
-- Lookup-bitmaps and masks are ignored if 'IgnoreBitmaps' is true,
-------------------------------------------------------------------------------------------
fn GetFaceTexWeights ignoreBitmaps:False quiet:False escToAbort:False =
(
-- Get per-vertex weights, or face-weights from lookup-render:
local faceVertWeights = this.GetFaceVertTexWeights perFace:True ignoreBitmaps:ignoreBitmaps quiet:quiet escToAbort:escToAbort
-- Return non-array error-values:
if (not isKindOf faceVertWeights Array) do return faceVertWeights
if (faceVertWeights.count == 0) do return #()
-- If this is a list of weights per vertex per face, convert to list of weights per face:
if (IsKindOf faceVertWeights[1][1] Array) do
(
local blendsCount = this.texCount
for faceIdx = 1 to faceVertWeights.count do
(
local vertWeights = faceVertWeights[faceIdx]
if (vertWeights.count != 0) do
(
local avgWeights = vertWeights[1]
for vertIdx = 2 to vertWeights.count do
(
local thisVertWeights = vertWeights[vertIdx]
for texIdx = 1 to blendsCount do
(
avgWeights[texIdx] += thisVertWeights[texIdx]
)
)
avgWeights = for thisWeight in avgWeights collect (thisWeight / blendsCount)
faceVertWeights[faceIdx] = avgWeights
)
)
)
return faceVertWeights
),
-------------------------------------------------------------------------------------------
-- HasMatchingTexIdx:
-- Returns idx of highest BlendWeight
-------------------------------------------------------------------------------------------
fn GetDominantTexIdx BlendWeights =
(
FindItem BlendWeights (Amax BlendWeights)
),
-------------------------------------------------------------------------------------------
-- HasMatchingTexIdx:
-- Used to decide whether a subobject uses a given texmap or not.
-- [Default] True if TexIdx has non-zero weighting
-- [Dominant:True] True if TexIdx has the highest weighting
-------------------------------------------------------------------------------------------
fn HasMatchingTexIdx BlendWeights TexIdx Dominant:False =
(
if Dominant then
(
return ((GetDominantTexIdx BlendWeights) == TexIdx)
)
else
(
return (BlendWeights[TexIdx] != 0.0)
)
),
-- Returns list of verts displaying texmap with index 'TexIdx';
fn GetVertsUsingTexmap TexIdx IgnoreBitmaps:False Dominant:False =
(
-- Return verts for all matfaces if no specific TexIdx was requested:
if (TexIdx == 0) then
(
-- Get list of verts used by matfaces:
local MatVerts = #()
local ObjGetFace = (RsGetFaceFunc Obj)
for FaceNum in MatFaces do
(
join MatVerts (ObjGetFace Obj FaceNum)
)
-- Return verts for faces:
return (MatVerts as BitArray)
)
else
(
local FaceGeomVerts = #()
-- Get vertex texture-blends data:
local FaceBlendWeights = GetFaceTexWeights FaceGeomVerts:FaceGeomVerts IgnoreBitmaps:IgnoreBitmaps
-- Abort if that failed:
if (not isKindOf FaceBlendWeights Array) do (return OK)
local TexVerts = #{}
-- Examine blend-weights on verts used by each face:
for FaceIdx = 1 to FaceBlendWeights.Count do
(
local FaceBlends = FaceBlendWeights[FaceIdx]
local FaceVertNums = FaceGeomVerts[FaceIdx]
for VertIdx = 1 to FaceBlends.Count do
(
-- Set bit for geometry-verts if weighting matches TexIdx:
if (HasMatchingTexIdx FaceBlends[VertIdx] TexIdx Dominant:Dominant) do
(
local VertNum = FaceVertNums[VertIdx]
TexVerts[VertNum] = True
)
)
)
return TexVerts
)
),
-- Returns list of faces displaying texmap with index 'TexIdx';
fn GetFacesUsingTexmap TexIdx IgnoreBitmaps:False Dominant:False =
(
-- Return all matfaces if no specific TexIdx was requested:
if (TexIdx == 0) do return MatFaces
-- Get vertex texture-blends data:
local FaceBlendWeights = GetFaceTexWeights IgnoreBitmaps:IgnoreBitmaps
-- Abort if that failed:
if (not isKindOf FaceBlendWeights Array) do (return OK)
local TexFaces = #{}
(
-- Initialise face-array sizes:
local MatFacesArray = (MatFaces as Array)
local MaxFaceNum = MatFacesArray[MatFacesArray.Count]
MatFacesArray.Count = 0
TexFaces.Count = MaxFaceNum
)
local FaceNums = (MatFaces as Array)
-- Examine blend-weights on verts used by each face:
for FaceIdx = 1 to FaceBlendWeights.Count do
(
local FaceHasTex = False
local FaceBlends = FaceBlendWeights[FaceIdx]
if Dominant then
(
-- Add faces' vert-weights together:
local CombinedBlends = for TexIdx = 1 to TexCount collect
(
local Val = 0
for VertBlends in FaceBlends do
(
Val += VertBlends[TexIdx]
)
Val
)
-- Find dominant texmap for combined blend-weights, and see if it matches TexIdx:
FaceHasTex = ((GetDominantTexIdx CombinedBlends) == TexIdx)
)
else
(
-- Does this face include a vert with non-zero blend for this texmap?
for VertBlends in FaceBlends while (not FaceHasTex) do
(
FaceHasTex = (HasMatchingTexIdx VertBlends TexIdx Dominant:False)
)
)
if FaceHasTex do
(
local FaceNum = FaceNums[FaceIdx]
TexFaces[FaceNum] = True
)
)
return TexFaces
),
------------------------------------------------------------------------------------------
-- SwapTexmapLookups:
-- Swaps lookup-colours for two texmap-ids.
------------------------------------------------------------------------------------------
fn SwapTexmapLookups TexIdxA TexIdxB =
(
-- Abort if both idxs are the same for some reason...
if (TexIdxA == TexIdxB) do return OK
-- Get vertex texture-blends data for material's faces:
local FaceLookupClrVerts = #()
local FaceBlendWeights = GetFaceTexWeights FaceLookupClrVerts:FaceLookupClrVerts IgnoreBitmaps:True
-- Abort if that failed:
if (not isKindOf FaceBlendWeights Array) or (FaceLookupClrVerts.Count != FaceBlendWeights.Count) do (return FaceBlendWeights)
-- Set up aliases to appropriate functions for this object:
local ObjOp = RsMeshPolyOp Obj
local ObjSetMapVert = ObjOp.SetMapVert
local ObjGetMapFace = RsGetMapFaceFunc Obj
-- We'll be processing the Lookup vertexcolour-channel:
local Chan = TypeDef.LookupClrChan
-- Get typedef's function for converting texmap-blend weights to colour-values:
local GetClrFromWeights = TypeDef.GetClrFromWeights
-- Get map-verts per lookup-channel face, to compare against 'FaceBlendWeights':
local LookupClrChan = TypeDef.LookupClrChan
-- Bitarray to keep track of which mapverts have already been processed:
local VertsDone = #{}
VertsDone.Count = (ObjOp.GetNumMapVerts Obj LookupClrChan)
-- Process all mapverts that have weights available:
for FaceIdx = 1 to FaceBlendWeights.Count do
(
-- Get blends and UV-indices for this face:
local FaceBlends = FaceBlendWeights[FaceIdx]
local FaceVerts = FaceLookupClrVerts[FaceIdx]
-- Process face's verts in turn:
for VertIdx = 1 to FaceVerts.Count do
(
local VertNum = FaceVerts[VertIdx]
-- Don't process mapverts more than once each:
if (not VertsDone[VertNum]) do
(
VertsDone[VertNum] = True
local VertWeights = FaceBlends[VertIdx]
-- Create new weights-array, where TexIdxA/B are swapped:
local NewWeights = for TexIdx = 1 to TexCount collect
(
case TexIdx of
(
TexIdxA:VertWeights[TexIdxB]
TexIdxB:VertWeights[TexIdxA]
Default:VertWeights[TexIdx]
)
)
-- Generate colour from swapped texmap-weights, and edit that lookup-vert:
local NewClr = GetClrFromWeights NewWeights
ObjSetMapVert Obj Chan VertNum NewClr
)
)
)
-- Swap the values for this struct's path/face arrays:
for ThisArray in #(DiffuseTexPaths, DiffuseFaces) do
(
local OldValA = ThisArray[TexIdxA]
ThisArray[TexIdxA] = ThisArray[TexIdxB]
ThisArray[TexIdxB] = OldValA
)
-- Update onscreen colours:
case ObjOp of
(
polyOp:(polyOp.collapseDeadStructs Obj)
meshOp:(update Obj)
)
CompleteRedraw()
return OK
),
------------------------------------------------------------------------------------------
-- SwapTexmapMatSlots, SwapTexmapSlotsByTexIdx:
-- Swaps material's texmap-slots for two texmap-ids.
------------------------------------------------------------------------------------------
fn SwapTexmapMatSlots SlotNumA SlotNumB =
(
--format "Swapping texmap slots: %/%\n" SlotNumA SlotNumB
local SlotATexmap = GetSubTexmap TerrainMat SlotNumA
local SlotBTexmap = GetSubTexmap TerrainMat SlotNumB
SetSubTexmap TerrainMat SlotNumA SlotBTexmap
SetSubTexmap TerrainMat SlotNumB SlotATexmap
SlotBTexmap.Filename = SlotBTexmap.Filename
),
fn SwapTexmapSlotsByTexIdx TexIdxA TexIdxB =
(
-- Swap diffuse and bump slots:
for ThisArray in #(DiffSlotNums, BumpSlotNums) where (ThisArray.Count != 0) do
(
SwapTexmapMatSlots ThisArray[TexIdxA] ThisArray[TexIdxB]
)
-- Update shader after swaps are completed:
RstRefreshMtl TerrainMat
),
------------------------------------------------------------------------------------------
-- SwapTexmaps:
-- Swaps lookup-colours or material texmap-slots for two texmap-ids.
------------------------------------------------------------------------------------------
fn SwapTexmaps TexIdxA TexIdxB SwapMatSlots:True SwapLookups:True =
(
if (TexIdxA == TexIdxB) do return False
if SwapMatSlots do
(
SwapTexmapSlotsByTexIdx TexIdxA TexIdxB
)
if SwapLookups do
(
SwapTexmapLookups TexIdxA TexIdxB
)
),
-------------------------------------------------------------------------------------------
-- FindDominantFaceTextures:
-- Works out which diffusemap is most prominent on each of material's faces
-- (This function takes lookup-texture/mask into account)
-------------------------------------------------------------------------------------------
fn FindDominantFaceTextures Quiet:False IgnoreBitmaps:False EscToAbort:False =
(
-- Get texture-blends data for this material-definition:
local FaceBlendWeights = (GetFaceTexWeights IgnoreBitmaps:IgnoreBitmaps EscToAbort:EscToAbort)
-- Abort if that failed:
if (not isKindOf FaceBlendWeights Array) do (return False)
-- Get number of faces used by material:
local MatFacesCount = 0
local MaxMatFaceNum = 0
for n in This.MatFaces do
(
MatFacesCount += 1
MaxMatFaceNum = n
)
-- Initialise face-array sizes:
for TexFaces in DiffuseFaces do
(
TexFaces.Count = MaxMatFaceNum
)
local FacesCount = (FaceBlendWeights.Count)
local PromptMsg = ("Finding dominant texmap index... [matId: " + (matId as String) + "]")
if EscToAbort do
(
append PromptMsg " [Esc to Cancel]"
)
PushPrompt (RsProgressString PromptMsg 0)
-- We'll update the status-prompt every so often:
local PromptUpdateInterval = (FacesCount / 21)
-- Examine blend-weights on verts used by each face:
local faceIdx = 0
local multiVertWeights = False
for FaceNum in This.MatFaces do
(
faceIdx += 1
-- Update statusprompt's progressbar every so often:
if ((Mod FaceIdx PromptUpdateInterval) == 0) do
(
ReplacePrompt (RsProgressString PromptMsg (1.0 * FaceIdx / FacesCount))
)
local faceBlends = faceBlendWeights[FaceIdx]
-- Is 'faceBlends' a single array of texmap-weights, or an array of per-vert weight-arrays?
if (faceIdx == 1) and (IsKindOf faceBlends[1] Array) do
(
multiVertWeights = True
)
local combinedBlends = if (not multiVertWeights) then faceBlends else
(
-- Add face's vert-weights together:
for texIdx = 1 to texCount collect
(
local val = 0
for vertBlends in faceBlends do
(
val += vertBlends[texIdx]
)
val
)
)
-- Find dominant texmap for combined blend-weights:
local texIdx = GetDominantTexIdx CombinedBlends
-- We can now assign this face to the matching diffuse-path's face-list:
DiffuseFaces[TexIdx][FaceNum] = True
)
PopPrompt()
return True
),
-------------------------------------------------------------------------------------------
-- GetNameString:
-- Generate name-string to show in tools
-------------------------------------------------------------------------------------------
fn GetNameString =
(
local MatText = StringStream ""
if (MatId != undefined) and (MatId != -1) do
(
format "%: " MatId To:MatText
)
format "% [" TerrainMat.Name To:MatText
-- Show shadername value if material is using a preset:
if ((GetFilenameFile PresetName) != ShaderName) do
(
format "% | " ShaderName To:MatText
)
format "%]" PresetName To:MatText
return (MatText as String)
),
-------------------------------------------------------------------------------------------
-- Create:
-- Initialises struct to match describe TerrainMat
-- Works out flavour of Terrain shader is in use (if any) and collects textures
-------------------------------------------------------------------------------------------
on Create do
(
-- Abort if 'TerrainMat' is undefined or invalid:
if (not isKindOf TerrainMat Rage_Shader) do return False
-- Get material shader-data:
UpdateVals()
return OK
)
)
struct RsTerrainHelpers
(
-------------------------------------------------------------------------------------------------
-- GetObjTerrainFaceData:
-- Returns list of 'RsTerrainMatInfo' descriptors of materials with
-- compatible terrain-shaders (these are defined by array 'RsTerrainShaderTypes')
-- If 'MatchMat' is supplied, function only returns descriptor for that submaterial.
-- (if submaterial was found on object, and uses compatible shader)
-------------------------------------------------------------------------------------------------
fn GetObjTerrainFaceData Obj Material: MatchMat: =
(
if (not isValidObj Obj) do return #()
-- Materials used on object, and their respective faces:
local ObjMats = #()
local FaceLists = #()
local MtlIdList = #()
-- Get material-info for object:
PushPrompt "Collecting material-info for object..."
RsGetMaterialsOnObjFaces Obj Material:Material Materials:ObjMats FaceLists:FaceLists MtlIdList:MtlIdList
PopPrompt()
-- Generate and collect terrain-material info-structs for each material found:
PushPrompt "Processing materials..."
local MatInfoList = for MatIdx = 1 to ObjMats.Count collect
(
local SubMat = ObjMats[MatIdx]
-- Skip this submaterial if if doesn't match the supplied 'MatchMat':
if (MatchMat != unsupplied) and (MatchMat != SubMat) then DontCollect else
(
local NewMatInfo = RsTerrainMatInfo TerrainMat:ObjMats[MatIdx] Obj:Obj MatId:MtlIdList[MatIdx]
-- Set up private array - set up list of faces used by material:
local MatFaces = NewMatInfo.GetMatFaces()
join MatFaces FaceLists[MatIdx]
-- Collect MatInfo struct:
NewMatInfo
)
)
PopPrompt()
-- Filter out materials without valid terrain-shaders:
MatInfoList = for Item in MatInfoList where (Item.TypeDef != undefined) collect Item
-- Sort materials by matid:
qsort MatInfoList (fn SortByMatId v1 v2 = (v1.MatId - v2.MatId))
return MatInfoList
),
-------------------------------------------------------------------------------------------------
-- GetDominantFaceTexInfo:
-- Collects compatible-shader descriptors for 'Obj',
-- and triggers collection of per-face dominant-texture data.
-------------------------------------------------------------------------------------------------
fn GetDominantFaceTexInfo Obj IgnoreBitmaps:False EscToAbort:False Material: MatchMat: =
(
local TimeStart = TimeStamp()
local MatInfoList = GetObjTerrainFaceData Obj Material:Material MatchMat:MatchMat
-- Collect dominant-textures face-data for listed material-structs:
PushPrompt "Finding dominant textures for terrain-faces..."
local Success = True
for Item in MatInfoList while Success and (Success = not (EscToAbort and Keyboard.EscPressed)) do
(
Success = Item.FindDominantFaceTextures IgnoreBitmaps:IgnoreBitmaps EscToAbort:EscToAbort
)
PopPrompt()
format "Dominant-texmap search took % seconds\n" ((TimeStamp() - TimeStart) / 1000.0)
return MatInfoList
),
------------------------------------------------------------------------------------------
-- BalanceTexWeights:
-- Balance texmap-colour weights - they should add up to 1.0
------------------------------------------------------------------------------------------
fn BalanceTexWeights texWeights =
(
local totalWeight = 0
for texWeight in texWeights do
(
totalWeight += texWeight
)
if (totalWeight != 1) do
(
local mult = (1.0 / totalWeight)
texWeights = for texWeight in texWeights collect (texWeight * mult)
)
return texWeights
)
)
gRsTerrainHelpers = RsTerrainHelpers()
-- Legacy function:
fn GetDominantTextureFromTerrainFace obj mat matID faceId =
(
-- Get submaterial:
local MatchMat = unsupplied
if (isKindOf Mat MultiMaterial) and (isKindOf MatId Integer) do
(
local MatIdx = FindItem Mat.MaterialIDList MatID
if (MatIdx != 0) do
(
MatchMat = Mat.MaterialList[MatIdx]
)
)
-- Collect dominant-texture terrain-material data from object:
local MatInfoList = gRsTerrainHelpers.GetDominantFaceTexInfo Obj Material:Mat MatchMat:MatchMat
-- Search collected data for material/texmap that uses 'FaceId':
local MatFound = False
local DiffusePath = undefined
for MatItem in MatInfoList while (not MatFound) do
(
if (MatItem.GetMatFaces())[FaceId] do
(
MatFound = True
local TexFound = False
for TexNum = 1 to MatItem.DiffuseTexPaths.Count while (not TexFound) do
(
if MatItem.DiffuseFaces[TexNum][FaceId] do
(
TexFound = True
DiffusePath = MatItem.DiffuseTexPaths[TexNum]
)
)
)
)
return DiffusePath
)
-- TEST --
IF FALSE DO
(
clearlistener()
print "IF YOU CAN SEE THIS, SOMEBODY LEFT THE TEST-CODE IN"
gc()
local TimeStart = TimeStamp()
local obj = $
--local stuff = (gRsTerrainHelpers.GetObjTerrainFaceData Obj EscToAbort:True)
local stuff = (gRsTerrainHelpers.GetDominantFaceTexInfo Obj EscToAbort:True) --IgnoreBitmaps:False)
--local stuff = (gRsTerrainHelpers.GetDominantFaceTexInfo (copy Obj.Mesh) Material:Obj.Material EscToAbort:True) --IgnoreBitmaps:False)
--local stuff = (gRsTerrainHelpers.GetObjTerrainFaceData (copy Obj.Mesh) Material:Obj.Material EscToAbort:True) --IgnoreBitmaps:False)
--local Verts = stuff[2].GetVertsUsingTexmap 0
format "Took % seconds\n" ((timeStamp() - timeStart) / 1000.0)
--stuff[1].GetFaceTexWeights()
print stuff
local MatThing = stuff[1]
print (MatThing.GetMatFaces()).numberset
for n = 1 to 4 do
(
print (MatThing.GetDiffuseFaces())[n].numberset
)
print (MatThing.GetFacesUsingTexmap 1)
print (MatThing.GetFacesUsingTexmap 2)
print (MatThing.GetFacesUsingTexmap 3)
print (MatThing.GetFacesUsingTexmap 4)
--MatThing.SwapTexmaps 1 2 SwapMatSlots:False SwapLookups:True
RsTerrainShaderTypes[3].GetClrFromWeights (RsTerrainShaderTypes[3].GetWeightsFromClr [0.1,0.5,0.1])
--ok
)