Files
GS13/code/__HELPERS/matrices.dm
2021-01-09 01:50:54 -03:00

224 lines
7.1 KiB
Plaintext

/matrix/proc/TurnTo(old_angle, new_angle)
. = new_angle - old_angle
Turn(.) //BYOND handles cases such as -270, 360, 540 etc. DOES NOT HANDLE 180 TURNS WELL, THEY TWEEN AND LOOK LIKE SHIT
/atom/proc/SpinAnimation(speed = 10, loops = -1, clockwise = 1, segments = 3, parallel = TRUE)
if(!segments)
return
var/segment = 360/segments
if(!clockwise)
segment = -segment
var/list/matrices = list()
for(var/i in 1 to segments-1)
var/matrix/M = matrix(transform)
M.Turn(segment*i)
matrices += M
var/matrix/last = matrix(transform)
matrices += last
speed /= segments
if(parallel)
animate(src, transform = matrices[1], time = speed, loops , flags = ANIMATION_PARALLEL)
else
animate(src, transform = matrices[1], time = speed, loops)
for(var/i in 2 to segments) //2 because 1 is covered above
animate(transform = matrices[i], time = speed)
//doesn't have an object argument because this is "Stacking" with the animate call above
//3 billion% intentional
//Dumps the matrix data in format a-f
/matrix/proc/tolist()
. = list()
. += a
. += b
. += c
. += d
. += e
. += f
//Dumps the matrix data in a matrix-grid format
/*
a d 0
b e 0
c f 1
*/
/matrix/proc/togrid()
. = list()
. += a
. += d
. += 0
. += b
. += e
. += 0
. += c
. += f
. += 1
//The X pixel offset of this matrix
/matrix/proc/get_x_shift()
. = c
//The Y pixel offset of this matrix
/matrix/proc/get_y_shift()
. = f
/matrix/proc/get_x_skew()
. = b
/matrix/proc/get_y_skew()
. = d
//Skews a matrix in a particular direction
//Missing arguments are treated as no skew in that direction
//As Rotation is defined as a scale+skew, these procs will break any existing rotation
//Unless the result is multiplied against the current matrix
/matrix/proc/set_skew(x = 0, y = 0)
b = x
d = y
/////////////////////
// COLOUR MATRICES //
/////////////////////
/* Documenting a couple of potentially useful color matrices here to inspire ideas
// Greyscale - indentical to saturation @ 0
list(LUMA_R,LUMA_R,LUMA_R,0, LUMA_G,LUMA_G,LUMA_G,0, LUMA_B,LUMA_B,LUMA_B,0, 0,0,0,1, 0,0,0,0)
// Color inversion
list(-1,0,0,0, 0,-1,0,0, 0,0,-1,0, 0,0,0,1, 1,1,1,0)
// Sepiatone
list(0.393,0.349,0.272,0, 0.769,0.686,0.534,0, 0.189,0.168,0.131,0, 0,0,0,1, 0,0,0,0)
*/
//Does nothing
/proc/color_matrix_identity()
return list(1,0,0,0, 0,1,0,0, 0,0,1,0, 0,0,0,1, 0,0,0,0)
//Adds/subtracts overall lightness
//0 is identity, 1 makes everything white, -1 makes everything black
/proc/color_matrix_lightness(power)
return list(1,0,0,0, 0,1,0,0, 0,0,1,0, 0,0,0,1, power,power,power,0)
//Changes distance hues have from grey while maintaining the overall lightness. Greys are unaffected.
//1 is identity, 0 is greyscale, >1 oversaturates colors
/proc/color_matrix_saturation(value)
var/inv = 1 - value
var/R = round(LUMA_R * inv, 0.001)
var/G = round(LUMA_G * inv, 0.001)
var/B = round(LUMA_B * inv, 0.001)
return list(R + value,R,R,0, G,G + value,G,0, B,B,B + value,0, 0,0,0,1, 0,0,0,0)
//Changes distance colors have from rgb(127,127,127) grey
//1 is identity. 0 makes everything grey >1 blows out colors and greys
/proc/color_matrix_contrast(value)
var/add = (1 - value) / 2
return list(value,0,0,0, 0,value,0,0, 0,0,value,0, 0,0,0,1, add,add,add,0)
//Moves all colors angle degrees around the color wheel while maintaining intensity of the color and not affecting greys
//0 is identity, 120 moves reds to greens, 240 moves reds to blues
/proc/color_matrix_rotate_hue(angle)
var/sin = sin(angle)
var/cos = cos(angle)
var/cos_inv_third = 0.333*(1-cos)
var/sqrt3_sin = sqrt(3)*sin
return list(
round(cos+cos_inv_third, 0.001), round(cos_inv_third+sqrt3_sin, 0.001), round(cos_inv_third-sqrt3_sin, 0.001), 0,
round(cos_inv_third-sqrt3_sin, 0.001), round(cos+cos_inv_third, 0.001), round(cos_inv_third+sqrt3_sin, 0.001), 0,
round(cos_inv_third+sqrt3_sin, 0.001), round(cos_inv_third-sqrt3_sin, 0.001), round(cos+cos_inv_third, 0.001), 0,
0,0,0,1,
0,0,0,0)
//These next three rotate values about one axis only
//x is the red axis, y is the green axis, z is the blue axis.
/proc/color_matrix_rotate_x(angle)
var/sinval = round(sin(angle), 0.001); var/cosval = round(cos(angle), 0.001)
return list(1,0,0,0, 0,cosval,sinval,0, 0,-sinval,cosval,0, 0,0,0,1, 0,0,0,0)
/proc/color_matrix_rotate_y(angle)
var/sinval = round(sin(angle), 0.001); var/cosval = round(cos(angle), 0.001)
return list(cosval,0,-sinval,0, 0,1,0,0, sinval,0,cosval,0, 0,0,0,1, 0,0,0,0)
/proc/color_matrix_rotate_z(angle)
var/sinval = round(sin(angle), 0.001); var/cosval = round(cos(angle), 0.001)
return list(cosval,sinval,0,0, -sinval,cosval,0,0, 0,0,1,0, 0,0,0,1, 0,0,0,0)
//Returns a matrix addition of A with B
/proc/color_matrix_add(list/A, list/B)
if(!istype(A) || !istype(B))
return color_matrix_identity()
if(A.len != 20 || B.len != 20)
return color_matrix_identity()
var/list/output = list()
output.len = 20
for(var/value in 1 to 20)
output[value] = A[value] + B[value]
return output
//Returns a matrix multiplication of A with B
/proc/color_matrix_multiply(list/A, list/B)
if(!istype(A) || !istype(B))
return color_matrix_identity()
if(A.len != 20 || B.len != 20)
return color_matrix_identity()
var/list/output = list()
output.len = 20
var/x = 1
var/y = 1
var/offset = 0
for(y in 1 to 5)
offset = (y-1)*4
for(x in 1 to 4)
output[offset+x] = round(A[offset+1]*B[x] + A[offset+2]*B[x+4] + A[offset+3]*B[x+8] + A[offset+4]*B[x+12]+(y==5?B[x+16]:0), 0.001)
return output
/atom/proc/shake_animation(var/intensity = 8) //Makes the object visibly shake
var/initial_transform = new/matrix(transform)
var/init_px = pixel_x
var/shake_dir = pick(-1, 1)
var/rotation = 2+soft_cap(intensity, 1, 1, 0.94)
var/offset = 1+soft_cap(intensity*0.3, 1, 1, 0.8)
var/time = 2+soft_cap(intensity*0.3, 2, 1, 0.92)
animate(src, transform=turn(transform, rotation*shake_dir), pixel_x=init_px + offset*shake_dir, time=1)
animate(transform=initial_transform, pixel_x=init_px, time=time, easing=ELASTIC_EASING)
/*
This proc makes the input taper off above cap. But there's no absolute cutoff.
Chunks of the input value above cap, are reduced more and more with each successive one and added to the output
A higher input value always makes a higher output value. but the rate of growth slows
*/
/proc/soft_cap(var/input, var/cap = 0, var/groupsize = 1, var/groupmult = 0.9)
//The cap is a ringfenced amount. If we're below that, just return the input
if (input <= cap)
return input
var/output = 0
var/buffer = 0
var/power = 1//We increment this after each group, then apply it to the groupmult as a power
//Ok its above, so the cap is a safe amount, we move that to the output
input -= cap
output += cap
//Now we start moving groups from input to buffer
while (input > 0)
buffer = min(input, groupsize) //We take the groupsize, or all the input has left if its less
input -= buffer
buffer *= groupmult**power //This reduces the group by the groupmult to the power of which index we're on.
//This ensures that each successive group is reduced more than the previous one
output += buffer
power++ //Transfer to output, increment power, repeat until the input pile is all used
return output