-
-
Save dockimbel/f6cd4c455a5e91b76e682d02898a69ce to your computer and use it in GitHub Desktop.
Heart animation for Red (only). Now with a complete control panel to play with the animations parameters. Nice time eater ;-)
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Red [ | |
title: "Heart animation" | |
author: "Didier Cadieu" | |
notes: { | |
Traduction in Red/Rebol of Terebus Volodymyr javascript demo : http://codepen.io/tvolodimir/pen/wqKuJ | |
} | |
Needs: View | |
] | |
;*** Settings | |
bkg-color: 0.0.0.255 | |
b-size: 400x400 | |
v-rate: 30 | |
target-scale: 1.0 | |
show-fps?: no | |
with-alpha?: yes | |
time-delta: 0.02 | |
trace-offset: 0.7 | |
target-scale: 1.5 | |
clear-speed: 16 | |
; Quick or slow animation | |
quick?: false | |
trace-count: either quick? [20] [50] | |
dr: either quick? [0.3] [0.1] | |
;*** Init | |
img: none ; for compilation to not error out | |
canvas: make image! reduce [b-size bkg-color] | |
;*** Functions to comptue the heart form points | |
heart-position: func [rad] [ | |
; reduce [sin rad cos rad] | |
reduce [power sin rad 3 negate (15 * cos rad) - (5 * cos 2 * rad) - (2 * cos 3 * rad) - cos 4 * rad] | |
] | |
scale-and-translate: func [pos sx sy dx dy] [ | |
reduce [dx + pos/1 * sx dy + pos/2 * sy] | |
] | |
build-points: func [sx sy dx dy /local i tau] [ | |
tau: pi * 2 | |
i: 0.0 | |
while [i <= tau] [ | |
append/only points-origin scale-and-translate heart-position i sx sy dx dy | |
i: i + dr | |
] | |
] | |
points-origin: [] | |
build-points 210 13 0 -2 | |
build-points 150 9 0 -2 | |
build-points 90 5 0 -2 | |
target-length: heart-points-count: length? points-origin | |
target-count: 0 | |
target-points: copy/deep points-origin | |
do set-clearing: does [ | |
clearing: compose clear-code: [fill-pen (bkg-color - (0.0.0.1 * clear-speed)) box -1x-1 (canvas/size)] | |
] | |
pulse: func [kx ky] [ | |
repeat i length? points-origin [ | |
target-points/:i/1: kx * points-origin/:i/1 + canvas/size/x / 2 | |
target-points/:i/2: ky * points-origin/:i/2 + canvas/size/y / 2 | |
] | |
] | |
give-color: func [obj type /local c] [ | |
switch type [ | |
1 [ | |
c: 128.0.0.196 + random 127.75.75.0 | |
c/3: c/2 | |
] | |
2 [c: random 255.255.255.96] | |
] | |
if not with-alpha? [c/4: 255] | |
obj/f: c | |
obj/a: 1.0 * c/4 / 255 ; alpha of the color | |
obj/oma: 1.0 - obj/a ; complemented alpha | |
obj/f: c * obj/a ; "weigth" of the pixel color regarding alpha value | |
obj/f/4: 0 ; alpha already used | |
] | |
sparks: [] | |
repeat i heart-points-count [ | |
point: reduce [random 1.0 * canvas/size/x random 1.0 * canvas/size/y] | |
append sparks context [ | |
vx: vy: 0 | |
R: 2 | |
speed: 5.0 + random 1.0 | |
q: random heart-points-count | |
D: 2 * (i // 2) - 1 | |
force: 0.7 + random 0.2 | |
f: a: oma: none | |
give-color self 1 | |
trace: copy [] | |
loop trace-count [append/only trace copy point] | |
] | |
] | |
time: 0.0 | |
draw-sparks: has [n n2 i u q dx dy length] [ | |
t1: now/time/precise | |
n: cos time | |
n2: target-scale + n * 0.5 | |
pulse n2 n2 | |
time: time + (time-delta * any [all [0 > sin time 9.0] any [all [n > 0.8 0.2] 1.0]]) | |
draw canvas clearing | |
i: length? sparks | |
while [i > target-count] [ | |
u: pick sparks i | |
q: pick target-points u/q | |
dx: u/trace/1/1 - q/1 | |
dy: u/trace/1/2 - q/2 | |
length: sqrt dx * dx + (dy * dy) | |
if 10 > length [ | |
either 95 < random 100 [ | |
u/q: random heart-points-count | |
] [ | |
if 99 < random 100 [u/D: negate u/D] | |
u/q: u/q + u/D | |
u/q: u/q // heart-points-count + 1 | |
if 0 > u/q [ | |
u/q: u/q + heart-points-count | |
] | |
] | |
] | |
u/vx: u/vx - (dx / length * u/speed) | |
u/vy: u/vy - (dy / length * u/speed) | |
u/trace/1/1: u/trace/1/1 + u/vx | |
u/trace/1/2: u/trace/1/2 + u/vy | |
u/vx: u/vx * u/force | |
u/vy: u/vy * u/force | |
k: next u/trace | |
forall k [ | |
n: k/-1 | |
n2: k/1 | |
n2/1: n2/1 - (n2/1 - n/1 * trace-offset) | |
n2/2: n2/2 - (n2/2 - n/2 * trace-offset) | |
] | |
k: at u/trace (length? u/trace) - trace-count | |
forall k [ | |
all [ | |
c: pick canvas point: to-pair k/1 ; some points may be outside the image | |
poke canvas point c * u/oma + u/f ; compute the new pixel color based on previous value and new one pondered by alpha value. | |
] | |
] | |
i: i - 1 | |
] | |
; poke canvas 1x1 pick canvas 1x1 ; needed if comp? = off : no refesh without that (despite the clearing) | |
show img | |
; display max FPS in the top left corner | |
if show-fps? [draw canvas reduce ['pen 200.200.200 'text 0x0 form 0.01 * to-integer to-float 100 / (now/time/precise - t1)]] | |
] | |
recolor: func [type] [ | |
foreach u sparks [give-color u type] | |
] | |
system/view/auto-sync?: no | |
img-tog: draw make image! 18x18 [polygon 1x1 18x1 9x18] | |
q: :quit | |
view/flags/no-wait layout [ | |
backdrop black | |
title "Heart animation" | |
origin 0x0 space 0x0 below | |
img: image canvas rate v-rate on-time [draw-sparks] | |
cp: panel [ | |
backdrop black | |
origin 0x0 space 2x2 | |
style label: text black font-color white | |
style cval: field black font-color white disabled 40 | |
style sld: slider black | |
style btn: button 0x18 | |
base " Control panel" black 84x18 font-color gray draw [rotate 0 6x9 fill-pen gray polygon 0x5 12x5 6x13] [ | |
face/draw/2: 180 - face/draw/2 | |
cp/size/y: cp/extra - cp/size/y | |
cp/parent/size/y: cp/offset/y + cp/size/y | |
show cp/parent | |
] return | |
label "Pulse speed" f-dt: cval data time-delta sld on-create [face/data: round/to time-delta * 5 0.001] [f-dt/data: round/to time-delta: max 0.001 face/data / 5 0.001 show f-dt] return | |
label "Refresh speed" f-rs: cval data v-rate sld on-create [face/data: v-rate / 60.0] [f-rs/data: v-rate: to-integer 60 * face/data img/rate: all [v-rate > 0 v-rate] show [f-rs img]] return | |
label "Trace count" f-tc: cval data trace-count sld on-create [face/data: trace-count / 50.0] [f-tc/data: trace-count: to-integer 50 * face/data show f-tc] return | |
label "Trace offset" f-to: cval data trace-offset sld data trace-offset [f-to/data: trace-offset: face/data show f-to] return | |
label "Trace colors" check "With alpha?" data with-alpha? [with-alpha?: face/data recolor f-dd/selected] black font-color white f-dd: drop-down data ["Only red" "Rainbow"] black font-color white select 1 on-change [recolor face/selected] return | |
label "Target length" f-tl: cval data target-length sld on-create [face/data: 1.0 * target-length / heart-points-count] [f-tl/data: target-length: to-integer heart-points-count * face/data target-count: heart-points-count - target-length show f-tl] return | |
label "Target scale" f-ts: cval data target-scale sld on-create [face/data: target-scale - 0.5 / 2] [f-ts/data: round/to target-scale: face/data * 2 + 0.5 0.1 target-scale show f-ts] return | |
label "Clearing speed" f-cs: cval data clear-speed sld on-create [face/data: clear-speed / 255.0] [f-cs/data: clear-speed: to-integer face/data * 255 set-clearing show f-cs] return | |
btn "Run?" [img/rate: either img/rate [none][v-rate] show img] | |
btn "Max fps?" [show-fps?: not show-fps?] | |
btn "Snapshot" [if file: request-file/save/title/file "Save the image to the disk" %heart.png [save file to-image img]] | |
btn "halt" [q: :halt unview] | |
] on-create [face/extra: face/size/y + 18 face/size/y: 18] | |
] 'resize | |
; resize the window to hide the control panel at launch | |
cp/parent/size/y: cp/offset/y + 18 | |
show cp/parent | |
; This handle the resize of window content when it is resized | |
insert-event-func [ | |
if event/type = 'resize [ | |
cp/offset/y: cp/parent/size/y - cp/size/y | |
img/size: img/parent/size - (0x1 * cp/size) | |
show cp/parent | |
'done | |
] | |
] | |
do-events | |
q |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment