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 ) )