Files
2025-09-29 00:52:08 +02:00

314 lines
8.5 KiB
Plaintext
Executable File

struct PaletteOps
(
--palette index is the palette table entry
--it contains an array of a colour and object verts indexes
-- palette[1] = #(#((color 255 255 255), 3, 5, 44, 155), #((color 255 12 34), 12, 55, 8, 205), .....)
palette = dotNetObject "RSG.MaxUtils.MaxDictionary", --key=colour value=#(mapverts)
--translator = dotNetObject "RSG.MaxUtils.MaxDictionary", --key=colour value = paletteindex
--indexToColour = dotNetObject "RSG.MaxUtils.MaxDictionary", --key = index value=colour
indexToColour = #(),
paletteIdx = #(),
--Grab the vertex colours from the selected mesh and channel
fn grabMeshColours channel:13 obj:$selection[1] =
(
--obj = $selection[1]
--clear the dict
palette.clear()
if (meshop.getMapSupport obj.mesh channel) != true then return false
theMesh = snapShotAsMesh obj
for mv = 1 to (meshOp.getNumMapVerts theMesh channel) do
(
mapVertColour = meshOp.getMapVert theMesh channel mv
--colourVec = dotNetObject "RSG.Base.Math.Vector3f" mapVertColour.x mapVertColour.y mapVertColour.z
colourVec = dotNetObject "System.Windows.Media.Media3D.Point3D" mapVertColour.x mapVertColour.y mapVertColour.z
--print mapVertColour
--try and add it to the dictionary, if its already there then append the mv index to the value array
if palette.containsKey colourVec == true then
(
val = append palette.item[colourVec] mv
palette.remove colourVec
palette.add colourVec val
)
else
(
palette.add colourVec #(mv)
--add colourToPaletteIndex
append indexToColour colourVec
)
)
format "Colours Grabbed: % \n" palette.count
),
--reduce the number of entries in the item to maxColours
--merge the two closest pairs of colours until we hit maxColours
fn reduce maxColours =
(
if maxColours > palette.count then return false
point3D = dotNetClass "System.Windows.Media.Media3D.Point3D"
progressStart "Reducing: "
progressRange = palette.count - maxcolours
while palette.count > maxColours do
(
colourDistance = #()
paletteIt = palette.keys.getEnumerator()
innerIt = palette.keys.getEnumerator()
--start = timestamp()
while paletteIt.moveNext() != false do
(
colourA = paletteIt.current
--loop over the dict entries.
while innerIt.moveNext() != false do
(
colourB = innerIt.current
--get the distance between the two colours
vec = point3D.subtract colourA colourB
if vec.length > 0.0 then
(
--closest = DataPair distance:dist colours:#(colourA, colourB)
append colourDistance (DataPair distance:vec.length colours:#(colourA, colourB))
)
)
)
--end = timestamp()
--format "distance calc: % \n" ((end - start) / 1000.0)
--sort or pick the lowest distance pair
theDistances = for i in colourDistance collect i.distance
sort theDistances
closest = (for d in colourDistance where d.distance == theDistances[1] collect d)[1]
colourA = closest.colours[1]
colourB = closest.colours[2]
--combine the mapvert index arrays
combineIndices = #()
join combineIndices palette.item[colourA]
join combineIndices palette.item[colourB]
--combine palette indexes
colourA_idx = findItem indexToColour colourA
colourB_idx = findItem indexToColour colourB
indexToColour[colourA_idx] = undefined
indexToColour[colourB_idx] = undefined
--take the average of the 2 colours
r = colourA.x + (0.5 * (colourB.x - colourA.x))
g = colourA.y + (0.5 * (colourB.y - colourA.y))
b = colourA.z + (0.5 * (colourB.z - colourA.z))
newColour = dotNetObject "System.Windows.Media.Media3D.Point3D" r g b
--remove the 2 old colours
palette.remove colourA
palette.remove colourB
--add the new averaged colour with the combined mapvert index array
palette.add newColour combineIndices
append indexToColour newColour
--
--end = timestamp()
--format "reduce calc: % \n" ((end - start) / 1000.0)
--print "."
progressUpdate (100.0 * (palette.count - maxColours) / progressRange)
)
--remove dead indices from indexToColour
indexToColour = for col in indexToColour where col != undefined collect col
progressEnd()
),
fn paintToMesh channel =
(
--flush
for v = 1 to (meshop.getnummapverts $ channel) do meshop.setmapvert $ channel v [0, 0, 0]
update $
--iterate the palette keys setting the values(mapverts) to the key colour
palIt = palette.keys.getEnumerator()
while palIt.moveNext() != false do
(
theColour = palIt.current
mapVerts = palette.item[theColour]
theColour = [theColour.x, theColour.y, theColour.z]
for v in mapVerts do
(
meshop.setmapvert $ channel v theColour
)
)
update $
CompleteRedraw()
),
fn genPaletteIndexes =
(
for i = 1 to indexToColour.count do
(
for mv = 1 to palette.item[indexToColour[i]].count do
(
paletteIdx[palette.item[indexToColour[i]][mv]] = i
)
)
--format "paletteIdx count: % \n" paletteIdx.count
),
--insert an entry into the item at position idx
fn insert idx =
(
),
--remove and entry from the item and position idx
fn remove idx =
(
),
--remove any empty indexes by adjusting item indexes into empty slots
fn compact =
(
)
)
struct ClonePal
(
clonePals = #(),
paletteCount = 4,
masterPal = #(),
fn combinePalettes clones:$selection =
(
--reduce each object palette to an equal number of entries
--clones = $selection
for obj in clones do
(
--create a pop instance
pOp = PaletteOps()
pOp.grabMeshColours channel:13 obj:obj
pOp.reduce paletteCount
pOp.genPaletteIndexes()
append clonePals pOp
)
),
/*
fn gather =
(
--so row 1 is the master, we trawl the other palettes looking for the closest match, then we update the indices to match the position of row1
theOriginal = clonePals[1]
for p = 2 to clonePals.count do
(
--for each palette entry
for c = 1 to clonePals[p]
)
),
*/
fn reorder =
(
--reorder palette entries so each mapvert id is only in one column
--create a new array to hold the new palette
--masterPal = #()
--start with the first palette to compare against the others, this will be row 0
/*
rowZeroConstruct = dotNetObject "System.Object[]" paletteCount
clonePals[1].palette.values.copyTo rowZeroConstruct 0
rowZero = for i = 0 to (rowZeroConstruct.length - 1) collect rowZeroConstruct.getValue[i] as BitArray
*/
--rowZeroRaw = clonePals[1].palette.item[clonePals[1].indexToColour[1]]
--rowZero = rowZeroRaw as BitArray
--print rowZero
--add this first clonepal to the master
theOriginal = clonePals[1]
append masterPal theOriginal
--now sort out the rest
for pal = 2 to clonePals.count do
(
--the clone this iteration
theClone = clonePals[pal]
--the mapvert indices
palRowRaw = theClone.palette.item[theClone.indexToColour[1]]
for i = 1 to theOriginal.indexTocolour.count do
(
--format "i = % \n" i
orig_mv_Idxs = theOriginal.palette.item[theOriginal.indexToColour[i]] as BitArray
--format "orig_mv_Idxs: % \n" orig_mv_Idxs
for j = 1 to theClone.indexToColour.count do
(
--format "j = % \n" j
clone_mv_Idxs = theClone.palette.item[theClone.indexToColour[j]] as BitArray
--format "clone_mv_Idxs: % \n" clone_mv_Idxs
--if they cancel out then they match
--format "orig - clone: % \n" (orig_mv_Idxs - clone_mv_Idxs)
if orig_mv_Idxs * clone_mv_Idxs != #{} then
(
--swap j for i in the clone indexToColours
theSwap = theClone.indextoColour[i]
theClone.indextoColour[i] = theClone.indextoColour[j]
theClone.indextoColour[j] = theSwap
)
)
)
--generate the palette indices
theClone.genPaletteIndexes()
append masterPal theClone
/*
palIdx = 0
indexArray = dotNetObject "System.Object[]" paletteCount
palNextRaw = clonePals[pal].palette.values.copyTo indexArray 0
--convert palette indices as bitarray and compare using that
palNext = clonePals[pal].palette.item[clonePals[1].indexToColour[1]] as BitArray
--compare
for i = 1 to rowZero.count do
(
for j = 1 to palNext.count do
(
if rowZero[i] == palNext[j] then palIdx = i
)
)
*/
)
--print masterPal
)
)