ID:1946162
 
Has anyone found anything neat to do with any of the new features?

I'm curious as to what kind of hijinks can be performed with color matrices, client.color, and this bit:

Patch notes:
animate() can now be used with clients for limited values such as pixel offsets.

Does this mean we'll get some much wanted easing applicable to the client's eye for stuff like shaking and smooth camera panning?

Trying to wrap my head around color matrices. I guess they're just like normal transformation matrices, you just treat the rgb as you would an x,y,z coord.

This article has some further explanation if you're familiar with transform matrices:
https://msdn.microsoft.com/en-us/library/windows/desktop/ ms533875%28v=vs.85%29.aspx

Wrote this little test code to try rotating the color axes:
#define MULT33(A, B) (list(A[1]*B[1] + A[2]*B[4] + A[3]*B[7], \
A[1]*B[2] + A[2]*B[5] + A[3]*B[8], \
A[1]*B[3] + A[2]*B[6] + A[3]*B[9], \
\
A[4]*B[1] + A[5]*B[4] + A[6]*B[7], \
A[4]*B[2] + A[5]*B[5] + A[6]*B[8], \
A[4]*B[3] + A[5]*B[6] + A[6]*B[9], \
\
A[7]*B[1] + A[8]*B[4] + A[9]*B[7], \
A[7]*B[2] + A[8]*B[5] + A[9]*B[8], \
A[7]*B[3] + A[8]*B[6] + A[9]*B[9] ) )


mob
var
redTheta = 0
greenTheta = 0
blueTheta = 0
proc
UpdateColor()
var/list
rcos = cos(redTheta)
rsin = sin(redTheta)
red=list(1, 0, 0, \
0, rcos, rsin, \
0, -rsin, rcos)

gcos = cos(greenTheta)
gsin = sin(greenTheta)
green=list(gcos, 0, -gsin, \
0, 1, 0, \
gsin, 0, gcos)

bcos = cos(blueTheta)
bsin = sin(blueTheta)
blue=list(bcos, bsin, 0, \
-bsin, bcos, 0, \
0, 0, 1)
rg = MULT33(red, green)
rgb = MULT33(rg, blue)
client.color = rgb

mob/verb/RotateBlue()
blueTheta = (blueTheta+90)%360
UpdateColor()

mob/verb/RotateGreen()
greenTheta = (greenTheta+90)%360
UpdateColor()

mob/verb/RotateRed()
redTheta = (redTheta+90)%360
UpdateColor()

mob/verb/Run()
var/global/running = 0
var/runningId = ++running
if (running % 2)
while(runningId == running)
redTheta = (redTheta+1) % 360
greenTheta = (greenTheta+3) % 360
blueTheta = (blueTheta+5) % 360
UpdateColor()
sleep(world.tick_lag)
else
blueTheta = 0
greenTheta = 0
redTheta = 0
UpdateColor()


I think it would look cooler if I could find a rotation path that keeps all of the colors positive, though (negative values are clamped to 0)
What even happens when you rotate a color though? Like, visually, I have no idea what that looks like.
Imagine a color wheel. You can find one in paint or photoshop or online. The center is white, the top is red, 120 degrees is green, and 240 degrees is blue. All colors are simply spun around the wheel. So anything red spun 120 degrees becomes green, anything green becomes blue, and anything blue is red.
In response to MisterPerson
I think it's actually a 3d coordinate system (or 4d, if you're using alpha).

This is a horrible image to illustrate this, but it's the only one I could find online. Imagine if we were to rotate 90 degrees along the "green" axis:


You can see the blue axis moves to where the red axis was, and the red moves to the negative of the original blue. Effectively this would cause the blue components of the colors to become red, and the red components to become negative blue (which gets clamped to 0)

So the color #FFDDAA would become #AADD00:
#define MULT13_33(A, B) (list(A[1]*B[1] + A[2]*B[4] + A[3]*B[7], \
A[1]*B[2] + A[2]*B[5] + A[3]*B[8], \
A[1]*B[3] + A[2]*B[6] + A[3]*B[9] ) )

mob
verb/TestRotation()
var
// Start with color #FFDDAA
list/myColor = list(0xFF, 0xDD, 0xAA)

// Create a rotation matrix of 90deg around green axis
gcos = cos(90)
gsin = sin(90)
green=list(gcos, 0, -gsin, \
0, 1, 0, \
gsin, 0, gcos)

// Rotate our color
list/resultColor = MULT13_33(myColor, green)

// The result is #aadd00
world << rgb(resultColor[1], resultColor[2], resultColor[3])
Yeah it is a 3d sphere, I just wanted to limit it to 2d to make it a bit simpler.
Aye, if you leave out alpha, you can think of a color matrix as just 12 values, and each row in the matrix corresponds to what a given component will become. So take the classic "moonlight" matrix (with no constant row):

client.color = list(0.2,0.05,0.05, 0.1,0.3,0.2, 0.1,0.1,0.4)

That says that the red component effectively becomes #330D0D (for full red), the green becomes #1A4D33, and blue becomes #1A1A66, and the scaled values get added together. When I developed that matrix it was based on the knowledge that colors become more muted at night (hence why every color maps to a less saturated value), and greens and blues are less affected than red and yellow.

Going grayscale looks like this:

client.color = list(0.3,0.3,0.3, 0.59,0.59,0.59, 0.11,0.11,0.11)

The red row becomes 30% gray, green becomes 59%, and blue becomes 11%, and all those grays get added together. Any shade of gray will be untouched, but colors will desaturate because all of their individual red, green, and blue components become gray.

Color matrix interpolation is linear; unlike transform matrices, no effort is made to preserve rotation separately. In theory that'd be possible (rotation would be seen as a move around a 4D axis), but IMO there aren't any serious situations that call for it.
BTW, if you want to convert a 20-item matrix to 12 when you're not using alpha:

proc/NoAlphaColorMatrix(list/m)
if(m.len >= 20)
var d=0,s=0,r,c
for(r=0, r<5, ++r)
if(r == 3) // skip alpha row
++r; s += 4
for(c=0, c<3, ++c) m[++d] = m[++s]
++s // skip alpha col
m.len = d