#![recursion_limit="1024"]
#![feature(trivial_bounds)]
extern crate gl_struct;
extern crate glfw;
extern crate gl;
extern crate rand;
use gl_struct::*;
glsl!{$
use self::ParticleUpdator::Particle;
pub mod ParticleShader {
@Vertex
#version 140
uniform float expansion;
in vec2 pos;
out float distance;
void main() {
distance = length(pos) / expansion;
gl_Position = vec4(pos, 0, expansion);
}
@Fragment
#version 140
in float distance;
void main() {
gl_FragColor = vec4(1-distance/10, 0, 1, 1);
}
}
pub mod ParticleUpdator {
@Compute
#version 440
layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
uniform float factor;
uniform float dt;
public struct Particle {
vec2 pos;
vec2 vel;
};
layout(std430) buffer Particles {
Particle p1[];
};
layout(std430) buffer NewParticles {
Particle p2[];
};
void main() {
const float g = 0.1;
vec2 p = p1[gl_GlobalInvocationID.x].pos;
vec2 v = p1[gl_GlobalInvocationID.x].vel;
p2[gl_GlobalInvocationID.x].pos = (v * dt + p* factor*exp(dt));
for(int i=0; i<gl_NumWorkGroups.x; i++) {
if(i!=gl_GlobalInvocationID.x) {
for(int x=-4; x<=4; x+=2){
for(int y=-4; y<=4; y+=2){
vec2 d = (p+vec2(x,y)) - p1[i].pos;
float r2 = dot(d, d);
if(r2 > 0.0000025) {
v -= g * dt * (1 / (r2)) * inversesqrt(r2) * d ;
}
}
}
}
}
p2[gl_GlobalInvocationID.x].vel = v;
}
}
}
fn main() {
let mut glfw = glfw::init(glfw::FAIL_ON_ERRORS).unwrap();
let width = 640;
let height = 480;
let mut window = glfw.create_window(width, height, "Basic gravity demo", glfw::WindowMode::Windowed).unwrap().0;
glfw::Context::make_current(&mut window);
window.set_key_polling(true);
glfw.set_swap_interval(glfw::SwapInterval::None);
let gl_provider = unsafe {
GLProvider::load(|s| ::std::mem::transmute(glfw.get_proc_address_raw(s)))
};
let mut context = Context::init(&gl_provider);
let mut shader = ParticleShader::init(&gl_provider).unwrap();
let mut computer = ParticleUpdator::init(&gl_provider).unwrap();
let num = 1000;
let speed = 0.1;
let mut init = Vec::with_capacity(num);
for _i in 0..num {
init.push(Particle{
pos: [rand::random::<f32>() * 2.0 - 1.0, rand::random::<f32>() * 2.0 - 1.0].into(),
vel: [(rand::random::<f32>() - 0.5)*speed, (rand::random::<f32>() - 0.5)*speed].into()
});
}
let (mut buf1, mut buf2) =
(Buffer::immut_from(&gl_provider, init.clone().into_boxed_slice()),
Buffer::immut_from(&gl_provider, init.into_boxed_slice()));
unsafe {
let (w, h) = (width as i32, height as i32);
if w > h {
gl::Viewport((w-h)/2,0,h,h);
} else {
gl::Viewport(0,(h-w)/2,w,w);
}
gl::Disable(gl::CULL_FACE);
gl::Disable(gl::DEPTH_TEST);
gl::Disable(gl::BLEND);
gl::PointSize(2.0);
}
let mut flip = false;
*shader.expansion = 1.0;
*computer.factor = 1.000;
*computer.dt = 0.0001;
while !window.should_close() {
glfw::Context::swap_buffers(&mut window);
glfw.poll_events();
unsafe {
gl::Clear(gl::COLOR_BUFFER_BIT | gl::DEPTH_BUFFER_BIT);
gl::ClearColor(1.0,1.0,1.0,0.0);
}
let p1 = &mut buf1;
let p2 = &mut buf2;
if flip {
computer.compute(num as u32, 1, 1, p1, p2);
shader.draw(&mut context, DrawMode::Points, num, Particle::get_attributes(p1).0);
} else {
computer.compute(num as u32, 1, 1, p2, p1);
shader.draw(&mut context, DrawMode::Points, num, Particle::get_attributes(p2).0);
}
flip = !flip;
*shader.expansion *= *computer.factor * (*computer.dt).exp();
}
}