
use nannou::prelude::*;
use rand::Rng;
struct Model {
color_coefficients: Vec<f32>, // ๊ฐ ๊ทธ๋ฆฌ๋ ์
์ hue ๊ณ์ ๊ฐ์ ์ ์ฅ
grid_size: usize, // ๊ทธ๋ฆฌ๋ ํฌ๊ธฐ (N x N)
max_grid_size: usize, // ์ต๋ ๊ทธ๋ฆฌ๋ ํฌ๊ธฐ (2^8 = 256)
show_too_dense: bool, // Too Dense ๋ฉ์์ง ํ์ ์ฌ๋ถ\
animation_offset: Vec<f32> // ๊ฐ ์
์ ์ ๋๋ฉ์ด์
์์ ์๊ฐ์ ๋ค๋ฅด๊ฒ ํ๊ธฐ ์ํ ์คํ์
}
fn main() {
nannou::app(model).update(update).run();
}
fn model(app: &App) -> Model {
app.new_window()
.size(1000, 1000)
.view(view)
.key_pressed(key_pressed)
.build()
.unwrap();
// ์ด๊ธฐ ๊ทธ๋ฆฌ๋ ํฌ๊ธฐ๋ฅผ 2๋ก ์ค์ , ์ต๋ ํฌ๊ธฐ๋ 2^8 = 256
let grid_size = 2;
let max_grid_size = 256; // 2^8
let total_cells = grid_size * grid_size;
// ๋๋คํ hue ๊ณ์ ๊ฐ์ผ๋ก ๊ทธ๋ฆฌ๋ ์์ ์ด๊ธฐํ
let mut rng = rand::thread_rng();
let color_coefficients = (0..total_cells).map(|_| rng.gen_range(0.0..1.0)).collect();
// ์ ๋๋ฉ์ด์
์คํ์
๋ฒกํฐ๋ฅผ ๋๋คํ๊ฒ ์์ฑ
// PI * 2.0์ผ๋ก ํ ์ฃผ๊ธฐ๋ฅผ ๊ตฌํ
let animation_offset = (0..total_cells).map(|_| rng.gen_range(0.0..PI * 2.0)).collect();
Model {
color_coefficients,
grid_size,
max_grid_size,
show_too_dense: false,
animation_offset,
}
}
fn update(_app: &App, _model: &mut Model, _update: Update) {
// Too Dense ๋ฉ์์ง๋ฅผ ์ผ์ ์๊ฐ ํ์ ์ฌ๋ผ์ง๊ฒ ํจ
// ๊ฐ๋จํ ๊ตฌํ: ๋ค์ ํ๋ ์์์ ๊ณ์ ํ์
}
fn view(app: &App, model: &Model, frame: Frame) {
let draw = app.draw();
let win = app.window_rect();
// ๋ฐฐ๊ฒฝ์ ๊ฒ์์์ผ๋ก
draw.background().color(BLACK);
let grid_size = model.grid_size;
let cell_width = win.w() / grid_size as f32;
let cell_height = win.h() / grid_size as f32;
for i in 0..grid_size {
for j in 0..grid_size {
let idx = i * grid_size + j;
if idx >= model.color_coefficients.len() {
continue;
}
// โจ ์ ๋๋ฉ์ด์
๋ก์ง ์์
let base_saturation = model.color_coefficients[idx];
let animation_offset = model.animation_offset[idx];
// app.time์ ๋ฐ๋ผ -1.0 ~ 1.0 ์ฌ์ด๋ฅผ ๋ฐ๋ณตํ๋ ์ฌ์ธํ(sin) ๊ฐ์ ๊ตฌํฉ๋๋ค.
// ์ฌ๊ธฐ์ ๊ฐ ์
์ ๊ณ ์ ์คํ์
์ ๋ํด ๋ชจ๋ ๋ค๋ฅธ ํ์ด๋ฐ์ ์์ง์ด๊ฒ ํฉ๋๋ค.
let sin_wave = (app.time + animation_offset).sin();
// ์ฌ์ธํ ๊ฒฐ๊ณผ(-1.0 ~ 1.0)๋ฅผ 0.0 ~ 1.0 ๋ฒ์๋ก ๋ณํํฉ๋๋ค.
// (sin_wave + 1.0) -> 0.0 ~ 2.0 / 2.0 -> 0.0 ~ 1.0
let time_coefficient = (sin_wave + 1.0) / 2.0;
// ์ต์ข
์ฑ๋๋ (๊ธฐ๋ณธ ์ฑ๋ * ์๊ฐ ๊ณ์)๋ก ๊ณ์ฐํ์ฌ ๋ฐ์ง์ด๋ ํจ๊ณผ๋ฅผ ์ค๋๋ค.
let color_factor = base_saturation * time_coefficient;
// โจ ์ ๋๋ฉ์ด์
๋ก์ง ๋
let x = win.left() + cell_width * (j as f32 + 0.5);
let y = win.top() - cell_height * (i as f32 + 0.5);
draw.rect()
.x_y(x, y)
.w_h(cell_width, cell_height)
// HSL์ S(์ฑ๋) ๊ฐ์ ๋ฐฉ๊ธ ๊ณ์ฐํ animated_saturation์ ์ฌ์ฉํฉ๋๋ค.
.color(hsl(color_factor, color_factor, 0.7));
}
}
// Too Dense ๋ฉ์์ง ํ์
if model.show_too_dense {
draw.text("Too Dense")
.x_y(0.0, 0.0)
.color(WHITE)
.font_size(48)
.align_text_middle_y();
}
draw.to_frame(app, &frame).unwrap();
}
fn key_pressed(_app: &App, model: &mut Model, key: Key) {
match key {
Key::C => {
// C ํค๋ฅผ ๋๋ฅด๋ฉด ๋ชจ๋ ์
์ hue ๊ณ์ ๊ฐ์ ๋๋คํ๊ฒ ๋ณ๊ฒฝ
let total_cells = model.grid_size * model.grid_size;
// ์์ ๊ณ์ ๋ฐฐ์ด ํฌ๊ธฐ๊ฐ ๋ง๋์ง ํ์ธํ๊ณ ํ์์ resize
if model.color_coefficients.len() != total_cells {
model.color_coefficients.resize(total_cells, 0.0);
}
let mut rng = rand::thread_rng();
for coefficient in &mut model.color_coefficients {
*coefficient = rng.gen_range(0.0..1.0);
}
model.show_too_dense = false;
}
Key::Up => {
// ์ ํ์ดํ: ๊ทธ๋ฆฌ๋ ํฌ๊ธฐ 2๋ฐฐ (์ต๋ ํฌ๊ธฐ ์ ํ)
if model.grid_size * 2 <= model.max_grid_size {
model.grid_size *= 2;
let total_cells = model.grid_size * model.grid_size;
// ์๋ก์ด ํฌ๊ธฐ์ ๋ง๊ฒ ์์ ๊ณ์ ๋ฐฐ์ด ์ฌ์์ฑ
let mut rng = rand::thread_rng();
model.color_coefficients = (0..total_cells)
.map(|_| rng.gen_range(0.0..1.0))
.collect();
// ๊ทธ๋ฆฌ๋ ํฌ๊ธฐ๊ฐ ๋ฐ๋์์ผ๋ ์คํ์
๋ ์๋ก ์์ฑ
model.animation_offset = (0..total_cells)
.map(|_| rng.gen_range(0.0..PI * 2.0))
.collect();
model.show_too_dense = false;
} else {
// ์ต๋ ํฌ๊ธฐ ์ด๊ณผ์ ๋ฉ์์ง ํ์
model.show_too_dense = true;
}
}
Key::Down => {
// ์๋ ํ์ดํ: ๊ทธ๋ฆฌ๋ ํฌ๊ธฐ ์ ๋ฐ (์ต์ 1 ์ ์ง)
if model.grid_size > 1 {
model.grid_size /= 2;
let total_cells = model.grid_size * model.grid_size;
// ์๋ก์ด ํฌ๊ธฐ์ ๋ง๊ฒ ์์ ๊ณ์ ๋ฐฐ์ด ์ฌ์์ฑ
let mut rng = rand::thread_rng();
model.color_coefficients = (0..total_cells)
.map(|_| rng.gen_range(0.0..1.0))
.collect();
// ๊ทธ๋ฆฌ๋ ํฌ๊ธฐ๊ฐ ๋ฐ๋์์ผ๋ ์คํ์
๋ ์๋ก ์์ฑ
model.animation_offset = (0..total_cells)
.map(|_| rng.gen_range(0.0..PI * 2.0))
.collect();
}
model.show_too_dense = false;
}
_ => {}
}
}
---