Random number generation was completely wrong. Fixed

macos-click-through
Jon Valdés 5 years ago
parent 7fd6df50ce
commit cef497d0a0

@ -2,14 +2,26 @@ use log::error;
use skulpin::skia_safe::{paint::Style, BlendMode, Canvas, Color, Paint, Point, Rect};
use super::animation_utils::*;
use super::CursorSettings;
use crate::editor::{Colors, Cursor};
use crate::settings::*;
use super::CursorSettings;
pub trait CursorVfx {
fn update(&mut self, settings: &CursorSettings, current_cursor_destination: Point, dt: f32) -> bool;
fn update(
&mut self,
settings: &CursorSettings,
current_cursor_destination: Point,
dt: f32,
) -> bool;
fn restart(&mut self, position: Point);
fn render(&self, settings: &CursorSettings, canvas: &mut Canvas, cursor: &Cursor, colors: &Colors, font_size: (f32, f32));
fn render(
&self,
settings: &CursorSettings,
canvas: &mut Canvas,
cursor: &Cursor,
colors: &Colors,
font_size: (f32, f32),
);
}
#[derive(Clone, PartialEq)]
@ -94,7 +106,12 @@ impl PointHighlight {
}
impl CursorVfx for PointHighlight {
fn update(&mut self, settings: &CursorSettings, _current_cursor_destination: Point, dt: f32) -> bool {
fn update(
&mut self,
_settings: &CursorSettings,
_current_cursor_destination: Point,
dt: f32,
) -> bool {
self.t = (self.t + dt * 5.0).min(1.0); // TODO - speed config
self.t < 1.0
}
@ -104,7 +121,14 @@ impl CursorVfx for PointHighlight {
self.center_position = position;
}
fn render(&self, settings: &CursorSettings, canvas: &mut Canvas, cursor: &Cursor, colors: &Colors, font_size: (f32, f32)) {
fn render(
&self,
settings: &CursorSettings,
canvas: &mut Canvas,
cursor: &Cursor,
colors: &Colors,
font_size: (f32, f32),
) {
if self.t == 1.0 {
return;
}
@ -207,7 +231,8 @@ impl CursorVfx for ParticleTrail {
let travel_distance = travel.length();
// Increase amount of particles when cursor travels further
// TODO -- particle count should not depend on font size
let particle_count = (travel_distance.powf(1.5) * settings.vfx_particle_density * 0.01) as usize;
let particle_count =
(travel_distance.powf(1.5) * settings.vfx_particle_density * 0.01) as usize;
let prev_p = self.previous_cursor_dest;
@ -216,19 +241,25 @@ impl CursorVfx for ParticleTrail {
for i in 0..particle_count {
let t = i as f32 / (particle_count as f32 - 1.0);
let phase = t * 60.0;
let speed = match self.trail_mode {
TrailMode::Railgun => Point::new(phase.sin(), phase.cos()) * 20.0,
TrailMode::Torpedo => rng.rand_dir() * 10.0,
TrailMode::Railgun => {
let phase = t * 60.0; // TODO -- Hardcoded spiral curl
Point::new(phase.sin(), phase.cos()) * 20.0 // TODO -- Hardcoded spiral outward speed
}
TrailMode::Torpedo => rng.rand_dir_normalized() * 10.0, // TODO -- Hardcoded particle speed
TrailMode::PixieDust => {
let base_dir = rng.rand_dir();
let base_dir = rng.rand_dir_normalized();
let dir = Point::new(base_dir.x * 0.5, 0.4 + base_dir.y.abs());
dir * 30.0
dir * 30.0 // TODO -- hardcoded particle speed
}
};
let pos = prev_p + travel * (t + 0.3 * rng.next_f32() / particle_count as f32);
// TODO -- Spawn position should be at the base of the cursor, not the
// middle
// Distribute particles along the travel distance, with a random offset to make it
// look random
let pos = prev_p + travel * rng.next_f32();
self.add_particle(pos, speed, t * settings.vfx_particle_lifetime);
}
@ -242,16 +273,23 @@ impl CursorVfx for ParticleTrail {
fn restart(&mut self, _position: Point) {}
fn render(&self, settings: &CursorSettings, canvas: &mut Canvas, cursor: &Cursor, colors: &Colors, font_size: (f32, f32)) {
fn render(
&self,
settings: &CursorSettings,
canvas: &mut Canvas,
cursor: &Cursor,
colors: &Colors,
font_size: (f32, f32),
) {
let mut paint = Paint::new(skulpin::skia_safe::colors::WHITE, None);
match self.trail_mode {
TrailMode::Torpedo | TrailMode::Railgun => {
paint.set_style(Style::Stroke);
paint.set_stroke_width(font_size.1 * 0.2);
}
_ => {}
}
paint.set_stroke_width(font_size.1 * 0.2);
let base_color: Color = cursor.background(&colors).to_color();
paint.set_blend_mode(BlendMode::SrcOver);
@ -266,8 +304,8 @@ impl CursorVfx for ParticleTrail {
TrailMode::Torpedo | TrailMode::Railgun => font_size.0 * 0.5 * l,
TrailMode::PixieDust => font_size.0 * 0.2,
};
let hr = radius * 0.5;
let hr = radius * 0.5;
let rect = Rect::from_xywh(particle.pos.x - hr, particle.pos.y - hr, radius, radius);
match self.trail_mode {
@ -295,34 +333,59 @@ impl RngState {
inc: (0xDA3E39CB94B95BDBu64 << 1) | 1,
}
}
fn next(&mut self) -> u64 {
use std::num::Wrapping;
fn next(&mut self) -> u32 {
let old_state = self.state;
self.state =
(Wrapping(old_state) * Wrapping(6_364_136_223_846_793_005u64) + Wrapping(self.inc)).0;
let xorshifted = (old_state >> 18) ^ old_state >> 27;
let rot = (old_state >> 59) as i64;
(xorshifted >> rot as u64) | (xorshifted << ((-rot) & 31))
// Implementation copied from:
// https://rust-random.github.io/rand/src/rand_pcg/pcg64.rs.html#103
let new_state = old_state
.wrapping_mul(6_364_136_223_846_793_005u64)
.wrapping_add(self.inc);
self.state = new_state;
const ROTATE: u32 = 59; // 64 - 5
const XSHIFT: u32 = 18; // (5 + 32) / 2
const SPARE: u32 = 27; // 64 - 32 - 5
let rot = (old_state >> ROTATE) as u32;
let xsh = (((old_state >> XSHIFT) ^ old_state) >> SPARE) as u32;
xsh.rotate_right(rot)
}
fn next_f32(&mut self) -> f32 {
let v = self.next();
// In C we'd do ldexp(v, -32) to bring a number in the range [0,2^32) down to [0,1) range.
// But as we don't have ldexp in Rust, we're implementing the same idea (subtracting 32
// from the floating point exponent) manually.
// First, extract exponent bits
let float_bits = (v as f64).to_bits();
let exponent = (float_bits >> 53) & ((1 << 10) - 1);
// Set exponent for 0-1 range
let exponent = (float_bits >> 52) & ((1 << 11) - 1);
// Set exponent for [0-1) range
let new_exponent = exponent.max(32) - 32;
let new_bits = (new_exponent << 53) | (float_bits & 0x801F_FFFF_FFFF_FFFFu64);
// Build the new f64 value from the old mantissa and sign, and the new exponent
let new_bits = (new_exponent << 52) | (float_bits & 0x801F_FFFF_FFFF_FFFFu64);
f64::from_bits(new_bits) as f32
}
// Produces a random vector with x and y in the [-1,1) range
// Note: Vector is not normalized.
fn rand_dir(&mut self) -> Point {
let x = self.next_f32();
let y = self.next_f32();
Point::new(x * 2.0 - 1.0, y * 2.0 - 1.0)
}
fn rand_dir_normalized(&mut self) -> Point {
let mut v = self.rand_dir();
v.normalize();
v
}
}

Loading…
Cancel
Save