Mix() and Clamp() functions
So, I was working on my raymarcher-in-progress and I remembered some interesting functions that I thought would be good to add into microstudio! These would work similarly to the min() or max() functions.
1: Mix() function
This function would take 3 arguments, and would basically mix the first two values according to the third value. The code would look like this:
output=x*(1-a)+y*a // 'A' would be a value from 0-1. Also, please note that similarly to the min() function it would not actually
give a variable output
2: Clamp() function
This function would also take 3 arguments, and would basically clamp the first value between the second value. The code would look like this:
clamp=function(x,bottom,top) // Clamps x value between bottom and top value
if bottom>top then
// This would be an error
And then you could use it like this:
I mean clamp already exists in mrLman's games-prog library.
As Crafter says. Quite easy to have a collection of helper functions tailored to your needs.
What would be useful would be if we could keep those snippets somewhere easily accessible.
Like a library tab, or something like that, where they are available project wide.
In FlowLab every user has his own 'Bundle' folder for that purpose, soooooo handy.
Another one I miss a lot is
fmod ; I often reimplement it in many projects I make.
fmod = function(x,y)
mix would be nice additions as well. I wouldn't bother having an error case in clamp though, I would probably stick on the GLSL implementation: https://www.khronos.org/registry/OpenGL-Refpages/gl4/html/clamp.xhtml
P.S. your mix() looks like what is commonly known as lerp() function.
@gilles ... trying to wrap my head around fmod() ...
What is the difference to the modulus operator? (x%y)
@TinkerSmith well first I called it
fmod which is misleading, I should call it simply
mod for clarity.
mod and the remainder operator
13 mod 10 = 3
13 rem 10 = 3 // same
-13 mod 10 = 7
-13 rem 10 = -3
I think a library of these functions would be a great idea! Maybe in the documentation tab? We could also do a distance function and a dot product function.
Also, yes, something like the 'lerp' function would work perfectly.
I don't know about other people, but I find myself using a
wrap function quite a lot. Similar to
clamp but instead of keeping a value within limits, it wraps the value around.
wrap = function(value, min, max)
if value > max then return min end
if value < min then return max end
Or in Lua:
function wrap(value, min, max)
return value > max and min or value < min and max or value
Although I could never decide if the first condition should be
value > max or
value >= max.
EDIT: a few days ago I noticed this wrap function doesn't do it properly. For example, given value
wrap(v+5, 10, 30) returns
10, but it should actually return
14. That function will only work for increments of 1.
Some I found that I often need:
dist2d=function(x1,y1,x2,y2) sqrt((x2-x1)^2+(y2-y1)^2) end
dist3d=function(x1,y1,x2,y2,z1,z2) sqrt((x2-x1)^2+(y2-y1)^2+(z2-z1)^2) end // fixed (thanks Gilles)
angle2d=function(x1,y1,x2,y2) 180-atan2d(x2-x1,y2-y1) end
rand=function(lo,hi) (hi-lo)*random.next()+lo end
lerp=function(v1,v2,amt) (1-amt)*v1+amt*v2 end
clamp=function(v,lo,hi) max(lo,min(v,hi)) end
sgn=function(v) (v>0)-(v<0) end
remap=function(v,s1,e1,s2,e2) (v-s1)*(e2-s2)/(e1-s1)+s2 end
not (x2>x1+w1 or x2+w2<x1 or y2>(y1+h1) or (y2+h2)<y1)
circlesOverlap=function(x1,y1,r1,x2,y2,r2) sqrt((x2-x1)^2+(y2-y1)^2)<abs(r2+r1) end
See also my post here if you would like to contribute other handy functions:
@JimB007 I just noticed a typo in the dist3d:
dist3d=function(x1,y1,x2,y2,z1,z2) sqrt((x2-x1)^2+(y2-y1)^2+(z2-z1)) end
dist3d=function(x1,y1,x2,y2,z1,z2) sqrt((x2-x1)^2+(y2-y1)^2+(z2-z1)^2) end
If you include a dist2d and dist3d, you risk distracting newbies from an easy efficiency lesson:
When calculating collisions between circle (or sphere) colliders, it's tempting to do something like this (pseudocode)
if distance_between(centre_of_a, centre_of_b) < (radius_of_a + radius_of_b)
else no collision
... but that involves a square root. Better then to do something like this:
if square_of_distance_between(centre_of_a, centre_of_b) < ((radius_of_a + radius_of_b) * (radius_of_a + radius_of_b))
else no collision
IIRC Unity has a square distance method for precisely this reason, and it's just the same as the distance function, but without the final square root operation.
If you're adding in a distance function, also adding the square distance function would actively push awareness of this sort of optimisation to new coders.
I note also that the "circlesOverlap" function can be optimised the same way:
circlesOverlap=function(x1,y1,r1,x2,y2,r2) ((x2-x1)^2+(y2-y1)^2)<(r2+r1)*(r2+r1) end
No need to calculate a square root this way, and it can save a surprising number of cycles when you've got a lot of collisions to check.
Wouldn't lerp be a better name than mix to avoid confusion? From my experience, it's a more common name for that kind of function than mix. Also maybe the circlesoverlap should be replaced with an ellipsesoverlap that has width and height instead of radius, it would be far more versatile.
@JmeJuniper, collisions between circles are different than between ellipses, though. You'd be making circle collision checking heavier than it needs to be. Plus, anyone only interested in circle collisions would have to provide more parameters to that function than necessary.
In terms of implementation, circles and ellipses are quite different, so it's probably a better idea to keep them separate.
@JmeJuniper agreed, lerp is better...
@JimBOO7 proposed addition to your handy functions
angletovector = function(ang)
return [sind(ang), cosd(ang)] // obviously returning a Vec2 object would be best here
Maybe documentation of vector classes would be a good idea as well?
@MyNameIsNotSir Good point! By the way, you can do
enclosed text like this and above using triple backquotes - just to make the code more readable :-)