Skip to content

Instantly share code, notes, and snippets.

@jasoncoon
Created August 21, 2022 15:55
Show Gist options
  • Save jasoncoon/cb2c0c9ebb6434dc4d719a78bdc42a80 to your computer and use it in GitHub Desktop.
Save jasoncoon/cb2c0c9ebb6434dc4d719a78bdc42a80 to your computer and use it in GitHub Desktop.
// Beating heart pattern. The heart shape is formed by a square turned 45 degees to form a \"diamond\" which is
// the base of the heart. Two semi-circles connect to the upper two sides of the \"diamond\" for the rounded heart
// portion. Depending on your resolution, you may want to play with the anti-aliasing distance to improve the
// definition and appearance of the heart's outline.
//
// Debra Ansell (GeekMomProejcts) 8/18/2022
// Ratio of the height of the heart to the length of one side of the diamond inside it
// length of one side of the diamond is also the diameter of the circle
var ratio = (0.5 + 3*sqrt(2)/4)
// Precompute
var sqr2_2 = sqrt(2)/2
export var delta = 0.05 // Max antialiasing distance
export var height = 0.8 // Height of heart in world units
export var xpos = 0.5 // x position of the bottom tip of the heart
export var ypos = (1-height)/2 // y position of the heart's tip for it to be centered vertically
export var L = height/ratio // Length of a side of the diagonal square forming the bottom of the heart
export var Lv = L*sqr2_2 // Half the vertical height of the \"diamond\"
var flip = true
export function toggleFlip(value) { flip = value }
var style = 0
export function triggerUpward() { style = 0 }
export function triggerDownward() { style = 1 }
export function triggerInward() { style = 2 }
export function triggerOutward() { style = 3 }
export function triggerClockwise() { style = 4 }
export function triggerCounterClockwise() { style = 5 }
export function beforeRender(delta) {
t1 = time(.02)
height = 0.5 + 0.3*sin(t1*PI) // Vary the heart's size with time to make it \"beat\"
L = height/ratio
Lv = L*sqr2_2
xc = Lv/2 // (xc,yc) are coordinates of the center of the circular part of the heart
yc = 3*Lv/2
ypos = 0.5 + height/2
xpos = 0.5
// Uncommenting the code below will cause the position of the heart to move around with time
//t2 = time(.035)
//t3 = time(.057)
//ypos = 0.45 + height/2 + 0.05*wave(t3)
//xpos = 0.3 + 0.2*wave(t2) + 0.2*wave(t3)
}
// The position of the bottom heart point is (x0,y0)
// Heart height and x0, y0 are given in world units
export function drawHeart(x, y, x0, y0, height, index) {
v = 0 // Intensity of the pixel
xn = abs(x - x0) // Take advantage of symmetry - only compute half of heart
yn = y0 - y // Remove y offset of heart for computations
if (yn < Lv) { // This portion of the heart is in the bottom half of the \"diamond\"
if (xn < yn) { // Point is inside the heart if it falls inside the line \"y=x\"
v = 1
} else { // Check to see if we are close enough for anti aliasing
d = (xn - yn)*sqr2_2 // Perpendicular distance to line x = y (makes a (90,45,45) triangle)
if (d < delta) { // Inside anti-aliasing distance of the straight portion of heart
v = 1-d/delta // Pixel intensity decreases with distance
}
}
} else { // Inside the curved portion of the heart
yd = abs(yn - yc) // Vertical distance from center of the circle
if (yn < 2*Lv) { // This portion of the heart is below the inverted point
if (xn < Lv/2 + sqrt(L*L/4 - yd*yd)) {
v = 1
}
} else { // This portion of the heart is above the inverted point
xd = abs(xn - xc) // Horizontal distance to center of the circular part of the heart
if (xd < sqrt(L*L/4 - yd*yd)) {
v = 1
}
}
if (v == 0) { // Anti alias the curved part of the heart
d = hypot(xn - xc, yn - yc) - L/2 // Distance from circle forming curved heart boundary
if (d < delta) {
v = 1-d/delta // Pixel intensity decreases with distance
}
}
}
if (style === 0) // upward
hsv(y + t1, 1, v*v)
else if (style === 1) // downward
hsv(y - t1, 1, v*v)
else if (style === 2) // inward
hsv(hypot(x - .5, y - .5) + t1, 1, v * v)
else if (style === 3) // outward
hsv(hypot(x - .5, y - .5) - t1, 1, v * v)
else { // rotating
x1 = (x - .5) * 2
y1 = (y - .5) * 2
dist = sqrt(x1 * x1 + y1 * y1)
angle = (atan2(y1, x1) + PI) / PI / 2
if (style === 4) // clockwise
hsv(angle + t1, 1, v*v) // hue depends on angle
else // counter-clockwise
hsv(angle - t1, 1, v*v) // hue depends on angle
}
}
export function render2D(index, x, y) {
if (flip)
drawHeart(x, 1-y, xpos, ypos, height, index)
else
drawHeart(x, y, xpos, ypos, height, index)
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment