Compare commits
4 Commits
a745c63de9
...
261392ee3d
Author | SHA1 | Date |
---|---|---|
Emi Simpson | 261392ee3d | |
Emi Simpson | 07ddec501a | |
Emi Simpson | 66093071ac | |
Emi Simpson | 38810f749c |
160
src/main.rs
160
src/main.rs
|
@ -1,5 +1,8 @@
|
|||
pub mod util;
|
||||
pub mod shadows;
|
||||
|
||||
use macroquad::prelude::draw_texture;
|
||||
use macroquad::prelude::DMat3;
|
||||
use smallvec::SmallVec;
|
||||
use smallvec::smallvec;
|
||||
use std::collections::HashSet;
|
||||
|
@ -11,33 +14,28 @@ use std::collections::HashMap;
|
|||
use core::fmt;
|
||||
use core::cell::Cell;
|
||||
use std::collections::hash_map::Entry;
|
||||
use macroquad::prelude::draw_circle_lines;
|
||||
use core::f64::consts::PI;
|
||||
use macroquad::prelude::mouse_position;
|
||||
use macroquad::prelude::is_mouse_button_pressed;
|
||||
use macroquad::prelude::Vec2;
|
||||
use core::ops::DerefMut;
|
||||
use core::ops::Deref;
|
||||
use macroquad::prelude::draw_line;
|
||||
use core::hash::Hasher;
|
||||
use core::hash::Hash;
|
||||
use macroquad::prelude::screen_height;
|
||||
use macroquad::prelude::next_frame;
|
||||
use macroquad::prelude::screen_width;
|
||||
use macroquad::prelude::draw_circle;
|
||||
use macroquad::prelude::clear_background;
|
||||
use macroquad::prelude::Color;
|
||||
use macroquad::input::MouseButton;
|
||||
use std::sync::Arc;
|
||||
|
||||
const BG: Color = Color::new(0.16863, 0.23922, 0.21176, 1.0);
|
||||
const FG: Color = Color::new(0.91569, 0.71765, 0.00000, 1.0);
|
||||
const DIM_FG: Color = Color::new(0.29412, 0.27451, 0.13333, 1.0);
|
||||
const HIL_FG: Color = Color::new(0.25806, 0.61290, 1.09032, 1.0);
|
||||
const FG: Color = Color::new(0.7686, 0.7216, 0.4078, 1.0);
|
||||
|
||||
const SPEED: f64 = 0.1;
|
||||
const BOING_RADIUS: f64 = 30.0;
|
||||
const HILITE: bool = false;
|
||||
const LIGHT_RADIUS: f32 = 128.;
|
||||
const WALL_THICKNESS: f32 = 5.;
|
||||
|
||||
#[macroquad::main("BasicShapes")]
|
||||
async fn main() {
|
||||
|
@ -46,10 +44,12 @@ async fn main() {
|
|||
set_camera(&camera);
|
||||
let mut iter = 0;
|
||||
|
||||
for _ in 0..200 {
|
||||
for _ in 0..100 {
|
||||
dd.add_random_point().unwrap();
|
||||
}
|
||||
|
||||
let gradient = shadows::get_gradient(LIGHT_RADIUS);
|
||||
|
||||
loop {
|
||||
if iter == 100 {
|
||||
iter = 0;
|
||||
|
@ -58,11 +58,11 @@ async fn main() {
|
|||
set_camera(&mut camera);
|
||||
}
|
||||
|
||||
let mouse_position: Vec2 = camera.screen_to_world(mouse_position().into());
|
||||
if is_mouse_button_pressed(MouseButton::Left) {
|
||||
dd.click(camera.screen_to_world(mouse_position().into()));
|
||||
dd.click(mouse_position);
|
||||
}
|
||||
if is_mouse_button_pressed(MouseButton::Right) {
|
||||
let mouse_position: Vec2 = camera.screen_to_world(mouse_position().into());
|
||||
|
||||
println!("{}", mouse_position);
|
||||
|
||||
|
@ -78,10 +78,35 @@ async fn main() {
|
|||
}
|
||||
}
|
||||
|
||||
clear_background(BG);
|
||||
clear_background(shadows::BLACK);
|
||||
|
||||
draw_texture(
|
||||
gradient,
|
||||
mouse_position.x - LIGHT_RADIUS,
|
||||
mouse_position.y - LIGHT_RADIUS,
|
||||
FG
|
||||
);
|
||||
|
||||
for (w1, w2) in dd.get_walls() {
|
||||
let w1 = w1.as_f32();
|
||||
let w2 = w2.as_f32();
|
||||
if shadows::wall_needs_to_be_drawn(w1, w2, mouse_position, LIGHT_RADIUS) {
|
||||
let perpendicular = (w1 - w2).perp();
|
||||
let shift = perpendicular / perpendicular.length() * WALL_THICKNESS;
|
||||
let points = [
|
||||
w1 + shift,
|
||||
w1 - shift,
|
||||
w2 + shift,
|
||||
w2 - shift,
|
||||
];
|
||||
shadows::draw_wall(points[0], points[1], mouse_position, LIGHT_RADIUS);
|
||||
shadows::draw_wall(points[1], points[2], mouse_position, LIGHT_RADIUS);
|
||||
shadows::draw_wall(points[2], points[3], mouse_position, LIGHT_RADIUS);
|
||||
shadows::draw_wall(points[3], points[0], mouse_position, LIGHT_RADIUS);
|
||||
}
|
||||
}
|
||||
|
||||
dd.update();
|
||||
//dd.draw_delaunay();
|
||||
dd.draw_voronoi();
|
||||
|
||||
iter += 1;
|
||||
next_frame().await;
|
||||
|
@ -337,25 +362,31 @@ impl Triangle {
|
|||
}
|
||||
|
||||
fn calc_circumcenter(a: DVec2, b: DVec2, c: DVec2) -> (DVec2, f64) {
|
||||
let len_a = b.distance(c);
|
||||
let len_b = c.distance(a);
|
||||
let len_c = a.distance(b);
|
||||
|
||||
let cos_a = (len_b.powf(2.0) + len_c.powf(2.0) - len_a.powf(2.0)) / (2.0 * len_b * len_c );
|
||||
let cos_b = (len_c.powf(2.0) + len_a.powf(2.0) - len_b.powf(2.0)) / (2.0 * len_c * len_a );
|
||||
let mag_a2 = a.powf(2.).dot(DVec2::ONE);
|
||||
let mag_b2 = b.powf(2.).dot(DVec2::ONE);
|
||||
let mag_c2 = c.powf(2.).dot(DVec2::ONE);
|
||||
|
||||
let ang_a = f64::acos(cos_a);
|
||||
let ang_b = f64::acos(cos_b);
|
||||
let ang_c = PI - ang_a - ang_b;
|
||||
|
||||
let sin_2a = f64::sin(2.0 * ang_a);
|
||||
let sin_2b = f64::sin(2.0 * ang_b);
|
||||
let sin_2c = f64::sin(2.0 * ang_c);
|
||||
|
||||
let circumcenter = DVec2::new(
|
||||
(a.x * sin_2a + b.x * sin_2b + c.x * sin_2c) / (sin_2a + sin_2b + sin_2c),
|
||||
(a.y * sin_2a + b.y * sin_2b + c.y * sin_2c) / (sin_2a + sin_2b + sin_2c),
|
||||
let s = DVec2::new(
|
||||
DMat3::from_cols_array(&[
|
||||
mag_a2, a.y, 1.,
|
||||
mag_b2, b.y, 1.,
|
||||
mag_c2, c.y, 1.,
|
||||
]).determinant() * 0.5,
|
||||
DMat3::from_cols_array(&[
|
||||
a.x, mag_a2, 1.,
|
||||
b.x, mag_b2, 1.,
|
||||
c.x, mag_c2, 1.,
|
||||
]).determinant() * 0.5,
|
||||
);
|
||||
|
||||
let little_a = DMat3::from_cols_array(&[
|
||||
a.x, a.y, 1.,
|
||||
b.x, b.y, 1.,
|
||||
c.x, c.y, 1.,
|
||||
]).determinant();
|
||||
|
||||
let circumcenter = s / little_a;
|
||||
let radius = circumcenter.distance(a);
|
||||
|
||||
(circumcenter, radius)
|
||||
|
@ -531,66 +562,17 @@ impl DelaunayDemo {
|
|||
}
|
||||
}
|
||||
|
||||
fn draw_delaunay(&self) {
|
||||
let mut highlight_segments = Vec::new();
|
||||
for triangle in &self.triangles {
|
||||
let (c, r) = triangle.circumcenter();
|
||||
let mpos: Vec2 = mouse_position().into();
|
||||
let color = if c.distance(mpos.as_f64()) < r && HILITE {
|
||||
highlight_segments.extend(&triangle.edges);
|
||||
HIL_FG
|
||||
} else {
|
||||
DIM_FG
|
||||
};
|
||||
draw_circle_lines(c.x as f32, c.y as f32, r as f32, 1.0, color);
|
||||
}
|
||||
for edge in self.adjacency.keys() {
|
||||
let color = if self.spanning_tree.contains(&edge) {
|
||||
HIL_FG
|
||||
} else {
|
||||
DIM_FG
|
||||
};
|
||||
let edge_0 = edge.0.get().as_f32();
|
||||
let edge_1 = edge.1.get().as_f32();
|
||||
|
||||
if
|
||||
edge_0.x < 0.0 || edge_0.x > self.width as f32
|
||||
|| edge_0.y < 0.0 || edge_0.y > self.height as f32
|
||||
|| edge_1.x < 0.0 || edge_1.x > self.width as f32
|
||||
|| edge_1.y < 0.0 || edge_1.y > self.height as f32
|
||||
{
|
||||
continue; //don't draw container nodes
|
||||
}
|
||||
draw_line(
|
||||
edge_0.x,
|
||||
edge_0.y,
|
||||
edge_1.x,
|
||||
edge_1.y,
|
||||
3.0, color
|
||||
);
|
||||
}
|
||||
for node in &self.nodes {
|
||||
let pos = node.get().as_f32();
|
||||
draw_circle(pos.x, pos.y, 10.0, FG);
|
||||
}
|
||||
}
|
||||
|
||||
fn draw_voronoi(&self) {
|
||||
for neighbors in self.adjacency.values() {
|
||||
if let (Occupant(tri1), Friend(tri2)) = neighbors {
|
||||
if !self.spanning_tree.contains(tri1.common_edge(tri2).unwrap()) {
|
||||
let (center1, _) = tri1.circumcenter();
|
||||
let (center2, _) = tri2.circumcenter();
|
||||
draw_line(
|
||||
center1.x as f32,
|
||||
center1.y as f32,
|
||||
center2.x as f32,
|
||||
center2.y as f32,
|
||||
3.0, FG
|
||||
);
|
||||
fn get_walls(&self) -> impl Iterator<Item=(DVec2, DVec2)> + '_ {
|
||||
self.adjacency.values()
|
||||
.filter_map(|n|
|
||||
if let (Occupant(tri1), Friend(tri2)) = n {
|
||||
Some((tri1, tri2))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
}
|
||||
)
|
||||
.filter(|(tri1, tri2)| !self.spanning_tree.contains(tri1.common_edge(tri2).unwrap()))
|
||||
.map(|(tri1, tri2)| (tri1.circumcenter().0, tri2.circumcenter().0))
|
||||
}
|
||||
|
||||
fn update(&mut self) {
|
||||
|
|
|
@ -0,0 +1,98 @@
|
|||
use macroquad::prelude::Mat2;
|
||||
use macroquad::prelude::draw_triangle;
|
||||
use macroquad::prelude::DVec2;
|
||||
use macroquad::prelude::draw_mesh;
|
||||
use macroquad::prelude::Vec3;
|
||||
use macroquad::models::Vertex;
|
||||
use macroquad::prelude::Mesh;
|
||||
use macroquad::prelude::Texture2D;
|
||||
use macroquad::prelude::Vec2;
|
||||
use macroquad::prelude::Image;
|
||||
use macroquad::prelude::Color;
|
||||
|
||||
//pub const LIGHT_COLOR: Color = Color::new(0.2980, 0.2824, 0.1686, 1.);
|
||||
pub const WHITE: Color = Color::new(1., 1., 1., 1.);
|
||||
pub const BLACK: Color = Color::new(0., 0., 0., 1.);
|
||||
|
||||
pub fn get_gradient(radius: f32) -> Texture2D {
|
||||
let dimension = (radius as u16) * 2 + 1;
|
||||
let center = Vec2::new(radius, radius);
|
||||
let mut img = Image::gen_image_color(dimension, dimension, BLACK);
|
||||
for x in 0..(dimension as u32) {
|
||||
for y in 0..(dimension as u32) {
|
||||
let pix = Vec2::new(x as f32, y as f32);
|
||||
let intensity = f32::max(0., (radius - pix.distance(center)) / radius);
|
||||
let mut color = WHITE;
|
||||
color.a = intensity;
|
||||
img.set_pixel(x, y, color);
|
||||
}
|
||||
}
|
||||
|
||||
Texture2D::from_image(&img)
|
||||
}
|
||||
|
||||
pub fn draw_wall(a: Vec2, b: Vec2, light_source: Vec2, radius: f32) {
|
||||
|
||||
let a_shft = a - light_source;
|
||||
let b_shft = b - light_source;
|
||||
|
||||
let mag_a = a_shft.length();
|
||||
let mag_b = b_shft.length();
|
||||
|
||||
let a_prime = a_shft.clamp_length_min(mag_a + radius);
|
||||
let b_prime = b_shft.clamp_length_min(mag_b + radius);
|
||||
let opposite_src = a_prime.lerp(b_prime, 0.5)
|
||||
.clamp_length_min(radius * 1.5);
|
||||
|
||||
let a_prime = light_source + a_prime;
|
||||
let b_prime = light_source + b_prime;
|
||||
let opposite_src = light_source + opposite_src;
|
||||
|
||||
draw_triangle(a, b_prime, b, BLACK);
|
||||
draw_triangle(a, b_prime, a_prime, BLACK);
|
||||
draw_triangle(b_prime, a_prime, opposite_src, BLACK);
|
||||
}
|
||||
|
||||
pub fn wall_needs_to_be_drawn(a: Vec2, b: Vec2, light_source: Vec2, radius: f32) -> bool {
|
||||
let a = a - light_source;
|
||||
let b = b - light_source;
|
||||
let delta = a - b;
|
||||
let unit = delta / delta.length();
|
||||
|
||||
let a_dot = unit.dot(a);
|
||||
let b_dot = unit.dot(b);
|
||||
|
||||
let d = Mat2::from_cols(unit, a).determinant();
|
||||
|
||||
(d < radius && d > -radius) && (
|
||||
a.length() < radius ||
|
||||
b.length() < radius ||
|
||||
(a_dot < 0. && b_dot > 0.) || (a_dot > 0. && b_dot < 0.)
|
||||
)
|
||||
}
|
||||
|
||||
/*/// Code adapted from https://github.com/not-fl3/macroquad/issues/174
|
||||
pub fn draw_polygon(points: &[Vec2], color: Color) {
|
||||
let points_length = points.len();
|
||||
let mut vertices = Vec::<Vertex>::with_capacity(points_length as usize + 2);
|
||||
let mut indices = Vec::<u16>::with_capacity(points_length as usize * 3);
|
||||
|
||||
for (i, point) in points.iter().enumerate() {
|
||||
let vertex = Vertex {
|
||||
position: Vec3::new(point.x, point.y, 0.0),
|
||||
uv: Vec2::default(),
|
||||
color
|
||||
};
|
||||
|
||||
vertices.push(vertex);
|
||||
indices.extend_from_slice(&[0, i as u16 + 1, i as u16 + 2]);
|
||||
}
|
||||
|
||||
let mesh = Mesh {
|
||||
vertices,
|
||||
indices,
|
||||
texture: None,
|
||||
};
|
||||
|
||||
draw_mesh(&mesh);
|
||||
}*/
|
Loading…
Reference in New Issue