diff --git a/examples/noise_1d.cr b/examples/noise_1d.cr new file mode 100644 index 0000000..b858ed8 --- /dev/null +++ b/examples/noise_1d.cr @@ -0,0 +1,49 @@ +require "../src/game" +require "../src/controller" +require "../src/noise" + +module PF + class Noise1d < Game + @noise : Noise = Noise.new + @noise_scale : Float64 + @noise_zoom : Float64 + + def initialize(*args, **kwargs) + super + + @noise_scale = height / 4 + @noise_zoom = width / 4 + @xpos = 0.0 + + @controller = PF::Controller(LibSDL::Scancode).new({ + LibSDL::Scancode::UP => "scale up", + LibSDL::Scancode::DOWN => "scale down", + LibSDL::Scancode::RIGHT => "zoom up", + LibSDL::Scancode::LEFT => "zoom down", + }) + end + + def update(dt, event) + @controller.map_event(event) + @noise_scale += (@noise_scale * 0.8) * dt if @controller.held?("scale up") + @noise_scale -= (@noise_scale * 0.8) * dt if @controller.held?("scale down") + @noise_zoom += (@noise_zoom * 0.8) * dt if @controller.held?("zoom up") + @noise_zoom -= (@noise_zoom * 0.8) * dt if @controller.held?("zoom down") + @xpos += 20.0 * dt + end + + def draw + clear(50, 127, 200) + step = width // 15 + mid = height // 2 + + 0.upto(width) do |x| + y = mid + (@noise.get((x + @xpos) / @noise_zoom) * @noise_scale).to_i + draw_point(x, y, Pixel.yellow) + end + end + end +end + +game = PF::Noise1d.new(300, 200, 2) +game.run! diff --git a/spec/noise_spec.cr b/spec/noise_spec.cr new file mode 100644 index 0000000..c77fe87 --- /dev/null +++ b/spec/noise_spec.cr @@ -0,0 +1,13 @@ +require "./spec_helper" +require "../src/noise" + +include PF + +describe Noise do + describe ".cos_interpolate" do + it "interpolates" do + i = Noise.cosine_interpolate(0.0, 10.0, 0.5) + (4.9..5.1).includes?(i).should eq(true) + end + end +end diff --git a/src/lehmer32.cr b/src/lehmer32.cr index 7690431..83a8af2 100644 --- a/src/lehmer32.cr +++ b/src/lehmer32.cr @@ -1,5 +1,5 @@ module PF - class Lehmer32 + struct Lehmer32 include Random @state : UInt32 @@ -9,6 +9,7 @@ module PF def new_seed(n : Number) @state = n.to_u32! + self end # Generate the next number in the squence diff --git a/src/noise.cr b/src/noise.cr new file mode 100644 index 0000000..fd2f260 --- /dev/null +++ b/src/noise.cr @@ -0,0 +1,37 @@ +require "./lehmer32" + +module PF + @[Experimental("Undergoing development")] + struct Noise + # Cosine interpolation + def self.cosine_interpolate(point1 : Float64, point2 : Float64, position : Float64) + ft = position * Math::PI + f = (1 - Math.cos(ft)) * 0.5 + point1 * (1 - f) + point2 * f + end + + # Linear interpolation + def self.linear_interpolate(point1 : Float64, point2 : Float64, position : Float64) + point1 * (1 - position) + point2 * position + end + + @prng : Lehmer32 + @seed : UInt32 + + def initialize(@seed = ::rand(UInt32)) + @prng = Lehmer32.new + end + + # Returns 1d noise + def get(x : Float64) + x += @seed + n1 = @prng.new_seed(x.to_u32!).rand(-1.0..1.0) + n2 = @prng.new_seed(x.to_u32! + 1).rand(-1.0..1.0) + Noise.cosine_interpolate(n1, n2, x - x.to_u32!) + end + + # Returns 2d noise + # def get(x : Float64, y : Float64) + # end + end +end