Notifications
Clear all

[Closed] Maxscript Melting Pot: Post your hot functions

Most of you who have been scripting for some time have obviously made a library of shortcut and grunt functions that have saved you hours of coding by a quick call. If you feel so inclined, it would be great to have a repositry of useful snippets. (similar to prettyPixel’s Geometrical Calculation thread). Even lines of code that condense what could be a difficult task into a few short calculations are helpful.

So post away and help build a growing community of kickass scripters.

Naturally, comment your code so we know where it came from when we use it!!!

8 Replies

Good idea erilaz

To begin, here are some functions for arrays.

This function inverts the array :

fn reverseArray array = (
	local arrayCount=array.count
	for i=0 to (arrayCount-1) collect array[(arrayCount-i)]
	)
-- usage :
ar=#(25,2,12,86,99,0)
reverseArray ar

This function moves the elements of the array. The offset is negative :

fn offsetArray array offset = (
	if offset>0 do (
		local startSegArray=for i=(offset+1) to (array.count) collect array[i]
		local endSegArray=for i=1 to offset collect array[i]
		(startSegArray+endSegArray)
		)--if
	)
-- usage :
ar=#(25,2,12,86,99,0)
offsetArray2 ar 1
offsetArray2 ar 3

This function compares 2 arrays

fn compArray array1 array2 = (
	local count=array1.count
	if count!=array2.count then false
	else (
		for i=1 to count do ( if array1[i]!=array2[i] do return false )
		true
		)
	)
-- usage :
ar=#(25,2,12,86,99,0)
compArray ar #(25,2,12,86,99,0,2)
compArray ar #(25,2,13,86,99,0)
compArray ar #(25,2,12,86,99,0)
compArray #(25,2,12,86,99,0) ar

This function finds the common part of 2 arrays :

fn unionArray array1 array2 = (
	uA=#()
	for array1Elem in array1 do ( if (findItem array2 array1Elem!=0) then append uA array1Elem )
	uA
	)
-- usage :
ar=#(25,2,12,86,99,0)
unionArray ar #(25,2,12,86,99,0)
unionArray ar #(56,48,2,95,25)

This function removes elements in an array. The elements to remove are stored in the second array :

fn substractArray array array2remove = (
	for elem in array2remove do (
		local idx=findItem array elem
		if idx!=0 do deleteItem array idx
		)
	array
	)
-- usage :
ar=#(25,2,12,86,99,0)
substractArray ar #(44,86,12,25)

There are many useful functions… Where to begin?

Hey PrettyPixel,

You can also use the string method to compare arrays of any kind:

fn theSame a b = (a as string) == (b as string)

Light

--FUNCTION TO GET ZERO-PADDED FRAME NUMBERS:
  
  fn getZeros theNum = (substring "0000" 1 (4-(theStr = theNum as string).count) + theStr ) 
  --Usage:
  theFrame = 12
  newPath = "c:\	em\\filename_" + getZeros theFrame +".tga"
  -->"c:	em\filename_0012.tga"
  
  --NOTE: Works correctly in the range from 0 to 9999.

Alternative version of the same function:


fn reverseArray2 theArray = (for i = theArray.count to 1 by -1 collect theArray[i])

anArray = #(1,2,3,4,5,6,7,8,9,10)
#(1, 2, 3, 4, 5, 6, 7, 8, 9, 10)
reverseArray2 anArray
#(10, 9, 8, 7, 6, 5, 4, 3, 2, 1)


  
  fn hasModifier theObjects theModClass = (
 	for o in theObjects where 
 		(for m in o.modifiers where classof m == theModClass collect m).count > 0 
 			collect o
 )
 
 --Usage:
 --get those selected objects that have a Slice modifier applied:
 theSliced = hasModifier selection SliceModifier 
 
 --get the objects named Box* that have a Bend modifier applied:
 theBentBoxes = hasModifier $Box* Bend 
  
  

So far most of these hot functions would be just about as easy to write anew as to copy paste from the thread…but hows about some good geometry funcs? You guys must have a lot of those…and they always trip me up

Here’s a bunch of rigging functions I use all the time. I should probably go through these again, seems like I’m also learning new scripting tricks to make functions like these better:

/*----------------------------------------------------------------------------------------------------------------------------------------------
 # Description  :	(MAPPED) A modified version of the freeze transform script that ships with Max.
 # 		 	Creates a list controller for both the position and rotation of an object and then add new controllers
 # 		 	which can be used to reset the object's position and rotation to it's initial state.
 # Parameters :	<node>	 obj		 :	The object to freeze.
 # 		 	<boolean> position	:	If true, freezes the object's position controller. Default:true
 # 		 	<boolean> rotation	:	If true, freezes the object's rotation controller. Default:true
 */----------------------------------------------------------------------------------------------------------------------------------------------
 mapped fn freezePosRot obj position:true rotation:true = (
 	-- feeze position
 	if position then (
 		obj.position.controller = Bezier_Position()
 		obj.position.controller = position_list()
 		obj.position.controller.available.controller = Position_XYZ()
 		obj.position.controller.setname 1 "dontUse"
 		obj.position.controller.setname 2 "animate"
 		obj.position.controller.SetActive 2
 		)
 	
 	-- freeze rotation
 	if rotation then (
 		obj.rotation.controller = Euler_Xyz()
 		obj.rotation.controller = Rotation_list()
 		obj.rotation.controller.available.controller = Euler_xyz()
 		obj.rotation.controller.setname 1 "dontUse"
 		obj.rotation.controller.setname 2 "animate"
 		obj.rotation.controller.SetActive 2
     	-- set the axis order so that the Z axis (bend) will always rotate as expected in Gimbal mode
 		obj.rotation.controller[2].axisOrder = 6
 		)
 	)
 
 
 /*----------------------------------------------------------------------------------------------------------------------------------------------
 # Description  :	Find the root of an object by getting the last parent object in the chain.
 # Parameters : <node>	obj	 :	The object whose root you want to find.
 */----------------------------------------------------------------------------------------------------------------------------------------------
 fn findRoot obj = (
 	local p1 = obj.parent
 	for i = 1 to 10000 do (
 		p2 = p1.parent
 		if p2 == undefined then return p1 else p1 = p2
 		)
 	)
 
 /*----------------------------------------------------------------------------------------------------------------------------------------------
 # Description :	Gets the matrix3 value defined by two point3 values. Uses positive Z for the world up vector.
 # Parameters : <point3>	p1 	:	The vector's start position.
 # 		 		<point3> p2		:	The vector's end position.
 */----------------------------------------------------------------------------------------------------------------------------------------------
 fn buildMatrix p1 p2 = (
 	upVector = [0,0,1]
 	xVector = normalize (p2 - p1)
 	yVector = normalize (cross upVector xVector)
 	zVector = normalize (cross xVector yVector)
 	theMatrix = matrix3 xVector yVector zVector p1
 	)
 
 /*----------------------------------------------------------------------------------------------------------------------------------------------
 # Description :	Quicker way of creating a specific type of helper object. Sets display types off by default so that you only have to specify
 # 		 	the exact one you want turned on. If other display types aren't specifically set to off, then the settings of the last selected
 #					point helper will be used.
 # Parameters : <point3>	pos 		 	:	Position. Default: [0,0,0]
 # 		 		<number> size		 	:	Size. Default: 1
 # 		 		<string> name		 	:	Name. Default: uniqueName "Helper"
 # 		 		<boolean> centerMarker		: Sets the Center Marker checkbox. Default: off
 # 		 	<boolean> axistripod		 :	Sets the Axis Tripod checkbox. Default: off
 # 		 		<boolean> cross		 	:	Sets the Cross checkbox. Default: off
 # 	 		 <boolean>	box 		 	:	Sets the Box checkbox. Default: off
 # 		 		<boolean> constantScreenSize	:	Sets the Constant Screen Size checkbox. Default: off
 # 		 	<boolean> drawOnTop		 :	Sets the Draw On Top checkbox. Default: on
 */----------------------------------------------------------------------------------------------------------------------------------------------
 fn createPointHelper pos:[0,0,0] size:1 name:"Helper" centerMarker:off axistripod:off cross:off box:off constantScreenSize:off drawOnTop:on wirecolor:(color 0 255 255)= (
 	p = point pos:pos name:name centerMarker:centerMarker axistripod:axistripod cross:cross box:box size:size constantscreensize:constantScreenSize drawontop:drawOnTop
 	p.wirecolor = wirecolor
 	p.showFrozenInGray = false
 	p
 	)
 
 /*----------------------------------------------------------------------------------------------------------------------------------------------
 # Description :	(MAPPED) Mirrors a spline across the world X axis, using a supplied point3 value as the center to mirror about. 
 # Parameters : <node>		obj 		:	The spline to mirror.
 # 		 		<point3> centerPoint	:	The position in world space to mirror about.
 */----------------------------------------------------------------------------------------------------------------------------------------------
 mapped fn mirrorSplines obj centerPoint = (
 	if superClassOf obj == shape then (
 		local n = numKnots obj
 		local knotPosArr = for i = 1 to n collect (getKnotPoint obj 1 i)
 		local inVecPosArr = for i = 1 to n collect (getInVec obj 1 i)
 		local outVectPosArr = for i = 1 to n collect (getOutVec obj 1 i)
 		obj.pos.x += 2 * (centerPoint - obj.pos.x)
 		for i = 1 to n do (
 		setKnotPoint obj 1 i [(knotPosArr[i][1] + 2 *(centerPoint - knotPosArr[i][1])),knotPosArr[i][2],knotPosArr[i][3]]
 		setInVec obj 1 i [(inVecPosArr[i][1] + 2 * (centerPoint - inVecPosArr[i][1])),inVecPosArr[i][2],inVecPosArr[i][3]]
 		setOutVec obj 1 i [(outVectPosArr[i][1] + 2 * (centerPoint - outVectPosArr[i][1])),outVectPosArr[i][2],outVectPosArr[i][3]]
 			)
 		updateShape obj
 		)
 	)
 
 /*----------------------------------------------------------------------------------------------------------------------------------------------
 # Description :	(MAPPED) Adds a Position Constraint controller to the supplied obj, and constrains the obj to the supplied constrainTo object.
 # 		 	If the obj already has a Position List controller, then add the PC to the Available slot, if not then replace the position
 #    		    	controller completely with the PC controller.
 # Parameters : <node>		obj 		 :	The obj to add the controller to.
 # 		 		<node> 	constrainTo	 :	The obj to be constrained to.
 # 		 		<boolean> replaceList		:	If true, the new controller is not added to an existing list controller, but replaces it instead.
 #	 		 		 		 		Default:false
 */----------------------------------------------------------------------------------------------------------------------------------------------
 mapped fn addPositionConstraint obj constrainTo keepOffset:false replaceList:false = (
 	local pc = Position_Constraint ()
 	-- if the position controller is a Position List then add the pc to the available slot
 	if classOf obj.position.controller == Position_List and replaceList == false then (
 		obj.position.controller.available.controller = pc
 		-- get the number of the pc controller
 		local numCon = obj.position.controller.getCount()
 		-- set the controller's name
 		obj.position.controller.setName numCon "posCon"
 		obj.position.controller.setActive numCon
 		)
 	-- replace position controller if it's not a Position List
 	if classOf obj.position.controller != Position_List or replaceList == true then (
 		obj.position.controller = pc
 		)
 	-- set the attributes of the controller
 	if classOf constrainTo != array then (pc.appendTarget constrainTo 100)
 	if classOf constrainTo == array then (
 		local n = constrainTo.count
 		for i = 1 to n do (
 			pc.appendTarget constrainTo[i] (100 / n)
 			)
 		)
 	pc.relative = keepOffset
 	-- return the position constraint controller
 	pc
 	)
 
 /*----------------------------------------------------------------------------------------------------------------------------------------------
 # Description :	(MAPPED) Adds a Path Constraint controller to the supplied obj, and constrains the obj to the supplied spline object.
 #	 			If the obj already has a Position List controller, then add the PC to the Available slot, if not then replace the position
 #    		    	controller completely with the PC controller.
 # Parameters : <node>		obj 		 :	The obj to add the controller to.
 # 		 		<node> 	pathSpl	 	:	The path to be constrained to.
 # 		 		<number> percent		 :	The percentage along the path to set the obj. Default: 0
 # 	 		 <boolean>	replaceList 	:	If true, the new controller is not added to an existing list controller, but replaces it instead.
 # 		 		 		 			Default:false
 */----------------------------------------------------------------------------------------------------------------------------------------------
 mapped fn addPathConstraint obj pathSpl percent:0 keepOffset:false replaceList:false = (
 	local pc = path_constraint()
 	-- if the position controller is a Position List then add the pc to the available slot
 	if classOf obj.position.controller == Position_List and replaceList == false then (
 		obj.position.controller.available.controller = pc
 		-- get the number of the pc controller
 		local numCon = obj.position.controller.getCount()
 		-- set the controller's name
 		obj.position.controller.setName numCon "pathCon"
 		obj.position.controller.setActive numCon
 		)
 	-- replace position controller if it's not a Position List
 	if classOf obj.position.controller != Position_List or replaceList == true then (
 		obj.position.controller = pc
 		)
 	-- set the attributes of the controller
 	pc.path = pathSpl
 	pc.percent = percent
 	pc.follow = off
 	pc.constantVel = on
 	pc.loop = off
 	pc.relative = keepOffset
 	-- remove keys
 	deleteKeys pc
 	-- return the path constraint controller
 	pc
 	)
 
 /*----------------------------------------------------------------------------------------------------------------------------------------------
 # Description :	(MAPPED) Adds a Look At controller to the supplied obj, and constrains the obj to the supplied constrainTo object.
 #	 			If the obj already has a Rotation List controller, then add the Look At to the Available slot, if not then replace the rotation
 #    		    	controller completely with the controller.
 # Parameters : <node>		obj 		 :	The obj to add the controller to.
 # 		 		<node> 	lookAtObj	 	:	The obj to look at.
 # 		 		<node> 	upnode	 	:	The Upnode to use. If not defined, then the Upnode is set to World.
 # 		 	<string> sourceAxis		:	The Source Axis to use. Default: "X"
 # 		 	<boolean> flipSourceAxis	:	Whether or not the Source Axis is flipped. Default: off
 # 		 	<string> upnodeAxis		:	The Aligned To Upnode Axis to use. Default: "X"
 # 		 	<boolean> replaceList		:	If true, the new controller is not added to an existing list controller, but replaces it instead.
 #	 		 		 		 		Default:false
 */----------------------------------------------------------------------------------------------------------------------------------------------
 mapped fn addLookAt obj lookAtObj upnode:undefined lookAtAxis:"X" flipLookAtAxis:off sourceAxis:"X" flipSourceAxis:off upnodeAxis:"X" keepOffset:false replaceList:false = (
 	local lac = LookAt_Constraint ()
 	-- if the rotation controller is a Rotation List then add the lac to the available slot
 	if classOf obj.rotation.controller == Rotation_List and replaceList == false then (
 		obj.rotation.controller.available.controller = lac
 		-- get the number of the pc controller
 		local numCon = obj.rotation.controller.getCount()
 		-- set the controller's name
 		obj.rotation.controller.setName numCon "rotLookAt"
 		obj.rotation.controller.setActive numCon
 		)
 	-- replace rotation controller if it's not a Rotation List
 	if classOf obj.rotation.controller != Rotation_List or replaceList == true then (
 		obj.rotation.controller = lac
 		)
 	-- set the attributes of the controller
 	lac.appendTarget lookAtObj 100
 	lac.lookat_vector_length = 0
 	lac.relative = keepOffset
 	if upnode == undefined then lac.upnode_world = on
 	if upnode != undefined then (
 		lac.upnode_world = off
 		lac.pickUpNode = upnode
 		)
 	lac.target_axis = case lookAtAxis of (
 		"X":0
 		"Y":1
 		"Z":2
 		)
 	lac.target_axisFlip = flipLookAtAxis
 	lac.StoUP_axis = case sourceAxis of (
 		"X":0
 		"Y":1
 		"Z":2
 		)
 	lac.StoUP_axisFlip = flipSourceAxis
 	lac.upnode_axis = case upnodeAxis of (
 		"X":0
 		"Y":1
 		"Z":2
 		)
 	-- return the look at controller
 	lac
 	)
 
 /*----------------------------------------------------------------------------------------------------------------------------------------------
 # Description :	(MAPPED) Adds an Orientation Constraint controller to the supplied obj, and constrains the obj to the supplied constrainTo object.
 # 		 	If the obj already has a Rotation List controller, then add the PC to the Available slot, if not then replace the position
 #    		    	controller completely with the PC controller.
 # Parameters : <node>		obj 		 :	The obj to add the controller to.
 # 		 		<node> 	constrainTo	 :	The obj to be constrained to.
 # 		 		<boolean> replaceList		:	If true, the new controller is not added to an existing list controller, but replaces it instead.
 #	 		 		 		 		Default:false
 */----------------------------------------------------------------------------------------------------------------------------------------------
 mapped fn addOrientationConstraint obj constrainTo keepOffset:false replaceList:false = (
 	local oc = Orientation_Constraint ()
 	-- add the oc to the available slot of the rotation list controller
 	if classOf obj.rotation.controller == Rotation_List and replaceList == false then (
 		obj.rotation.controller.available.controller = oc
 		-- get the number of the pc controller
 		local numCon = obj.rotation.controller.getCount()
 		-- set the controller's name
 		obj.rotation.controller.setName numCon "orientCon"
 		obj.rotation.controller.setActive numCon
 		)
 	-- replace rotation controller
 	if classOf obj.rotation.controller != Rotation_List or replaceList == true then (
 		obj.rotation.controller = oc
 		)
 	-- set the attributes of the controller
 	oc.appendTarget constrainTo 100
 	oc.relative = keepOffset
 	-- return the orientation constraint controller
 	oc
 	)
 
 /*----------------------------------------------------------------------------------------------------------------------------------------------
 # Description :	Creates a new bone such that the X axis is the twist, the Y axis is side to side rotation, and the Z axis is the bend.
 #	 			Also freezes the transform of the bone after creation, so that doesn't need to be done seperately.
 # Parameters : <matrix3>	p1 		:	The start point of the bone.
 #	 		 <number>	p2 		:	The end point of the bone.
 #	 		 <number>	width 	:	Width of the bone. Default: 1
 #		 		<number> height		:	Height of the bone. Default: 1
 #	 		 <string>	name 	:	Name of the bone. Adds a number at the end of the name to keep it unique. Default: "Bone"
 # 		 	<string> side		:	Either "LT" (left), "RT" (right), or "CTR" (center). Used to determine what color the bone is.
 #	 		 		 		 	Defualt: "CTR"
 # 		 	<boolean> stretchy	:	Set the Freeze Length attribute of the bone. Default: false
 */----------------------------------------------------------------------------------------------------------------------------------------------
 fn createNewBone p1 p2 width:1 height:1 name:"Bone" side:"CTR" stretchy:false = (
 	local matrix = buildMatrix p1 p2
 	local length = distance p1 p2
 	local startPos = matrix.position
 	local endPos = [startPos.x + length,startPos.y,startPos.z]
 	local b = boneSys.createBone startPos endPos [0,1,0]
 	-- set properties of the bone
 	b.width = width
 	b.height = height
 	b.taper = 30
 	b.sideFins = off
 	b.frontFin = off
 	b.backFin = off
 	-- rotate bone into place
 	in coordsys matrix (b.rotation = (quat 1 0 0 1))
 	-- set the color of the bone
 	if side == "LT" then b.wirecolor = (color 28 28 177)
 	if side == "RT" then b.wirecolor = (color 6 134 6)
 	if side == "CTR" then b.wirecolor = (color 8 110 134)
 	-- set name of bone
 	b.name = name
 	-- set freeze length attribute
 	if stretchy then b.boneFreezeLength = false
 	-- turn off the "Show Frozen In Gray" property, I hate that :)
 	b.showFrozenInGray = false
 
 	return b
 	)
 
 /*----------------------------------------------------------------------------------------------------------------------------------------------
 # Description :	Creates a chain of bones using either an array of point3 values or objects. This function calls the "createNewBone" function
 #					to create the individual bones.
 # Parameters : <array>	arr 		 	:	Array that contains the positions or objects to use as end points for the bones.
 # 		 	<number> width		 	:	The width of the bones. Default: 1
 #		 		<number> height		 	:	The height of the bones. Default: 1
 #		 		<boolean> constrainToHelpers	:	Settings this to true applies both a position and look at constraint to each of the bones,
 #		 		 		 		 		and assigns the helper objects as targets. This lets you use helpers objects to move and rotate
 # 		 		 		 		 	the bones. Default: false
 # 		 	<boolean> stretchy		 :	Set the Freeze Length attribute of the bone. Default: false
 */----------------------------------------------------------------------------------------------------------------------------------------------
 fn createBoneChain arr width:1 height:1 constrainToHelpers:false stretchy:false = (
 	local boneArr = #()
 	for i = 2 to arr.count do (
 		-- check to see what type of values the array is using.
 		-- should be either point3 or some type of object.
 		local theClass = classOf arr[1]
 		-- get the two points to use as the beginning and end of the bone.
 		-- if the array is not made up of point3 values, use the object's position.
 		local p1 = if theClass == point3 then arr[i - 1] else arr[i - 1].transform.position
 		local p2 = if theClass == point3 then arr[i] else arr[i].transform.position
 		-- set some defaults for the bone's name.
 		local hlpName = if theClass == point3 then "Bone" else arr[i].name
 		-- make the bone using the "createNewBone" function
 		local bn = createNewBone p1 p2 width:width height:height name:hlpName stretchy:stretchy
 		-- change "HLP" to "BN" in the bone's name if needed
 		local n = findString bn.name "HLP"
 		if n != undefined then (bn.name = replace bn.name n 3 "BN")
 		-- add the position and look at constraints if constrainToHelpers is set to true
 		if constrainToHelpers then (addLookAt bn arr[i] upnode:arr[i])
 		if constrainToHelpers then (addPositionConstraint bn arr[i - 1])
 		-- add the new bone to the bone array
 		append boneArr bn
 		-- create nub
 		if i == arr.count then (
 			-- make the nub bone using the "createNewBone" function
 		local bnNub = createNewBone p2 (p2 + ((distance p1 p2) * .1)) width:(width * .25) height:(height * .25) name:(bn.name + "_nub")
 			in coordsys bn (bnNub.rotation = (quat 0 0 0 1))
 			bnNub.pos = p2
 			-- add the position constraint if constrainToHelpers is set to true.
 		-- no look at controller is needed because this bone at the end of the chain with nothing to look at.
 			if constrainToHelpers then (addPositionConstraint bnNub arr[i])
 			-- add the new bone to the bone array
 			append boneArr bnNub
 			)
 		)
 	-- link bones
 	for i = 2 to boneArr.count do (
 		boneArr[i].parent = boneArr[i - 1]
 		)
 	-- return the bone array
 	boneArr	
 	)
 
 
 /*----------------------------------------------------------------------------------------------------------------------------------------------
 # Description : Returns an array of nodeTansformMonitor objects for created loose references to noded. If only one object is passed in instead
 #		 	 of an array, one nodeTansformMonitor object is returned.
 # Parameters : <array> arr		 		 	:	Array of nodes to reference.
 # 		 <bool>	 forwardTransformChangeMsgs	:	From the help file: "If true (default), node transform messages from the monitored node 
 #	 		 		 		 		 	invalidate the dependents of the NodeTransformMonitor instance. If false, only deletion 
 # 		 		 		 		 		of the monitored node invalidates the dependents of the NodeTransformMonitor instance."
 # 		 		 		 		 		Default: false
 */----------------------------------------------------------------------------------------------------------------------------------------------
 fn getLooseReference arr forwardMessages:false = (
 	local tempArr = undefined
 	if classOf arr != array then tempArr = #(arr) else tempArr = arr
 	nodeArr = for obj in tempArr collect (
 		ntm = nodeTransformMonitor()
 		ntm.node = obj
 		ntm.forwardTransformChangeMsgs = forwardMessages
 		ntm
 		)
 	if nodeArr.count == 1 then return nodeArr[1]
 	else return nodeArr
 	) -- end getLooseReference

Here’s some compositing functions you guys might find useful if you ever have to do any straight composites with render passes. No comments because I’m an awful coder, just pass the functions two pixels (as color values) and an optional opacity value (as opacityV:<float>), and they’ll return the composite as a color value. The first three functions are necessary.

edit: Ok the code is fixed, opacityMod() definition was missing an argument.


fn cToV colorVal =
(
tempVal = colorVal as point3
return [(tempVal.x/255), (tempVal.y/255), (tempVal.z/255)]
)
fn vToC valueVal =
(
return [(valueVal.x*255 as integer), (valueVal.y*255 as integer), (valueVal.z*255 as integer)] as color
)
fn opacityMod pixelR pixelB opacityV =
(
pixelR.x = pixelB.x + (pixelR.x - pixelB.x)*opacityV
pixelR.y = pixelB.y + (pixelR.y - pixelB.y)*opacityV
pixelR.z = pixelB.z + (pixelR.z - pixelB.z)*opacityV
return pixelR
)
 
fn normalBlend pixelB pixelS opacityV: =
(
pixelB = cToV pixelB
pixelS = cToV pixelS
pixelR = [pixelS.x, pixelS.y, pixelS.z]
 
if not opacityV == unsupplied then
return vToC (opacityMod pixelR pixelB opacityV)
else
return vToC pixelR 
)
fn averageBlend pixelB pixelS opacityV: =
(
pixelB = cToV pixelB
pixelS = cToV pixelS
pixelR = [(pixelB.x+pixelS.x)/2, (pixelB.y+pixelS.y)/2, (pixelB.z+pixelS.z)/2]
 
if not opacityV == unsupplied then
return vToC (opacityMod pixelR pixelB opacityV)
else
return vToC pixelR
)
fn multiplyBlend pixelB pixelS opacityV: =
(
pixelB = cToV pixelB
pixelS = cToV pixelS
pixelR = [pixelB.x*pixelS.x, pixelB.y*pixelS.y, pixelB.z*pixelS.z]
 
if not opacityV == unsupplied then
return vToC (opacityMod pixelR pixelB opacityV)
else
return vToC pixelR
)
fn screenBlend pixelB pixelS opacityV: =
(
pixelB = cToV pixelB
pixelS = cToV pixelS
pixelR = [pixelB.x+pixelS.x-pixelB.x*pixelS.x, pixelB.y+pixelS.y-pixelB.y*pixelS.y, pixelB.z+pixelS.z-pixelB.z*pixelS.z]
 
if not opacityV == unsupplied then
return vToC (opacityMod pixelR pixelB opacityV)
else
return vToC pixelR
)
fn darkenBlend pixelB pixelS opacityV: =
(
pixelB = cToV pixelB
pixelS = cToV pixelS
pixelR = [0,0,0] 
if pixelB.x > pixelS.x then pixelR.x = pixelS.x else pixelR.x = pixelB.x
if pixelB.y > pixelS.y then pixelR.y = pixelS.y else pixelR.y = pixelB.y
if pixelB.z > pixelS.z then pixelR.z = pixelS.z else pixelR.z = pixelB.z 
 
if not opacityV == unsupplied then
return vToC (opacityMod pixelR pixelB opacityV)
else
return vToC pixelR
)
fn lightenBlend pixelB pixelS opacityV: =
(
pixelB = cToV pixelB
pixelS = cToV pixelS
pixelR = [0,0,0] 
if pixelB.x < pixelS.x then pixelR.x = pixelS.x else pixelR.x = pixelB.x
if pixelB.y < pixelS.y then pixelR.y = pixelS.y else pixelR.y = pixelB.y
if pixelB.z < pixelS.z then pixelR.z = pixelS.z else pixelR.z = pixelB.z 
 
if not opacityV == unsupplied then
return vToC (opacityMod pixelR pixelB opacityV)
else
return vToC pixelR
)
fn differenceBlend pixelB pixelS opacityV: =
(
pixelB = cToV pixelB
pixelS = cToV pixelS
pixelR = [abs (pixelB.x-pixelS.x), abs (pixelB.y-pixelS.y), abs (pixelB.z-pixelS.z)]
 
if not opacityV == unsupplied then
return vToC (opacityMod pixelR pixelB opacityV)
else
return vToC pixelR
)
fn negationBlend pixelB pixelS opacityV: =
(
pixelB = cToV pixelB
pixelS = cToV pixelS
pixelR = [1-(abs (1-pixelB.x-pixelS.x)), 1-(abs (1-pixelB.y-pixelS.y)), 1-(abs (1-pixelB.z-pixelS.z))]
 
if not opacityV == unsupplied then
return vToC (opacityMod pixelR pixelB opacityV)
else
return vToC pixelR 
)
fn exclusionBlend pixelB pixelS opacityV: =
(
pixelB = cToV pixelB
pixelS = cToV pixelS
pixelR = [pixelB.x+pixelS.x-2*pixelB.x*pixelS.x, pixelB.y+pixelS.y-2*pixelB.y*pixelS.y, pixelB.z+pixelS.z-2*pixelB.z*pixelS.z]
 
if not opacityV == unsupplied then
return vToC (opacityMod pixelR pixelB opacityV)
else
return vToC pixelR 
)
fn overlayBlend pixelB pixelS opacityV: =
(
pixelB = cToV pixelB
pixelS = cToV pixelS
pixelR = [0,0,0]
 
if pixelB.x <= 0.5 then
(
pixelR.x = 2*pixelB.x*pixelS.x
)
else
(
pixelR.x = 1-2*(1-pixelB.x)*(1-pixelS.x)
)
 
if pixelB.y <= 0.5 then
(
pixelR.y = 2*pixelB.y*pixelS.y
)
else
(
pixelR.y = 1-2*(1-pixelB.y)*(1-pixelS.y)
)
 
if pixelB.z <= 0.5 then
(
pixelR.z = 2*pixelB.z*pixelS.z
)
else
(
pixelR.z = 1-2*(1-pixelB.z)*(1-pixelS.z)
)
if not opacityV == unsupplied then
return vToC (opacityMod pixelR pixelB opacityV)
else
return vToC pixelR
)
fn hardLightBlend pixelB pixelS opacityV: =
(
pixelB = cToV pixelB
pixelS = cToV pixelS
pixelR = [0,0,0]
 
if pixelS.x <= 0.5 then
(
pixelR.x = 2*pixelB.x*pixelS.x
)
else
(
pixelR.x = 1-2*(1-pixelB.x)*(1-pixelS.x)
)
 
if pixelS.y <= 0.5 then
(
pixelR.y = 2*pixelB.y*pixelS.y
)
else
(
pixelR.y = 1-2*(1-pixelB.y)*(1-pixelS.y)
)
 
if pixelS.z <= 0.5 then
(
pixelR.z = 2*pixelB.z*pixelS.z
)
else
(
pixelR.z = 1-2*(1-pixelB.z)*(1-pixelS.z)
)
if not opacityV == unsupplied then
return vToC (opacityMod pixelR pixelB opacityV)
else
return vToC pixelR
)
fn softLightBlend pixelB pixelS opacityV: =
(
pixelB = cToV pixelB
pixelS = cToV pixelS
pixelR = [2*pixelB.x*pixelS.x+(pow pixelB.x 2)-2*(pow pixelB.x 2)*pixelS.x, 2*pixelB.y*pixelS.y+(pow pixelB.y 2)-2*(pow pixelB.y 2)*pixelS.y, 2*pixelB.z*pixelS.z+(pow pixelB.z 2)-2*(pow pixelB.z 2)*pixelS.z]
 
if not opacityV == unsupplied then
return vToC (opacityMod pixelR pixelB opacityV)
else
return vToC pixelR 
)
fn colorDodgeBlend pixelB pixelS opacityV: =
(
pixelB = cToV pixelB
pixelS = cToV pixelS
pixelR = [pixelB.x/(1-pixelS.x), pixelB.y/(1-pixelS.y), pixelB.z/(1-pixelS.z)]
 
if not opacityV == unsupplied then
return vToC (opacityMod pixelR pixelB opacityV)
else
return vToC pixelR 
)
fn inverseDodgeBlend pixelB pixelS opacityV: =
[font=Lucida Console](
pixelB = cToV pixelB
pixelS = cToV pixelS
pixelR = [pixelS.x/(1-pixelB.x), pixelS.y/(1-pixelB.y), pixelS.z/(1-pixelB.z)]
 
if not opacityV == unsupplied then
return vToC (opacityMod pixelR pixelB opacityV)
else
return vToC pixelR 
)
[/font]