Data commit

This commit is contained in:
Ingy döt Net 2023-07-01 11:58:00 -04:00
parent 7387c8f97b
commit cb5bb5e222
199093 changed files with 3378972 additions and 0 deletions

View file

@ -0,0 +1,2 @@
---
from: http://rosettacode.org/wiki/Particle_fountain

View file

@ -0,0 +1,14 @@
Implement a particle fountain.
Emulate a fountain of water droplets in a gravitational field being sprayed up and then falling back down.
The particle fountain should be generally ordered but individually chaotic; the particles should be going mostly in the same direction, but should have slightly different vectors.
Your fountain should have at least several hundred particles in motion at any one time, and ideally several thousand.
It is optional to have the individual particle interact with each other.
If at all possible, link to a short video clip of your fountain in action.
[https://github.com/thundergnat/rc/blob/master/img/fountain-raku.mp4?raw=true Off-site link to a demo video]

View file

@ -0,0 +1,237 @@
#include <SDL2/SDL.h>
#include <algorithm>
#include <chrono>
#include <cmath>
#include <iostream>
#include <memory>
#include <random>
#include <tuple>
#include <vector>
auto now() {
using namespace std::chrono;
auto time = system_clock::now();
return duration_cast<milliseconds>(time.time_since_epoch()).count();
}
auto hsv_to_rgb(int h, double s, double v) {
double hp = h / 60.0;
double c = s * v;
double x = c * (1 - std::abs(std::fmod(hp, 2) - 1));
double m = v - c;
double r = 0, g = 0, b = 0;
if (hp <= 1) {
r = c;
g = x;
} else if (hp <= 2) {
r = x;
g = c;
} else if (hp <= 3) {
g = c;
b = x;
} else if (hp <= 4) {
g = x;
b = c;
} else if (hp <= 5) {
r = x;
b = c;
} else {
r = c;
b = x;
}
r += m;
g += m;
b += m;
return std::make_tuple(Uint8(r * 255), Uint8(g * 255), Uint8(b * 255));
}
class ParticleFountain {
public:
ParticleFountain(int particles, int width, int height);
void run();
private:
struct WindowDeleter {
void operator()(SDL_Window* window) const { SDL_DestroyWindow(window); }
};
struct RendererDeleter {
void operator()(SDL_Renderer* renderer) const {
SDL_DestroyRenderer(renderer);
}
};
struct PointInfo {
double x = 0;
double y = 0;
double vx = 0;
double vy = 0;
double lifetime = 0;
};
void update(double df);
bool handle_event();
void render();
double rand() { return dist_(rng_); }
double reciprocate() const {
return reciprocate_ ? range_ * std::sin(now() / 1000.0) : 0.0;
}
std::unique_ptr<SDL_Window, WindowDeleter> window_;
std::unique_ptr<SDL_Renderer, RendererDeleter> renderer_;
int width_;
int height_;
std::vector<PointInfo> point_info_;
std::vector<SDL_Point> points_;
int num_points_ = 0;
double saturation_ = 0.4;
double spread_ = 1.5;
double range_ = 1.5;
bool reciprocate_ = false;
std::mt19937 rng_;
std::uniform_real_distribution<> dist_;
};
ParticleFountain::ParticleFountain(int n, int width, int height)
: width_(width), height_(height), point_info_(n), points_(n, {0, 0}),
rng_(std::random_device{}()), dist_(0.0, 1.0) {
window_.reset(SDL_CreateWindow(
"C++ Particle System!", SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED,
width, height, SDL_WINDOW_RESIZABLE));
if (window_ == nullptr)
throw std::runtime_error(SDL_GetError());
renderer_.reset(
SDL_CreateRenderer(window_.get(), -1, SDL_RENDERER_ACCELERATED));
if (renderer_ == nullptr)
throw std::runtime_error(SDL_GetError());
}
void ParticleFountain::run() {
for (double df = 0.0001;;) {
auto start = now();
if (!handle_event())
break;
update(df);
render();
df = (now() - start) / 1000.0;
}
}
void ParticleFountain::update(double df) {
int pointidx = 0;
for (PointInfo& point : point_info_) {
bool willdraw = false;
if (point.lifetime <= 0.0) {
if (rand() < df) {
point.lifetime = 2.5;
point.x = width_ / 20.0;
point.y = height_ / 10.0;
point.vx =
(spread_ * rand() - spread_ / 2 + reciprocate()) * 10.0;
point.vy = (rand() - 2.9) * height_ / 20.5;
willdraw = true;
}
} else {
if (point.y > height_ / 10.0 && point.vy > 0)
point.vy *= -0.3;
point.vy += (height_ / 10.0) * df;
point.x += point.vx * df;
point.y += point.vy * df;
point.lifetime -= df;
willdraw = true;
}
if (willdraw) {
points_[pointidx].x = std::floor(point.x * 10.0);
points_[pointidx].y = std::floor(point.y * 10.0);
++pointidx;
}
}
num_points_ = pointidx;
}
bool ParticleFountain::handle_event() {
bool result = true;
SDL_Event event;
while (result && SDL_PollEvent(&event)) {
switch (event.type) {
case SDL_QUIT:
result = false;
break;
case SDL_WINDOWEVENT:
if (event.window.event == SDL_WINDOWEVENT_RESIZED) {
width_ = event.window.data1;
height_ = event.window.data2;
}
break;
case SDL_KEYDOWN:
switch (event.key.keysym.scancode) {
case SDL_SCANCODE_UP:
saturation_ = std::min(saturation_ + 0.1, 1.0);
break;
case SDL_SCANCODE_DOWN:
saturation_ = std::max(saturation_ - 0.1, 0.0);
break;
case SDL_SCANCODE_PAGEUP:
spread_ = std::min(spread_ + 0.1, 5.0);
break;
case SDL_SCANCODE_PAGEDOWN:
spread_ = std::max(spread_ - 0.1, 0.2);
break;
case SDL_SCANCODE_RIGHT:
range_ = std::min(range_ + 0.1, 2.0);
break;
case SDL_SCANCODE_LEFT:
range_ = std::max(range_ - 0.1, 0.1);
break;
case SDL_SCANCODE_SPACE:
reciprocate_ = !reciprocate_;
break;
case SDL_SCANCODE_Q:
result = false;
break;
default:
break;
}
break;
}
}
return result;
}
void ParticleFountain::render() {
SDL_Renderer* renderer = renderer_.get();
SDL_SetRenderDrawColor(renderer, 0x0, 0x0, 0x0, 0xff);
SDL_RenderClear(renderer);
auto [red, green, blue] = hsv_to_rgb((now() % 5) * 72, saturation_, 1);
SDL_SetRenderDrawColor(renderer, red, green, blue, 0x7f);
SDL_RenderDrawPoints(renderer, points_.data(), num_points_);
SDL_RenderPresent(renderer);
}
int main() {
std::cout << "Use UP and DOWN arrow keys to modify the saturation of the "
"particle colors.\n"
"Use PAGE UP and PAGE DOWN keys to modify the \"spread\" of "
"the particles.\n"
"Toggle reciprocation off / on with the SPACE bar.\n"
"Use LEFT and RIGHT arrow keys to modify angle range for "
"reciprocation.\n"
"Press the \"q\" key to quit.\n";
if (SDL_Init(SDL_INIT_VIDEO) != 0) {
std::cerr << "ERROR: " << SDL_GetError() << '\n';
return EXIT_FAILURE;
}
try {
ParticleFountain pf(3000, 800, 800);
pf.run();
} catch (const std::exception& ex) {
std::cerr << "ERROR: " << ex.what() << '\n';
SDL_Quit();
return EXIT_FAILURE;
}
SDL_Quit();
return EXIT_SUCCESS;
}

View file

@ -0,0 +1,126 @@
using Dates, Colors, SimpleDirectMediaLayer.LibSDL2
mutable struct ParticleFountain
particlenum::Int
positions::Vector{Float64}
velocities::Vector{Float64}
lifetimes::Vector{Float64}
points::Vector{SDL_Point}
numpoints::Int
saturation::Float64
spread::Float64
range::Float64
reciprocate::Bool
ParticleFountain(N) = new(N, zeros(2N), zeros(2N), zeros(N), fill(SDL_Point(0, 0), N),
0, 0.4, 1.5, 1.5, false)
end
function update(pf, w, h, df)
xidx, yidx, pointidx = 1, 2, 0
recip() = pf.reciprocate ? pf.range * sin(Dates.value(now()) / 1000) : 0.0
for idx in 1:pf.particlenum
willdraw = false
if pf.lifetimes[idx] <= 0.0
if rand() < df
pf.lifetimes[idx] = 2.5; # time to live
pf.positions[xidx] = (w / 20) # starting position x
pf.positions[yidx] = (h / 10) # and y
pf.velocities[xidx] = 10 * (pf.spread * rand() - pf.spread / 2 + recip()) # starting velocity x
pf.velocities[yidx] = (rand() - 2.9) * h / 20.5; # and y (randomized slightly so points reach different heights)
willdraw = true
end
else
if pf.positions[yidx] > h / 10 && pf.velocities[yidx] > 0
pf.velocities[yidx] *= -0.3 # "bounce"
end
pf.velocities[yidx] += df * h / 10 # adjust velocity
pf.positions[xidx] += pf.velocities[xidx] * df # adjust position x
pf.positions[yidx] += pf.velocities[yidx] * df # and y
pf.lifetimes[idx] -= df
willdraw = true
end
if willdraw # gather all of the points that are going to be rendered
pointidx += 1
pf.points[pointidx] = SDL_Point(Cint(floor(pf.positions[xidx] * 10)),
Cint(floor(pf.positions[yidx] * 10)))
end
xidx += 2
yidx = xidx + 1
pf.numpoints = pointidx
end
return pf
end
function fountain(particlenum = 3000, w = 800, h = 800)
SDL_Init(SDL_INIT_VIDEO)
window = SDL_CreateWindow("Julia Particle System!", SDL_WINDOWPOS_CENTERED_MASK,
SDL_WINDOWPOS_CENTERED_MASK, w, h, SDL_WINDOW_RESIZABLE)
renderer = SDL_CreateRenderer(window, -1, SDL_RENDERER_ACCELERATED)
SDL_ClearError()
df = 0.0001
pf = ParticleFountain(3000)
overallstart, close, frames = now(), false, 0
while !close
dfstart = now()
event_ref = Ref{SDL_Event}()
while Bool(SDL_PollEvent(event_ref))
event_type = event_ref[].type
evt = event_ref[]
if event_type == SDL_QUIT
close = true
break
end
if event_type == SDL_WINDOWEVENT
if evt.window.event == 5
w = evt.window.data1
h = evt.window.data2
end
end
if event_type == SDL_KEYDOWN
comm = evt.key.keysym.scancode
if comm == SDL_SCANCODE_UP
saturation = min(pf.saturation + 0.1, 1.0)
elseif comm == SDL_SCANCODE_DOWN
saturation = max(pf.saturation - 0.1, 0.0)
elseif comm == SDL_SCANCODE_PAGEUP
spread = min(pf.spread + 1, 50.0)
elseif comm == SDL_SCANCODE_PAGEDOWN
spread = max(pf.spread - 0.1, 0.2)
elseif comm == SDL_SCANCODE_LEFT
range = min(pf.range + 0.1, 12.0)
elseif comm == SDL_SCANCODE_RIGHT
range = max(pf.range - 0.1, 0.1)
elseif comm == SDL_SCANCODE_SPACE
pf.reciprocate = !pf.reciprocate
elseif comm == SDL_SCANCODE_Q
close = true
break
end
end
end
pf = update(pf, w, h, df)
SDL_SetRenderDrawColor(renderer, 0x0, 0x0, 0x0, 0xff)
SDL_RenderClear(renderer)
rgb = parse(UInt32, hex(HSL((Dates.value(now()) % 5) * 72, pf.saturation, 0.5)), base=16)
red, green, blue = rgb & 0xff, (rgb >> 8) & 0xff, (rgb >>16) & 0xff
SDL_SetRenderDrawColor(renderer, red, green, blue, 0x7f)
SDL_RenderDrawPoints(renderer, pf.points, pf.numpoints)
SDL_RenderPresent(renderer)
frames += 1
df = Float64(Dates.value(now()) - Dates.value(dfstart)) / 1000
elapsed = Float64(Dates.value(now()) - Dates.value(overallstart)) / 1000
elapsed > 0.5 && print("\r", ' '^20, "\rFPS: ", round(frames / elapsed, digits=1))
end
SDL_Quit()
end
println("""
Use UP and DOWN arrow keys to modify the saturation of the particle colors.
Use PAGE UP and PAGE DOWN keys to modify the "spread" of the particles.
Toggle reciprocation off / on with the SPACE bar.
Use LEFT and RIGHT arrow keys to modify angle range for reciprocation.
Press the "q" key to quit.
""")
fountain()

View file

@ -0,0 +1,140 @@
import std/[lenientops, math, monotimes, random, times]
import sdl2
type ParticleFountain[N: static Positive] = object
positions: array[1..2 * N, float]
velocities: array[1..2 * N, float]
lifetimes: array[1..N, float]
points: array[1..N, Point]
numPoints: int
saturation: float
spread: float
range: float
reciprocate: bool
proc initParticleFountain[N: static Positive](): ParticleFountain[N] =
ParticleFountain[N](saturation: 0.4, spread: 1.5, range: 1.5)
proc update(pf: var ParticleFountain; w, h: cint; df: float) =
var
xidx = 1
yidx = 2
pointidx = 0
template recip(pf: ParticleFountain): float =
if pf.reciprocate: pf.range * sin(epochTime() / 1000) else: 0.0
for idx in 1..pf.N:
var willDraw = false
if pf.lifetimes[idx] <= 0:
if rand(1.0) < df:
pf.lifetimes[idx] = 2.5 # Time to live.
# Starting position.
pf.positions[xidx] = w / 20
pf.positions[yidx] = h / 10
# Starting velocity.
pf.velocities[xidx] = 10 * (pf.spread * rand(1.0) - pf.spread / 2 + pf.recip())
pf.velocities[yidx] = (rand(1.0) - 2.9) * h / 20.5
willDraw = true
else:
if pf.positions[yidx] > h / 10 and pf.velocities[yidx] > 0:
pf.velocities[yidx] *= -0.3 # "Bounce".
pf.velocities[yidx] += df * h / 10 # Adjust velocity.
pf.positions[xidx] += pf.velocities[xidx] * df # Adjust position x.
pf.positions[yidx] += pf.velocities[yidx] * df # Adjust position y.
pf.lifetimes[idx] -= df
willDraw = true
if willDraw:
# Gather all of the points that are going to be rendered.
inc pointIdx
pf.points[pointidx] = (cint(pf.positions[xidx] * 10), cint(pf.positions[yidx] * 10))
inc xidx, 2
yidx = xidx + 1
pf.numPoints = pointidx
func hsvToRgb(h, s, v: float): (byte, byte, byte) =
let hp = h / 60.0
let c = s * v
let x = c * (1 - abs(hp mod 2 - 1))
let m = v - c
var (r, g, b) = if hp <= 1: (c, x, 0.0)
elif hp <= 2: (x, c, 0.0)
elif hp <= 3: (0.0, c, x)
elif hp <= 4: (0.0, x, c)
elif hp <= 5: (x, 0.0, c)
else: (c, 0.0, x)
r += m
g += m
b += m
result = (byte(r * 255), byte(g * 255), byte(b * 255))
proc fountain(particleNum = 3000; w = 800; h = 800) =
var w = w.cint
var h = h.cint
discard sdl2.init(INIT_VIDEO or INIT_EVENTS)
let window = createWindow("Nim Particle System!", SDL_WINDOWPOS_CENTERED_MASK,
SDL_WINDOWPOS_CENTERED_MASK, w, h, SDL_WINDOW_RESIZABLE)
let renderer = createRenderer(window, -1, 0)
clearError()
var df = 0.0001
var pf = initParticleFountain[3000]()
var close = false
var frames = 0
block Simulation:
while not close:
let dfStart = getMonoTime()
var event: Event
while bool(pollEvent(event)):
case event.kind
of QuitEvent:
break Simulation
of WindowEvent:
if event.window.event == WindowEvent_Resized:
w = event.window.data1
h = event.window.data2
of KeyDown:
let comm = event.key.keysym.sym
case comm
of K_UP:
pf.saturation = min(pf.saturation + 0.1, 1.0)
of K_DOWN:
pf.saturation = max(pf.saturation - 0.1, 0.0)
of K_PAGEUP:
pf.spread = min(pf.spread + 1.0, 50.0)
of K_PAGEDOWN:
pf.spread = max(pf.spread - 0.1, 0.2)
of K_LEFT:
pf.range = min(pf.range + 0.1, 12.0)
of K_RIGHT:
pf.range = max(pf.range - 0.1, 0.1)
of K_SPACE:
pf.reciprocate = not pf.reciprocate
of K_Q:
break Simulation
else:
discard
else:
discard
pf.update(w, h, df)
renderer.setDrawColor(0x0, 0x0, 0x0, 0xff)
renderer.clear()
let (red, green, blue) = hsvToRgb(epochTime() mod 5 * 72, pf.saturation, 1.0)
renderer.setDrawColor(red, green, blue, 0x7f)
renderer.drawPoints(pf.points[1].addr, pf.numPoints.cint)
renderer.present()
inc frames
df = (getMonoTime() - dfStart).inMilliseconds.float / 1000
sdl2.quit()
randomize()
echo """
Use UP and DOWN arrow keys to modify the saturation of the particle colors.
Use PAGE UP and PAGE DOWN keys to modify the "spread" of the particles.
Toggle reciprocation off / on with the SPACE bar.
Use LEFT and RIGHT arrow keys to modify angle range for reciprocation.
Press the "q" key to quit.
"""
fountain()

View file

@ -0,0 +1,48 @@
#!/usr/bin/perl
use strict; # https://rosettacode.org/wiki/Particle_fountain
use warnings;
use Tk;
my $size = 900;
my @particles;
my $maxparticles = 500;
my @colors = qw( red green blue yellow cyan magenta orange white );
my $mw = MainWindow->new;
my $c = $mw->Canvas( -width => $size, -height => $size, -bg => 'black',
)->pack;
$mw->Button(-text => 'Exit', -command => sub {$mw->destroy},
)->pack(-fill => 'x');
step();
MainLoop;
-M $0 < 0 and exec $0;
sub step
{
$c->delete('all');
$c->createLine($size / 2 - 10, $size, $size / 2, $size - 10,
$size / 2 + 10, $size, -fill => 'white' );
for ( @particles )
{
my ($ox, $oy, $vx, $vy, $color) = @$_;
my $x = $ox + $vx;
my $y = $oy + $vy;
$c->createRectangle($ox, $oy, $x, $y, -fill => $color, -outline => $color);
if( $y < $size )
{
$_->[0] = $x;
$_->[1] = $y;
$_->[3] += 0.006; # gravity :)
}
else { $_ = undef }
}
@particles = grep defined, @particles;
if( @particles < $maxparticles and --$| )
{
push @particles, [ $size >> 1, $size - 10,
(1 - rand 2) / 2.5 , -3 - rand 0.05, $colors[rand @colors] ];
}
$mw->after(1 => \&step);
}

View file

@ -0,0 +1,126 @@
(phixonline)-->
<span style="color: #000080;font-style:italic;">--
-- demo\rosetta\Particle_fountain.exw
-- ==================================
--</span>
<span style="color: #008080;">with</span> <span style="color: #008080;">javascript_semantics</span>
<span style="color: #008080;">include</span> <span style="color: #000000;">pGUI</span><span style="color: #0000FF;">.</span><span style="color: #000000;">e</span>
<span style="color: #004080;">Ihandle</span> <span style="color: #000000;">dlg</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">canvas</span>
<span style="color: #004080;">cdCanvas</span> <span style="color: #000000;">cddbuffer</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">cdcanvas</span>
<span style="color: #008080;">constant</span> <span style="color: #000000;">title</span> <span style="color: #0000FF;">=</span> <span style="color: #008000;">"Particle fountain"</span>
<span style="color: #008080;">constant</span> <span style="color: #000000;">help_text</span> <span style="color: #0000FF;">=</span> <span style="color: #008000;">"""
Uparrow increases the saturation of the particle colors,
downarrow decreases saturation until they all become white.
PageUp sprays the particles out at a wider angle/spread,
PageDown makes the jet narrower.
Space toggles reciprocation (wobble) on and off (straight up).
Left arrow decreases the angle range for reciprocation,
right arrow increases the angle range for reciprocation.
Press the "q" key to quit.
"""</span>
<span style="color: #008080;">constant</span> <span style="color: #000000;">particlenum</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">3000</span>
<span style="color: #000080;font-style:italic;">-- each particle is {x,y,color,life,dx,dy}</span>
<span style="color: #004080;">sequence</span> <span style="color: #000000;">particles</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">repeat</span><span style="color: #0000FF;">({</span><span style="color: #000000;">0</span><span style="color: #0000FF;">,</span><span style="color: #000000;">0</span><span style="color: #0000FF;">,</span><span style="color: #000000;">0</span><span style="color: #0000FF;">,</span><span style="color: #000000;">0</span><span style="color: #0000FF;">,</span><span style="color: #000000;">0</span><span style="color: #0000FF;">,</span><span style="color: #000000;">0</span><span style="color: #0000FF;">},</span><span style="color: #000000;">particlenum</span><span style="color: #0000FF;">)</span>
<span style="color: #004080;">atom</span> <span style="color: #000000;">t1</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">time</span><span style="color: #0000FF;">()+</span><span style="color: #000000;">1</span>
<span style="color: #004080;">integer</span> <span style="color: #000000;">fps</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">0</span>
<span style="color: #004080;">bool</span> <span style="color: #000000;">reciprocate</span> <span style="color: #0000FF;">=</span> <span style="color: #004600;">true</span>
<span style="color: #004080;">atom</span> <span style="color: #000000;">range</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">1.5</span><span style="color: #0000FF;">,</span>
<span style="color: #000000;">spread</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">1.5</span><span style="color: #0000FF;">,</span>
<span style="color: #000000;">saturation</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">0.4</span><span style="color: #0000FF;">,</span>
<span style="color: #000000;">start</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">time</span><span style="color: #0000FF;">(),</span>
<span style="color: #000000;">df</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">0.0001</span>
<span style="color: #008080;">function</span> <span style="color: #000000;">redraw_cb</span><span style="color: #0000FF;">(</span><span style="color: #004080;">Ihandle</span> <span style="color: #000080;font-style:italic;">/*ih*/</span><span style="color: #0000FF;">,</span> <span style="color: #004080;">integer</span> <span style="color: #000080;font-style:italic;">/*posx*/</span><span style="color: #0000FF;">,</span> <span style="color: #000080;font-style:italic;">/*posy*/</span><span style="color: #0000FF;">)</span>
<span style="color: #004080;">integer</span> <span style="color: #0000FF;">{</span><span style="color: #000000;">w</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">h</span><span style="color: #0000FF;">}</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">IupGetIntInt</span><span style="color: #0000FF;">(</span><span style="color: #000000;">canvas</span><span style="color: #0000FF;">,</span> <span style="color: #008000;">"DRAWSIZE"</span><span style="color: #0000FF;">)</span>
<span style="color: #7060A8;">cdCanvasActivate</span><span style="color: #0000FF;">(</span><span style="color: #000000;">cddbuffer</span><span style="color: #0000FF;">)</span>
<span style="color: #7060A8;">cdCanvasClear</span><span style="color: #0000FF;">(</span><span style="color: #000000;">cddbuffer</span><span style="color: #0000FF;">)</span>
<span style="color: #008080;">for</span> <span style="color: #000000;">i</span><span style="color: #0000FF;">=</span><span style="color: #000000;">1</span> <span style="color: #008080;">to</span> <span style="color: #7060A8;">length</span><span style="color: #0000FF;">(</span><span style="color: #000000;">particles</span><span style="color: #0000FF;">)</span> <span style="color: #008080;">do</span>
<span style="color: #004080;">atom</span> <span style="color: #0000FF;">{</span><span style="color: #000000;">x</span><span style="color: #0000FF;">,</span><span style="color: #000000;">y</span><span style="color: #0000FF;">,</span><span style="color: #000000;">color</span><span style="color: #0000FF;">,</span><span style="color: #000000;">life</span><span style="color: #0000FF;">}</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">particles</span><span style="color: #0000FF;">[</span><span style="color: #000000;">i</span><span style="color: #0000FF;">]</span>
<span style="color: #008080;">if</span> <span style="color: #000000;">life</span><span style="color: #0000FF;">></span><span style="color: #000000;">0</span> <span style="color: #008080;">then</span>
<span style="color: #7060A8;">cdCanvasPixel</span><span style="color: #0000FF;">(</span><span style="color: #000000;">cddbuffer</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">x</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">h</span><span style="color: #0000FF;">/</span><span style="color: #000000;">10</span><span style="color: #0000FF;">-</span><span style="color: #000000;">y</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">color</span><span style="color: #0000FF;">)</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">for</span>
<span style="color: #7060A8;">cdCanvasFlush</span><span style="color: #0000FF;">(</span><span style="color: #000000;">cddbuffer</span><span style="color: #0000FF;">)</span>
<span style="color: #008080;">return</span> <span style="color: #004600;">IUP_DEFAULT</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">function</span>
<span style="color: #008080;">function</span> <span style="color: #000000;">map_cb</span><span style="color: #0000FF;">(</span><span style="color: #004080;">Ihandle</span> <span style="color: #000000;">ih</span><span style="color: #0000FF;">)</span>
<span style="color: #000000;">cdcanvas</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">cdCreateCanvas</span><span style="color: #0000FF;">(</span><span style="color: #004600;">CD_IUP</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">ih</span><span style="color: #0000FF;">)</span>
<span style="color: #000000;">cddbuffer</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">cdCreateCanvas</span><span style="color: #0000FF;">(</span><span style="color: #004600;">CD_DBUFFER</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">cdcanvas</span><span style="color: #0000FF;">)</span>
<span style="color: #7060A8;">cdCanvasSetBackground</span><span style="color: #0000FF;">(</span><span style="color: #000000;">cddbuffer</span><span style="color: #0000FF;">,</span> <span style="color: #004600;">CD_BLACK</span><span style="color: #0000FF;">)</span>
<span style="color: #008080;">return</span> <span style="color: #004600;">IUP_DEFAULT</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">function</span>
<span style="color: #008080;">function</span> <span style="color: #000000;">timer_cb</span><span style="color: #0000FF;">(</span><span style="color: #004080;">Ihandle</span> <span style="color: #000080;font-style:italic;">/*ih*/</span><span style="color: #0000FF;">)</span>
<span style="color: #004080;">integer</span> <span style="color: #0000FF;">{</span><span style="color: #000000;">w</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">h</span><span style="color: #0000FF;">}</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">IupGetIntInt</span><span style="color: #0000FF;">(</span><span style="color: #000000;">canvas</span><span style="color: #0000FF;">,</span> <span style="color: #008000;">"DRAWSIZE"</span><span style="color: #0000FF;">)</span>
<span style="color: #000000;">fps</span> <span style="color: #0000FF;">+=</span> <span style="color: #000000;">1</span>
<span style="color: #000000;">df</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">time</span><span style="color: #0000FF;">()-</span><span style="color: #000000;">start</span>
<span style="color: #000000;">start</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">time</span><span style="color: #0000FF;">()</span>
<span style="color: #008080;">for</span> <span style="color: #000000;">i</span><span style="color: #0000FF;">=</span><span style="color: #000000;">1</span> <span style="color: #008080;">to</span> <span style="color: #000000;">particlenum</span> <span style="color: #008080;">do</span>
<span style="color: #004080;">atom</span> <span style="color: #0000FF;">{</span><span style="color: #000000;">x</span><span style="color: #0000FF;">,</span><span style="color: #000000;">y</span><span style="color: #0000FF;">,</span><span style="color: #000000;">color</span><span style="color: #0000FF;">,</span><span style="color: #000000;">life</span><span style="color: #0000FF;">,</span><span style="color: #000000;">dx</span><span style="color: #0000FF;">,</span><span style="color: #000000;">dy</span><span style="color: #0000FF;">}</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">particles</span><span style="color: #0000FF;">[</span><span style="color: #000000;">i</span><span style="color: #0000FF;">]</span>
<span style="color: #008080;">if</span> <span style="color: #000000;">life</span><span style="color: #0000FF;"><=</span><span style="color: #000000;">0</span> <span style="color: #008080;">then</span>
<span style="color: #008080;">if</span> <span style="color: #7060A8;">rnd</span><span style="color: #0000FF;">()<</span><span style="color: #000000;">df</span> <span style="color: #008080;">then</span>
<span style="color: #000000;">life</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">2.5</span> <span style="color: #000080;font-style:italic;">-- time to live</span>
<span style="color: #000000;">x</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">w</span><span style="color: #0000FF;">/</span><span style="color: #000000;">2</span> <span style="color: #000080;font-style:italic;">-- starting position x</span>
<span style="color: #000000;">y</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">h</span><span style="color: #0000FF;">/</span><span style="color: #000000;">10</span> <span style="color: #000080;font-style:italic;">-- and y
-- randomize velocity so points reach different heights:</span>
<span style="color: #004080;">atom</span> <span style="color: #000000;">r</span> <span style="color: #0000FF;">=</span> <span style="color: #008080;">iff</span><span style="color: #0000FF;">(</span><span style="color: #000000;">reciprocate</span><span style="color: #0000FF;">?</span><span style="color: #000000;">range</span><span style="color: #0000FF;">*</span><span style="color: #7060A8;">sin</span><span style="color: #0000FF;">(</span><span style="color: #7060A8;">time</span><span style="color: #0000FF;">()):</span><span style="color: #000000;">0</span><span style="color: #0000FF;">)</span>
<span style="color: #000000;">dx</span> <span style="color: #0000FF;">=</span> <span style="color: #0000FF;">(</span><span style="color: #000000;">spread</span><span style="color: #0000FF;">*</span><span style="color: #7060A8;">rnd</span><span style="color: #0000FF;">()-</span><span style="color: #000000;">spread</span><span style="color: #0000FF;">/</span><span style="color: #000000;">2</span><span style="color: #0000FF;">+</span><span style="color: #000000;">r</span><span style="color: #0000FF;">)*</span><span style="color: #000000;">50</span> <span style="color: #000080;font-style:italic;">-- starting velocity x</span>
<span style="color: #000000;">dy</span> <span style="color: #0000FF;">=</span> <span style="color: #0000FF;">(</span><span style="color: #7060A8;">rnd</span><span style="color: #0000FF;">()-</span><span style="color: #000000;">2.9</span><span style="color: #0000FF;">)</span> <span style="color: #0000FF;">*</span> <span style="color: #000000;">h</span><span style="color: #0000FF;">/</span><span style="color: #000000;">20.5</span> <span style="color: #000080;font-style:italic;">-- and y </span>
<span style="color: #000000;">color</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">hsv_to_rgb</span><span style="color: #0000FF;">(</span><span style="color: #7060A8;">round</span><span style="color: #0000FF;">(</span><span style="color: #7060A8;">remainder</span><span style="color: #0000FF;">(</span><span style="color: #7060A8;">time</span><span style="color: #0000FF;">(),</span><span style="color: #000000;">5</span><span style="color: #0000FF;">)/</span><span style="color: #000000;">5</span><span style="color: #0000FF;">,</span><span style="color: #000000;">100</span><span style="color: #0000FF;">),</span> <span style="color: #000000;">saturation</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">1</span><span style="color: #0000FF;">)</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
<span style="color: #008080;">else</span>
<span style="color: #008080;">if</span> <span style="color: #000000;">y</span><span style="color: #0000FF;">></span><span style="color: #000000;">h</span><span style="color: #0000FF;">/</span><span style="color: #000000;">10</span> <span style="color: #008080;">and</span> <span style="color: #000000;">dy</span><span style="color: #0000FF;">></span><span style="color: #000000;">0</span> <span style="color: #008080;">then</span>
<span style="color: #000000;">dy</span> <span style="color: #0000FF;">*=</span> <span style="color: #0000FF;">-</span><span style="color: #000000;">0.3</span> <span style="color: #000080;font-style:italic;">-- "bounce"</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
<span style="color: #000000;">dy</span> <span style="color: #0000FF;">+=</span> <span style="color: #0000FF;">(</span><span style="color: #000000;">h</span><span style="color: #0000FF;">/</span><span style="color: #000000;">10</span><span style="color: #0000FF;">)*</span><span style="color: #000000;">df</span> <span style="color: #000080;font-style:italic;">-- adjust velocity</span>
<span style="color: #000000;">x</span> <span style="color: #0000FF;">+=</span> <span style="color: #000000;">dx</span><span style="color: #0000FF;">*</span><span style="color: #000000;">df</span> <span style="color: #000080;font-style:italic;">-- adjust position x</span>
<span style="color: #000000;">y</span> <span style="color: #0000FF;">+=</span> <span style="color: #000000;">dy</span><span style="color: #0000FF;">*</span><span style="color: #000000;">df</span><span style="color: #0000FF;">*</span><span style="color: #000000;">8</span> <span style="color: #000080;font-style:italic;">-- and y</span>
<span style="color: #000000;">life</span> <span style="color: #0000FF;">-=</span> <span style="color: #000000;">df</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
<span style="color: #000000;">particles</span><span style="color: #0000FF;">[</span><span style="color: #000000;">i</span><span style="color: #0000FF;">]</span> <span style="color: #0000FF;">=</span> <span style="color: #0000FF;">{</span><span style="color: #000000;">x</span><span style="color: #0000FF;">,</span><span style="color: #000000;">y</span><span style="color: #0000FF;">,</span><span style="color: #000000;">color</span><span style="color: #0000FF;">,</span><span style="color: #000000;">life</span><span style="color: #0000FF;">,</span><span style="color: #000000;">dx</span><span style="color: #0000FF;">,</span><span style="color: #000000;">dy</span><span style="color: #0000FF;">}</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">for</span>
<span style="color: #7060A8;">IupRedraw</span><span style="color: #0000FF;">(</span><span style="color: #000000;">canvas</span><span style="color: #0000FF;">)</span>
<span style="color: #008080;">if</span> <span style="color: #7060A8;">time</span><span style="color: #0000FF;">()></span><span style="color: #000000;">t1</span> <span style="color: #008080;">then</span>
<span style="color: #7060A8;">IupSetStrAttribute</span><span style="color: #0000FF;">(</span><span style="color: #000000;">dlg</span><span style="color: #0000FF;">,</span><span style="color: #008000;">"TITLE"</span><span style="color: #0000FF;">,</span><span style="color: #008000;">"%s (%d, %d fps/s [%dx%d])"</span><span style="color: #0000FF;">,{</span><span style="color: #000000;">title</span><span style="color: #0000FF;">,</span><span style="color: #000000;">particlenum</span><span style="color: #0000FF;">,</span><span style="color: #000000;">fps</span><span style="color: #0000FF;">,</span><span style="color: #000000;">w</span><span style="color: #0000FF;">,</span><span style="color: #000000;">h</span><span style="color: #0000FF;">})</span>
<span style="color: #000000;">t1</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">time</span><span style="color: #0000FF;">()+</span><span style="color: #000000;">1</span>
<span style="color: #000000;">fps</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">0</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
<span style="color: #008080;">return</span> <span style="color: #004600;">IUP_DEFAULT</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">function</span>
<span style="color: #008080;">function</span> <span style="color: #000000;">key_cb</span><span style="color: #0000FF;">(</span><span style="color: #004080;">Ihandle</span> <span style="color: #000080;font-style:italic;">/*dlg*/</span><span style="color: #0000FF;">,</span> <span style="color: #004080;">atom</span> <span style="color: #000000;">c</span><span style="color: #0000FF;">)</span>
<span style="color: #008080;">if</span> <span style="color: #000000;">c</span><span style="color: #0000FF;">=</span><span style="color: #004600;">K_ESC</span> <span style="color: #008080;">or</span> <span style="color: #7060A8;">lower</span><span style="color: #0000FF;">(</span><span style="color: #000000;">c</span><span style="color: #0000FF;">)=</span><span style="color: #008000;">'q'</span> <span style="color: #008080;">then</span> <span style="color: #008080;">return</span> <span style="color: #004600;">IUP_CLOSE</span>
<span style="color: #008080;">elsif</span> <span style="color: #000000;">c</span><span style="color: #0000FF;">=</span><span style="color: #004600;">K_F1</span> <span style="color: #008080;">then</span> <span style="color: #7060A8;">IupMessage</span><span style="color: #0000FF;">(</span><span style="color: #000000;">title</span><span style="color: #0000FF;">,</span><span style="color: #000000;">help_text</span><span style="color: #0000FF;">)</span>
<span style="color: #008080;">elsif</span> <span style="color: #000000;">c</span><span style="color: #0000FF;">=</span><span style="color: #004600;">K_UP</span> <span style="color: #008080;">then</span> <span style="color: #000000;">saturation</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">min</span><span style="color: #0000FF;">(</span><span style="color: #000000;">saturation</span><span style="color: #0000FF;">+</span><span style="color: #000000;">0.1</span><span style="color: #0000FF;">,</span><span style="color: #000000;">1</span><span style="color: #0000FF;">)</span>
<span style="color: #008080;">elsif</span> <span style="color: #000000;">c</span><span style="color: #0000FF;">=</span><span style="color: #004600;">K_DOWN</span> <span style="color: #008080;">then</span> <span style="color: #000000;">saturation</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">max</span><span style="color: #0000FF;">(</span><span style="color: #000000;">saturation</span><span style="color: #0000FF;">-</span><span style="color: #000000;">0.1</span><span style="color: #0000FF;">,</span><span style="color: #000000;">0</span><span style="color: #0000FF;">)</span>
<span style="color: #008080;">elsif</span> <span style="color: #000000;">c</span><span style="color: #0000FF;">=</span><span style="color: #004600;">K_PGUP</span> <span style="color: #008080;">then</span> <span style="color: #000000;">spread</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">min</span><span style="color: #0000FF;">(</span><span style="color: #000000;">spread</span><span style="color: #0000FF;">+</span><span style="color: #000000;">0.1</span><span style="color: #0000FF;">,</span><span style="color: #000000;">5</span><span style="color: #0000FF;">)</span>
<span style="color: #008080;">elsif</span> <span style="color: #000000;">c</span><span style="color: #0000FF;">=</span><span style="color: #004600;">K_PGDN</span> <span style="color: #008080;">then</span> <span style="color: #000000;">spread</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">max</span><span style="color: #0000FF;">(</span><span style="color: #000000;">spread</span><span style="color: #0000FF;">-</span><span style="color: #000000;">0.1</span><span style="color: #0000FF;">,</span><span style="color: #000000;">0.2</span><span style="color: #0000FF;">)</span>
<span style="color: #008080;">elsif</span> <span style="color: #000000;">c</span><span style="color: #0000FF;">=</span><span style="color: #004600;">K_RIGHT</span> <span style="color: #008080;">then</span> <span style="color: #000000;">range</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">min</span><span style="color: #0000FF;">(</span><span style="color: #000000;">range</span><span style="color: #0000FF;">+</span><span style="color: #000000;">0.1</span><span style="color: #0000FF;">,</span><span style="color: #000000;">2</span><span style="color: #0000FF;">)</span>
<span style="color: #008080;">elsif</span> <span style="color: #000000;">c</span><span style="color: #0000FF;">=</span><span style="color: #004600;">K_LEFT</span> <span style="color: #008080;">then</span> <span style="color: #000000;">range</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">max</span><span style="color: #0000FF;">(</span><span style="color: #000000;">range</span><span style="color: #0000FF;">-</span><span style="color: #000000;">0.1</span><span style="color: #0000FF;">,</span><span style="color: #000000;">0.1</span><span style="color: #0000FF;">)</span>
<span style="color: #008080;">elsif</span> <span style="color: #000000;">c</span><span style="color: #0000FF;">=</span><span style="color: #004600;">K_SP</span> <span style="color: #008080;">then</span> <span style="color: #000000;">reciprocate</span> <span style="color: #0000FF;">=</span> <span style="color: #008080;">not</span> <span style="color: #000000;">reciprocate</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
<span style="color: #008080;">return</span> <span style="color: #004600;">IUP_CONTINUE</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">function</span>
<span style="color: #008080;">procedure</span> <span style="color: #000000;">main</span><span style="color: #0000FF;">()</span>
<span style="color: #7060A8;">IupOpen</span><span style="color: #0000FF;">()</span>
<span style="color: #000000;">canvas</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">IupGLCanvas</span><span style="color: #0000FF;">(</span><span style="color: #008000;">"RASTERSIZE=400x300"</span><span style="color: #0000FF;">)</span>
<span style="color: #7060A8;">IupSetCallbacks</span><span style="color: #0000FF;">({</span><span style="color: #000000;">canvas</span><span style="color: #0000FF;">},</span> <span style="color: #0000FF;">{</span><span style="color: #008000;">"ACTION"</span><span style="color: #0000FF;">,</span> <span style="color: #7060A8;">Icallback</span><span style="color: #0000FF;">(</span><span style="color: #008000;">"redraw_cb"</span><span style="color: #0000FF;">),</span>
<span style="color: #008000;">"MAP_CB"</span><span style="color: #0000FF;">,</span> <span style="color: #7060A8;">Icallback</span><span style="color: #0000FF;">(</span><span style="color: #008000;">"map_cb"</span><span style="color: #0000FF;">)})</span>
<span style="color: #000000;">dlg</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">IupDialog</span><span style="color: #0000FF;">(</span><span style="color: #000000;">canvas</span><span style="color: #0000FF;">,</span><span style="color: #008000;">`TITLE="%s"`</span><span style="color: #0000FF;">,{</span><span style="color: #000000;">title</span><span style="color: #0000FF;">})</span>
<span style="color: #7060A8;">IupSetCallback</span><span style="color: #0000FF;">(</span><span style="color: #000000;">dlg</span><span style="color: #0000FF;">,</span> <span style="color: #008000;">"KEY_CB"</span><span style="color: #0000FF;">,</span> <span style="color: #7060A8;">Icallback</span><span style="color: #0000FF;">(</span><span style="color: #008000;">"key_cb"</span><span style="color: #0000FF;">))</span>
<span style="color: #004080;">Ihandle</span> <span style="color: #000000;">timer</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">IupTimer</span><span style="color: #0000FF;">(</span><span style="color: #7060A8;">Icallback</span><span style="color: #0000FF;">(</span><span style="color: #008000;">"timer_cb"</span><span style="color: #0000FF;">),</span> <span style="color: #000000;">1000</span><span style="color: #0000FF;">/</span><span style="color: #000000;">25</span><span style="color: #0000FF;">)</span>
<span style="color: #7060A8;">IupShowXY</span><span style="color: #0000FF;">(</span><span style="color: #000000;">dlg</span><span style="color: #0000FF;">,</span><span style="color: #004600;">IUP_CENTER</span><span style="color: #0000FF;">,</span><span style="color: #004600;">IUP_CENTER</span><span style="color: #0000FF;">)</span>
<span style="color: #7060A8;">IupSetAttribute</span><span style="color: #0000FF;">(</span><span style="color: #000000;">canvas</span><span style="color: #0000FF;">,</span> <span style="color: #008000;">"RASTERSIZE"</span><span style="color: #0000FF;">,</span> <span style="color: #004600;">NULL</span><span style="color: #0000FF;">)</span>
<span style="color: #008080;">if</span> <span style="color: #7060A8;">platform</span><span style="color: #0000FF;">()!=</span><span style="color: #004600;">JS</span> <span style="color: #008080;">then</span>
<span style="color: #7060A8;">IupMainLoop</span><span style="color: #0000FF;">()</span>
<span style="color: #7060A8;">IupClose</span><span style="color: #0000FF;">()</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">procedure</span>
<span style="color: #000000;">main</span><span style="color: #0000FF;">()</span>
<!--

View file

@ -0,0 +1,178 @@
use NativeCall;
use SDL2::Raw;
my int ($w, $h) = 800, 800;
my SDL_Window $window;
my SDL_Renderer $renderer;
my int $particlenum = 3000;
SDL_Init(VIDEO);
$window = SDL_CreateWindow(
"Raku Particle System!",
SDL_WINDOWPOS_CENTERED_MASK, SDL_WINDOWPOS_CENTERED_MASK,
$w, $h,
RESIZABLE
);
$renderer = SDL_CreateRenderer( $window, -1, ACCELERATED );
SDL_ClearError();
my num @positions = 0e0 xx ($particlenum * 2);
my num @velocities = 0e0 xx ($particlenum * 2);
my num @lifetimes = 0e0 xx $particlenum;
my CArray[int32] $points .= new;
my int $numpoints;
my Num $saturation = 4e-1;
my Num $spread = 15e-1;
my &reciprocate = sub { 0 }
my $range = 1.5;
sub update (num \df) {
my int $xidx = 0;
my int $yidx = 1;
my int $pointidx = 0;
loop (my int $idx = 0; $idx < $particlenum; $idx = $idx + 1) {
my int $willdraw = 0;
if (@lifetimes[$idx] <= 0e0) {
if (rand < df) {
@lifetimes[$idx] = 25e-1; # time to live
@positions[$xidx] = ($w / 20e0).Num; # starting position x
@positions[$yidx] = ($h / 10).Num; # and y
@velocities[$xidx] = ($spread * rand - $spread/2 + reciprocate()) * 10; # starting velocity x
@velocities[$yidx] = (rand - 2.9e0) * $h / 20.5; # and y (randomized slightly so points reach different heights)
$willdraw = 1;
}
} else {
if @positions[$yidx] > $h / 10 && @velocities[$yidx] > 0 {
@velocities[$yidx] = @velocities[$yidx] * -0.3e0; # "bounce"
}
@velocities[$yidx] = @velocities[$yidx] + $h/10.Num * df; # adjust velocity
@positions[$xidx] = @positions[$xidx] + @velocities[$xidx] * df; # adjust position x
@positions[$yidx] = @positions[$yidx] + @velocities[$yidx] * df; # and y
@lifetimes[$idx] = @lifetimes[$idx] - df;
$willdraw = 1;
}
if ($willdraw) {
$points[$pointidx++] = (@positions[$xidx] * 10).floor; # gather all of the points that
$points[$pointidx++] = (@positions[$yidx] * 10).floor; # are still going to be rendered
}
$xidx = $xidx + 2;
$yidx = $xidx + 1;
}
$numpoints = ($pointidx - 1) div 2;
}
sub render {
SDL_SetRenderDrawColor($renderer, 0x0, 0x0, 0x0, 0xff);
SDL_RenderClear($renderer);
SDL_SetRenderDrawColor($renderer, |hsv2rgb(((now % 5) / 5).round(.01), $saturation, 1), 0x7f);
SDL_RenderDrawPoints($renderer, $points, $numpoints);
SDL_RenderPresent($renderer);
}
enum KEY_CODES (
K_UP => 82,
K_DOWN => 81,
K_LEFT => 80,
K_RIGHT => 79,
K_SPACE => 44,
K_PGUP => 75,
K_PGDN => 78,
K_Q => 20,
);
say q:to/DOCS/;
Use UP and DOWN arrow keys to modify the saturation of the particle colors.
Use PAGE UP and PAGE DOWN keys to modify the "spread" of the particles.
Toggle reciprocation off / on with the SPACE bar.
Use LEFT and RIGHT arrow keys to modify angle range for reciprocation.
Press the "q" key to quit.
DOCS
my $event = SDL_Event.new;
my num $df = 0.0001e0;
main: loop {
my $start = now;
while SDL_PollEvent($event) {
my $casted_event = SDL_CastEvent($event);
given $casted_event {
when *.type == QUIT {
last main;
}
when *.type == WINDOWEVENT {
if .event == RESIZED {
$w = .data1;
$h = .data2;
}
}
when *.type == KEYDOWN {
if KEY_CODES(.scancode) -> $comm {
given $comm {
when 'K_UP' { $saturation = (($saturation + .1) min 1e0) }
when 'K_DOWN' { $saturation = (($saturation - .1) max 0e0) }
when 'K_PGUP' { $spread = (($spread + .1) min 5e0) }
when 'K_PGDN' { $spread = (($spread - .1) max 2e-1) }
when 'K_RIGHT' { $range = (($range + .1) min 2e0) }
when 'K_LEFT' { $range = (($range - .1) max 1e-1) }
when 'K_SPACE' { &reciprocate = reciprocate() == 0 ?? sub { $range * sin(now) } !! sub { 0 } }
when 'K_Q' { last main }
}
}
}
}
}
update($df);
render();
$df = (now - $start).Num;
print fps();
}
say '';
sub fps {
state $fps-frames = 0;
state $fps-now = now;
state $fps = '';
$fps-frames++;
if now - $fps-now >= 1 {
$fps = [~] "\r", ' ' x 20, "\r",
sprintf "FPS: %5.1f ", ($fps-frames / (now - $fps-now));
$fps-frames = 0;
$fps-now = now;
}
$fps
}
sub hsv2rgb ( $h, $s, $v ){
state %cache;
%cache{"$h|$s|$v"} //= do {
my $c = $v * $s;
my $x = $c * (1 - abs( (($h*6) % 2) - 1 ) );
my $m = $v - $c;
[(do given $h {
when 0..^1/6 { $c, $x, 0 }
when 1/6..^1/3 { $x, $c, 0 }
when 1/3..^1/2 { 0, $c, $x }
when 1/2..^2/3 { 0, $x, $c }
when 2/3..^5/6 { $x, 0, $c }
when 5/6..1 { $c, 0, $x }
} ).map: ((*+$m) * 255).Int]
}
}

View file

@ -0,0 +1,139 @@
import "dome" for Window, Platform, Process
import "graphics" for Canvas, Color
import "math" for Math, Point
import "random" for Random
import "input" for Keyboard
import "./dynamic" for Struct
var Start = Platform.time
var Rand = Random.new()
var fields = [
"particleNum",
"positions",
"velocities",
"lifetimes",
"points",
"numPoints",
"saturation",
"spread",
"range",
"reciprocate"
]
var ParticleFountain = Struct.create("ParticleFountain", fields)
class ParticleDisplay {
construct new(particleNum, width, height) {
Window.resize(width, height)
Canvas.resize(width, height)
Window.title = "Wren Particle System!"
_pn = particleNum
_w = width
_h = height
_df = 1 / 200 // say
_pf = ParticleFountain.new(
_pn, // particleNum
List.filled(_pn * 2, 0), // positions
List.filled(_pn * 2, 0), // velocities
List.filled(_pn, 0), // lifetimes
List.filled(_pn, null), // points
0, // numPoints
0.4, // saturation
1.5, // spread
1.5, // range
false // reciprocate
)
for (i in 0..._pn) _pf.points[i] = Point.new(0, 0)
}
init() {
Canvas.cls()
_frames = 0
}
updatePF() {
var xidx = 0
var yidx = 1
var pointIdx = 0
var recip = Fn.new { _pf.reciprocate ? _pf.range * Math.sin(Platform.time/1000) : 0 }
for (idx in 0..._pf.particleNum) {
var willDraw = false
if (_pf.lifetimes[idx] <= 0) {
if (Rand.float() < _df) {
_pf.lifetimes[idx] = 2.5 // time to live
_pf.positions[xidx] = _w / 20 // starting position x
_pf.positions[yidx] = _h / 10 // and y
// starting velocities x and y
// randomized slightly so points reach different heights
_pf.velocities[xidx] = 10 * (_pf.spread * Rand.float() - _pf.spread / 2 + recip.call())
_pf.velocities[yidx] = (Rand.float() - 2.9) * _h / 20.5
_willDraw = true
}
} else {
if (_pf.positions[yidx] > _h/10 && _pf.velocities[yidx] > 0) {
_pf.velocities[yidx] = _pf.velocities[yidx] * (-0.3) // bounce
}
_pf.velocities[yidx] = _pf.velocities[yidx] + _df * _h / 10 // adjust velocity
_pf.positions[xidx] = _pf.positions[xidx] + _pf.velocities[xidx] * _df // adjust position x
_pf.positions[yidx] = _pf.positions[yidx] + _pf.velocities[yidx] * _df // and y
_pf.lifetimes[idx] = _pf.lifetimes[idx] - _df
willDraw = true
}
if (willDraw) { // gather all the points that are going to be rendered
_pf.points[pointIdx] = Point.new((_pf.positions[xidx] * 10).floor,
(_pf.positions[yidx] * 10).floor)
pointIdx = pointIdx + 1
}
xidx = xidx + 2
yidx = xidx + 1
_pf.numPoints = pointIdx
}
}
update() {
if (Keyboard["Up"].justPressed) {
_pf.saturation = Math.min(_pf.saturation + 0.1, 1)
} else if (Keyboard["Down"].justPressed) {
_pf.saturation = Math.max(_pf.saturation - 0.1, 0)
} else if (Keyboard["PageUp"].justPressed) {
_pf.spread = Math.min(_pf.spread + 1, 50)
} else if (Keyboard["PageDown"].justPressed) {
_pf.spread = Math.max(_pf.spread - 0.1, 0.2)
} else if (Keyboard["Left"].justPressed) {
_pf.range = Math.min(_pf.range + 0.1, 12)
} else if (Keyboard["Right"].justPressed) {
_pf.range = Math.max(_pf.range - 0.1, 0.1)
} else if (Keyboard["Space"].justPressed) {
_pf.reciprocate = !_pf.reciprocate
} else if (Keyboard["Q"].justPressed) {
Process.exit()
}
updatePF()
}
draw(alpha) {
var c = Color.hsv((Platform.time % 5) * 72, _pf.saturation, 0.5, 0x7f)
for (i in 0..._pf.numPoints) {
Canvas.pset(_pf.points[i].x, _pf.points[i].y, c)
}
_frames = _frames + 1
var now = Platform.time
if (now - Start >= 1) {
Start = now
Window.title = "Wren Particle System! (FPS = %(_frames))"
_frames = 0
}
}
}
System.print("""
Use UP and DOWN arrow keys to modify the saturation of the particle colors.
Use PAGE UP and PAGE DOWN keys to modify the "spread" of the particles.
Toggle reciprocation off / on with the SPACE bar.
Use LEFT and RIGHT arrow keys to modify angle range for reciprocation.
Press the "q" key to quit.
""")
var Game = ParticleDisplay.new(3000, 800, 800)