mirror of
https://github.com/Astatin3/IntroToWebAuthoring.git
synced 2026-06-09 00:28:00 -06:00
Start work on views system
This commit is contained in:
+8
-4
@@ -16,11 +16,15 @@ addEventListener("TrunkApplicationStarted", (event) => {
|
|||||||
window.wasmBindings.resize(context, width, height);
|
window.wasmBindings.resize(context, width, height);
|
||||||
});
|
});
|
||||||
|
|
||||||
canvas.addEventListener("click", (e) => {
|
canvas.addEventListener("mousemove", (event) => {
|
||||||
// console.log(e);
|
window.wasmBindings.mouse_move(context, event.pageX, event.pageY);
|
||||||
|
});
|
||||||
|
|
||||||
// [width, height] = [window.innerWidth, window.innerHeight];
|
canvas.addEventListener("click", (e) => {
|
||||||
// console.log("Window resized: (", width, ", ", height, ")");
|
|
||||||
window.wasmBindings.click(context, e.pageX, e.pageY);
|
window.wasmBindings.click(context, e.pageX, e.pageY);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// export function cursor(name) {
|
||||||
|
// document.body.style.cursor = name;
|
||||||
|
// }
|
||||||
|
|||||||
@@ -0,0 +1,3 @@
|
|||||||
|
mod test_activity;
|
||||||
|
|
||||||
|
pub use test_activity::TestActivity;
|
||||||
@@ -0,0 +1,166 @@
|
|||||||
|
use crate::{
|
||||||
|
app::{Activity, App, AppState},
|
||||||
|
log,
|
||||||
|
render::Renderer,
|
||||||
|
};
|
||||||
|
|
||||||
|
pub struct TestActivity {
|
||||||
|
elements: Vec<Element>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl TestActivity {
|
||||||
|
pub fn top_element_at_point(&mut self, x: f32, y: f32) -> Option<(&mut Element, usize)> {
|
||||||
|
for (i, element) in self.elements.iter_mut().enumerate().rev() {
|
||||||
|
if x >= element.x
|
||||||
|
&& x <= element.x + element.width
|
||||||
|
&& y >= element.y
|
||||||
|
&& y <= element.y + element.height
|
||||||
|
{
|
||||||
|
return Some((element, i));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
None
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn bottom_element_at_point(
|
||||||
|
&mut self,
|
||||||
|
x: f32,
|
||||||
|
y: f32,
|
||||||
|
min_index: usize,
|
||||||
|
) -> Option<(&mut Element, usize)> {
|
||||||
|
for (i, element) in self.elements.iter_mut().enumerate().skip(min_index) {
|
||||||
|
if x >= element.x
|
||||||
|
&& x <= element.x + element.width
|
||||||
|
&& y >= element.y
|
||||||
|
&& y <= element.y + element.height
|
||||||
|
{
|
||||||
|
return Some((element, i));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
None
|
||||||
|
}
|
||||||
|
|
||||||
|
fn mark_for_redraw(&mut self, current_elements: &mut Vec<usize>, element_index: usize) {
|
||||||
|
current_elements.push(element_index);
|
||||||
|
|
||||||
|
let element = &self.elements[element_index];
|
||||||
|
|
||||||
|
for (x, y) in vec![
|
||||||
|
(element.x.clone(), element.y.clone()),
|
||||||
|
(element.x.clone() + element.width, element.y.clone()),
|
||||||
|
(element.x.clone(), element.y.clone() + element.height),
|
||||||
|
(
|
||||||
|
element.x.clone() + element.width,
|
||||||
|
element.y.clone() + element.height,
|
||||||
|
),
|
||||||
|
] {
|
||||||
|
let option = self.bottom_element_at_point(x, y, element_index + 1);
|
||||||
|
if let Some((element, index)) = option {
|
||||||
|
if element_index == index || current_elements.contains(&index) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
self.mark_for_redraw(current_elements, index);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Activity for TestActivity {
|
||||||
|
fn new() -> Self
|
||||||
|
where
|
||||||
|
Self: Sized,
|
||||||
|
{
|
||||||
|
Self {
|
||||||
|
elements: Vec::new(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn update(&mut self, dt: f32) {
|
||||||
|
// todo!()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn draw(&self, renderer: &mut Renderer, state: &AppState) {
|
||||||
|
renderer.img.randomize(&mut renderer.rand);
|
||||||
|
let (cx, cy) = (renderer.actual_width / 2, renderer.actual_height / 2);
|
||||||
|
renderer.circle(cx as i32, cy as i32, 100, (127, 127, 127));
|
||||||
|
|
||||||
|
// renderer.rect_center_xywh(cx as i32, cy as i32, 200, 200, (155, 127, 155));
|
||||||
|
// renderer.rect_xyxy(10, 10, cx as i32, cy as i32, (255, 127, 155));
|
||||||
|
|
||||||
|
for element in &self.elements {
|
||||||
|
element.draw(renderer);
|
||||||
|
}
|
||||||
|
|
||||||
|
renderer.update();
|
||||||
|
}
|
||||||
|
|
||||||
|
fn l_click(&mut self, renderer: &mut Renderer, state: &AppState) {
|
||||||
|
// log!("Mouse moved");
|
||||||
|
let option = self.top_element_at_point(state.mouse_x, state.mouse_y);
|
||||||
|
if let Some((_, index)) = option {
|
||||||
|
let mut for_redraw: Vec<usize> = Vec::new();
|
||||||
|
self.mark_for_redraw(&mut for_redraw, index);
|
||||||
|
|
||||||
|
for_redraw.sort();
|
||||||
|
|
||||||
|
for n in for_redraw.iter_mut() {
|
||||||
|
let element = &mut self.elements[*n];
|
||||||
|
element.color = (
|
||||||
|
renderer.rand.next_u32() as u8,
|
||||||
|
renderer.rand.next_u32() as u8,
|
||||||
|
renderer.rand.next_u32() as u8,
|
||||||
|
);
|
||||||
|
element.draw(renderer);
|
||||||
|
}
|
||||||
|
renderer.update();
|
||||||
|
} else {
|
||||||
|
self.elements.push(Element::new(
|
||||||
|
state.mouse_x,
|
||||||
|
state.mouse_y,
|
||||||
|
50.0,
|
||||||
|
50.0,
|
||||||
|
(
|
||||||
|
renderer.rand.next_u32() as u8,
|
||||||
|
renderer.rand.next_u32() as u8,
|
||||||
|
renderer.rand.next_u32() as u8,
|
||||||
|
),
|
||||||
|
));
|
||||||
|
|
||||||
|
self.draw(renderer, state);
|
||||||
|
renderer.update();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn mouse_move(&mut self, renderer: &mut Renderer, state: &AppState) {}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct Element {
|
||||||
|
pub x: f32,
|
||||||
|
pub y: f32,
|
||||||
|
pub width: f32,
|
||||||
|
pub height: f32,
|
||||||
|
pub color: (u8, u8, u8),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Element {
|
||||||
|
pub fn new(x: f32, y: f32, width: f32, height: f32, color: (u8, u8, u8)) -> Self {
|
||||||
|
Self {
|
||||||
|
x,
|
||||||
|
y,
|
||||||
|
width,
|
||||||
|
height,
|
||||||
|
color,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn draw(&self, renderer: &mut Renderer) {
|
||||||
|
renderer.rect_xywh(
|
||||||
|
self.x as i32,
|
||||||
|
self.y as i32,
|
||||||
|
self.width as i32,
|
||||||
|
self.height as i32,
|
||||||
|
self.color,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
-57
@@ -1,57 +0,0 @@
|
|||||||
use wasm_bindgen::prelude::wasm_bindgen;
|
|
||||||
|
|
||||||
use crate::render::Renderer;
|
|
||||||
|
|
||||||
pub trait Activity {
|
|
||||||
fn new() -> Self
|
|
||||||
where
|
|
||||||
Self: Sized;
|
|
||||||
fn update(&mut self, dt: f32);
|
|
||||||
fn draw(&self, ctx: &mut Renderer);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[wasm_bindgen]
|
|
||||||
pub struct App {
|
|
||||||
pub(crate) activities: Vec<Box<dyn Activity>>,
|
|
||||||
pub(crate) renderer: Renderer,
|
|
||||||
pub(crate) current_activity: Option<usize>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl App {
|
|
||||||
pub fn new(renderer: Renderer) -> Self {
|
|
||||||
App {
|
|
||||||
activities: Vec::new(),
|
|
||||||
renderer,
|
|
||||||
current_activity: None,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn draw(&mut self) {
|
|
||||||
// if let Some(current_activity) = self.current_activity {
|
|
||||||
// self.activities[current_activity].draw(&mut self.renderer);
|
|
||||||
// }
|
|
||||||
self.renderer.img.randomize(&mut self.renderer.rand);
|
|
||||||
|
|
||||||
let (cx, cy) = (
|
|
||||||
self.renderer.actual_width / 2,
|
|
||||||
self.renderer.actual_height / 2,
|
|
||||||
);
|
|
||||||
|
|
||||||
self.renderer
|
|
||||||
.circle(cx as i32, cy as i32, 200, (255, 255, 255));
|
|
||||||
|
|
||||||
self.renderer.update();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// App events
|
|
||||||
impl App {
|
|
||||||
pub fn resize(&mut self, width: u32, height: u32) {
|
|
||||||
self.renderer.resize(width, height);
|
|
||||||
self.draw();
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn click(&mut self, x: f32, y: f32) {
|
|
||||||
// self.renderer.click(x, y);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -0,0 +1,91 @@
|
|||||||
|
use wasm_bindgen::prelude::wasm_bindgen;
|
||||||
|
|
||||||
|
#[wasm_bindgen(module = "/js/index.js")]
|
||||||
|
extern "C" {
|
||||||
|
fn cursor(name: &str);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn set_cursor(c: Cursor) {
|
||||||
|
cursor(c.value());
|
||||||
|
}
|
||||||
|
|
||||||
|
#[allow(dead_code)]
|
||||||
|
pub enum Cursor {
|
||||||
|
Alias,
|
||||||
|
AllScroll,
|
||||||
|
Auto,
|
||||||
|
Cell,
|
||||||
|
ColResize,
|
||||||
|
ContextMenu,
|
||||||
|
Copy,
|
||||||
|
Crosshair,
|
||||||
|
Default,
|
||||||
|
EResize,
|
||||||
|
EWResize,
|
||||||
|
Grab,
|
||||||
|
Grabbing,
|
||||||
|
Help,
|
||||||
|
Move,
|
||||||
|
NResize,
|
||||||
|
NEResize,
|
||||||
|
NESWResize,
|
||||||
|
NSResize,
|
||||||
|
NWResize,
|
||||||
|
NWSEResize,
|
||||||
|
NoDrop,
|
||||||
|
None,
|
||||||
|
NotAllowed,
|
||||||
|
Pointer,
|
||||||
|
Progress,
|
||||||
|
RowResize,
|
||||||
|
SResize,
|
||||||
|
SEResize,
|
||||||
|
SWResize,
|
||||||
|
Text,
|
||||||
|
WResize,
|
||||||
|
Wait,
|
||||||
|
ZoomIn,
|
||||||
|
ZoomOut,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Cursor {
|
||||||
|
fn value(&self) -> &str {
|
||||||
|
match self {
|
||||||
|
Cursor::Alias => "alias",
|
||||||
|
Cursor::AllScroll => "all-scroll",
|
||||||
|
Cursor::Auto => "auto",
|
||||||
|
Cursor::Cell => "cell",
|
||||||
|
Cursor::ColResize => "col-resize",
|
||||||
|
Cursor::ContextMenu => "context-menu",
|
||||||
|
Cursor::Copy => "copy",
|
||||||
|
Cursor::Crosshair => "crosshair",
|
||||||
|
Cursor::Default => "default",
|
||||||
|
Cursor::EResize => "e-resize",
|
||||||
|
Cursor::EWResize => "ew-resize",
|
||||||
|
Cursor::Grab => "grab",
|
||||||
|
Cursor::Grabbing => "grabbing",
|
||||||
|
Cursor::Help => "help",
|
||||||
|
Cursor::Move => "move",
|
||||||
|
Cursor::NResize => "n-resize",
|
||||||
|
Cursor::NEResize => "ne-resize",
|
||||||
|
Cursor::NESWResize => "nesw-resize",
|
||||||
|
Cursor::NSResize => "ns-resize",
|
||||||
|
Cursor::NWResize => "nw-resize",
|
||||||
|
Cursor::NWSEResize => "nwse-resize",
|
||||||
|
Cursor::NoDrop => "no-drop",
|
||||||
|
Cursor::None => "none",
|
||||||
|
Cursor::NotAllowed => "not-allowed",
|
||||||
|
Cursor::Pointer => "pointer",
|
||||||
|
Cursor::Progress => "progress",
|
||||||
|
Cursor::RowResize => "row-resize",
|
||||||
|
Cursor::SResize => "s-resize",
|
||||||
|
Cursor::SEResize => "se-resize",
|
||||||
|
Cursor::SWResize => "sw-resize",
|
||||||
|
Cursor::Text => "text",
|
||||||
|
Cursor::WResize => "w-resize",
|
||||||
|
Cursor::Wait => "wait",
|
||||||
|
Cursor::ZoomIn => "zoom-in",
|
||||||
|
Cursor::ZoomOut => "zoom-out",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,93 @@
|
|||||||
|
mod cursors;
|
||||||
|
|
||||||
|
pub use cursors::{Cursor, set_cursor};
|
||||||
|
|
||||||
|
use wasm_bindgen::prelude::wasm_bindgen;
|
||||||
|
|
||||||
|
use crate::{
|
||||||
|
log,
|
||||||
|
render::Renderer,
|
||||||
|
views::{View, default_view},
|
||||||
|
};
|
||||||
|
|
||||||
|
pub trait Activity {
|
||||||
|
fn new() -> Self
|
||||||
|
where
|
||||||
|
Self: Sized;
|
||||||
|
fn update(&mut self, dt: f32);
|
||||||
|
fn draw(&self, renderer: &mut Renderer, state: &AppState);
|
||||||
|
fn l_click(&mut self, renderer: &mut Renderer, state: &AppState);
|
||||||
|
fn mouse_move(&mut self, renderer: &mut Renderer, state: &AppState);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[wasm_bindgen]
|
||||||
|
pub struct App {
|
||||||
|
// pub(crate) activities: Vec<Box<dyn Activity>>,
|
||||||
|
pub(crate) root_view: Option<Box<dyn View>>,
|
||||||
|
pub(crate) renderer: Renderer,
|
||||||
|
// pub(crate) current_activity: Option<usize>,
|
||||||
|
pub(crate) state: AppState,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct AppState {
|
||||||
|
pub(crate) mouse_x: f32,
|
||||||
|
pub(crate) mouse_y: f32,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl AppState {
|
||||||
|
pub fn new() -> Self {
|
||||||
|
AppState {
|
||||||
|
mouse_x: 0.0,
|
||||||
|
mouse_y: 0.0,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl App {
|
||||||
|
pub fn new(renderer: Renderer) -> Self {
|
||||||
|
App {
|
||||||
|
root_view: Some(default_view()),
|
||||||
|
renderer,
|
||||||
|
// current_activity: Some(0),
|
||||||
|
state: AppState::new(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn draw(&mut self) {
|
||||||
|
if let Some(view) = &self.root_view {
|
||||||
|
let (width, height) = (
|
||||||
|
self.renderer.actual_width.clone() as f32,
|
||||||
|
self.renderer.actual_height.clone() as f32,
|
||||||
|
);
|
||||||
|
|
||||||
|
view.draw(&mut self.renderer, 0., 0., width, height);
|
||||||
|
self.renderer.update();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// App events
|
||||||
|
impl App {
|
||||||
|
pub fn resize(&mut self, width: u32, height: u32) {
|
||||||
|
self.renderer.resize(width, height);
|
||||||
|
self.draw();
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn mouse_move(&mut self, x: f32, y: f32) {
|
||||||
|
self.state.mouse_x = x;
|
||||||
|
self.state.mouse_y = y;
|
||||||
|
|
||||||
|
// if let Some(current_activity) = self.current_activity {
|
||||||
|
// self.activities[current_activity].mouse_move(&mut self.renderer, &self.state);
|
||||||
|
// }
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn l_click(&mut self, x: f32, y: f32) {
|
||||||
|
self.state.mouse_x = x;
|
||||||
|
self.state.mouse_y = y;
|
||||||
|
|
||||||
|
// if let Some(current_activity) = self.current_activity {
|
||||||
|
// self.activities[current_activity].l_click(&mut self.renderer, &self.state);
|
||||||
|
// }
|
||||||
|
}
|
||||||
|
}
|
||||||
-15
@@ -1,15 +0,0 @@
|
|||||||
use crate::render::Renderer;
|
|
||||||
|
|
||||||
pub fn draw(ctx: &mut Renderer) {
|
|
||||||
// // Draw the background
|
|
||||||
// ctx.background(0.0, 0.0, 0.0);
|
|
||||||
|
|
||||||
// // Draw the foreground
|
|
||||||
// ctx.fill(1.0, 1.0, 1.0);
|
|
||||||
// ctx.rect(50.0, 50.0, 100.0, 100.0);
|
|
||||||
//
|
|
||||||
|
|
||||||
let (cx, cy) = (ctx.actual_width / 2, ctx.actual_height / 2);
|
|
||||||
|
|
||||||
ctx.circle(cx as i32, cy as i32, 200, (255, 255, 255));
|
|
||||||
}
|
|
||||||
+14
-12
@@ -1,5 +1,7 @@
|
|||||||
|
// mod activities;
|
||||||
mod app;
|
mod app;
|
||||||
mod render;
|
mod render;
|
||||||
|
mod views;
|
||||||
|
|
||||||
use wasm_bindgen::{Clamped, prelude::*};
|
use wasm_bindgen::{Clamped, prelude::*};
|
||||||
use web_sys::ImageData;
|
use web_sys::ImageData;
|
||||||
@@ -8,7 +10,10 @@ use web_sys::ImageData;
|
|||||||
use render::buffer::ImgBuffer;
|
use render::buffer::ImgBuffer;
|
||||||
use render::rand::Rnd;
|
use render::rand::Rnd;
|
||||||
|
|
||||||
use crate::{app::App, render::Renderer};
|
use crate::{
|
||||||
|
app::{App, Cursor, set_cursor},
|
||||||
|
render::Renderer,
|
||||||
|
};
|
||||||
|
|
||||||
#[wasm_bindgen]
|
#[wasm_bindgen]
|
||||||
extern "C" {
|
extern "C" {
|
||||||
@@ -28,6 +33,7 @@ pub fn init(canvas: &web_sys::HtmlCanvasElement, width: u32, height: u32) -> App
|
|||||||
canvas.set_height(cheight);
|
canvas.set_height(cheight);
|
||||||
|
|
||||||
log!("WASM Successfully initialized!");
|
log!("WASM Successfully initialized!");
|
||||||
|
// set_cursor(Cursor::Auto);
|
||||||
|
|
||||||
let mut renderer = Renderer {
|
let mut renderer = Renderer {
|
||||||
ctx: canvas
|
ctx: canvas
|
||||||
@@ -65,17 +71,13 @@ pub fn draw(app: &mut App) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[wasm_bindgen]
|
#[wasm_bindgen]
|
||||||
pub fn click(app: &mut App, x: i32, y: i32) {
|
pub fn click(app: &mut App, x: f32, y: f32) {
|
||||||
// ctx.img.randomize(&mut ctx.rand);
|
// ctx.img.randomize(&mut ctx.rand);
|
||||||
// draw::draw(ctx);
|
// draw::draw(ctx);
|
||||||
|
app.l_click(x, y);
|
||||||
app.renderer.circle(x, y, 20, (255, 255, 255));
|
}
|
||||||
|
|
||||||
let data = ImageData::new_with_u8_clamped_array_and_sh(
|
#[wasm_bindgen]
|
||||||
Clamped(&app.renderer.img.data),
|
pub fn mouse_move(app: &mut App, x: f32, y: f32) {
|
||||||
app.renderer.img.width(),
|
app.mouse_move(x, y);
|
||||||
app.renderer.img.height(),
|
|
||||||
)
|
|
||||||
.unwrap();
|
|
||||||
app.renderer.ctx.put_image_data(&data, 0., 0.).unwrap();
|
|
||||||
}
|
}
|
||||||
|
|||||||
+19
-1
@@ -4,7 +4,7 @@ mod renderer;
|
|||||||
|
|
||||||
pub use renderer::Renderer;
|
pub use renderer::Renderer;
|
||||||
|
|
||||||
pub const RESOLUTION: u32 = 800;
|
pub const RESOLUTION: u32 = 1200;
|
||||||
|
|
||||||
pub fn calc_resolution(width: u32, height: u32) -> (u32, u32, f32, f32) {
|
pub fn calc_resolution(width: u32, height: u32) -> (u32, u32, f32, f32) {
|
||||||
let aspect = width as f32 / height as f32;
|
let aspect = width as f32 / height as f32;
|
||||||
@@ -15,3 +15,21 @@ pub fn calc_resolution(width: u32, height: u32) -> (u32, u32, f32, f32) {
|
|||||||
let new_height = (distortion_y * RESOLUTION as f32).round() as u32;
|
let new_height = (distortion_y * RESOLUTION as f32).round() as u32;
|
||||||
(new_width, new_height, distortion_x, distortion_y)
|
(new_width, new_height, distortion_x, distortion_y)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// aspect = width / height
|
||||||
|
// dist_x = aspect
|
||||||
|
// dist_y = height / width
|
||||||
|
//
|
||||||
|
// cw = RES * width / height
|
||||||
|
// ch = RES * height / width
|
||||||
|
//
|
||||||
|
// ux = x * (width / cw)
|
||||||
|
// ux = x * (width / (RES * width / height))
|
||||||
|
// ux = x * (height / RES)
|
||||||
|
//
|
||||||
|
// uy = y * (width / RES)
|
||||||
|
//
|
||||||
|
// e = (cw * ch) / (width * height)
|
||||||
|
// e = ((RES * (width / height)) * RES * height / width) / (width * height)
|
||||||
|
// e = ((RES * (1 / height)) * RES * (1 / width)
|
||||||
|
// e = RES^2 / (width * height)
|
||||||
|
|||||||
+50
-6
@@ -1,10 +1,7 @@
|
|||||||
use wasm_bindgen::{Clamped, prelude::*};
|
use wasm_bindgen::{Clamped, prelude::*};
|
||||||
use web_sys::ImageData;
|
use web_sys::ImageData;
|
||||||
|
|
||||||
use crate::{
|
use crate::render::{RESOLUTION, buffer::ImgBuffer, calc_resolution, rand::Rnd};
|
||||||
log,
|
|
||||||
render::{buffer::ImgBuffer, calc_resolution, rand::Rnd},
|
|
||||||
};
|
|
||||||
|
|
||||||
#[wasm_bindgen]
|
#[wasm_bindgen]
|
||||||
pub struct Renderer {
|
pub struct Renderer {
|
||||||
@@ -72,6 +69,10 @@ impl Renderer {
|
|||||||
.unwrap();
|
.unwrap();
|
||||||
self.ctx.put_image_data(&data, 0., 0.).unwrap();
|
self.ctx.put_image_data(&data, 0., 0.).unwrap();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn clear(&mut self) {
|
||||||
|
self.img.data = vec![0; (self.img.width() * self.img.height() * 4) as usize];
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Renderer {
|
impl Renderer {
|
||||||
@@ -82,6 +83,47 @@ impl Renderer {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Draw a rectangle centered at (cx, cy) with the given width and height.
|
||||||
|
pub fn rect_center_xywh(
|
||||||
|
&mut self,
|
||||||
|
cx: i32,
|
||||||
|
cy: i32,
|
||||||
|
width: i32,
|
||||||
|
height: i32,
|
||||||
|
color: (u8, u8, u8),
|
||||||
|
) {
|
||||||
|
self.rect_xyxy(
|
||||||
|
cx - width / 2,
|
||||||
|
cy - height / 2,
|
||||||
|
cx + width / 2,
|
||||||
|
cy + height / 2,
|
||||||
|
color,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Draw a rectangle at (x, y) with the given width and height.
|
||||||
|
pub fn rect_xywh(&mut self, x: i32, y: i32, width: i32, height: i32, color: (u8, u8, u8)) {
|
||||||
|
self.rect_xyxy(x, y, x + width, y + height, color);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Draw a rectangle at (x1, y1) with the given width and height.
|
||||||
|
pub fn rect_xyxy(&mut self, x1: i32, y1: i32, x2: i32, y2: i32, color: (u8, u8, u8)) {
|
||||||
|
let (leftx, topy) = self.undistort(x1 as f32, y1 as f32);
|
||||||
|
let (rightx, bottomy) = self.undistort(x2 as f32, y2 as f32);
|
||||||
|
|
||||||
|
let leftx = leftx.max(0f32);
|
||||||
|
let topy = topy.max(0f32);
|
||||||
|
let rightx = rightx.min(self.canvas_width as f32);
|
||||||
|
let bottomy = bottomy.min(self.canvas_height as f32);
|
||||||
|
|
||||||
|
for x in leftx as i32..rightx as i32 {
|
||||||
|
for y in topy as i32..bottomy as i32 {
|
||||||
|
self.img.set_pixel(x as u32, y as u32, color);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Calculate the square distance between two points on the screen, and convert to canvas coordinates for processing
|
||||||
pub fn screen_dist_sq(&self, x: f32, y: f32, rx: f32, ry: f32) -> f32 {
|
pub fn screen_dist_sq(&self, x: f32, y: f32, rx: f32, ry: f32) -> f32 {
|
||||||
(rx - x).powf(2.) * self.distortion_y + (ry - y).powf(2.) * self.distortion_x
|
(rx - x).powf(2.) * self.distortion_y + (ry - y).powf(2.) * self.distortion_x
|
||||||
}
|
}
|
||||||
@@ -99,8 +141,10 @@ impl Renderer {
|
|||||||
let rightx = rightx.min(self.canvas_width as f32);
|
let rightx = rightx.min(self.canvas_width as f32);
|
||||||
let bottomy = bottomy.min(self.canvas_height as f32);
|
let bottomy = bottomy.min(self.canvas_height as f32);
|
||||||
|
|
||||||
let e = (self.canvas_height as f32 / self.actual_height as f32)
|
// let e = (self.canvas_height as f32 / self.actual_height as f32)
|
||||||
* (self.canvas_width as f32 / self.actual_width as f32);
|
// * (self.canvas_width as f32 / self.actual_width as f32);
|
||||||
|
|
||||||
|
let e = RESOLUTION.pow(2) as f32 / (self.actual_width * self.actual_height) as f32;
|
||||||
|
|
||||||
let r2 = (radius).powf(2.) * e;
|
let r2 = (radius).powf(2.) * e;
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,25 @@
|
|||||||
|
use crate::{
|
||||||
|
log,
|
||||||
|
render::Renderer,
|
||||||
|
views::{Bounds, View},
|
||||||
|
};
|
||||||
|
|
||||||
|
pub struct ColorRectView {
|
||||||
|
color: (u8, u8, u8),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ColorRectView {
|
||||||
|
pub fn new(r: u8, g: u8, b: u8) -> Self {
|
||||||
|
Self { color: (r, g, b) }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl View for ColorRectView {
|
||||||
|
fn draw(&self, renderer: &mut Renderer, x: f32, y: f32, w: f32, h: f32) {
|
||||||
|
renderer.rect_xywh(x as i32, y as i32, w as i32, h as i32, self.color);
|
||||||
|
log!("Draw");
|
||||||
|
}
|
||||||
|
fn bounds(&self, _ph: f32, _pw: f32) -> (Bounds, Bounds) {
|
||||||
|
(Bounds::MatchParent, Bounds::Pixels(2200.))
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,28 @@
|
|||||||
|
use crate::render::Renderer;
|
||||||
|
|
||||||
|
mod color_rect_view;
|
||||||
|
mod vertical_layout;
|
||||||
|
|
||||||
|
use color_rect_view::ColorRectView;
|
||||||
|
use vertical_layout::VerticalLayout;
|
||||||
|
|
||||||
|
pub trait View {
|
||||||
|
fn draw(&self, renderer: &mut Renderer, x: f32, y: f32, w: f32, h: f32);
|
||||||
|
fn bounds(&self, pw: f32, ph: f32) -> (Bounds, Bounds);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub enum Bounds {
|
||||||
|
MatchParent,
|
||||||
|
Pixels(f32),
|
||||||
|
}
|
||||||
|
|
||||||
|
// pub trait ViewPosition: Drawable {
|
||||||
|
// // fn draw(&self)
|
||||||
|
// }
|
||||||
|
|
||||||
|
pub fn default_view() -> Box<dyn View> {
|
||||||
|
Box::new(VerticalLayout::new(vec![
|
||||||
|
Box::new(ColorRectView::new(12, 34, 56)),
|
||||||
|
Box::new(ColorRectView::new(20, 60, 80)),
|
||||||
|
]))
|
||||||
|
}
|
||||||
@@ -0,0 +1,59 @@
|
|||||||
|
use crate::views::{Bounds, View};
|
||||||
|
|
||||||
|
pub struct VerticalLayout {
|
||||||
|
pub views: Vec<Box<dyn View>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl VerticalLayout {
|
||||||
|
pub fn new(views: Vec<Box<dyn View>>) -> Self {
|
||||||
|
Self { views }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl View for VerticalLayout {
|
||||||
|
fn draw(&self, renderer: &mut crate::render::Renderer, x: f32, y: f32, w: f32, h: f32) {
|
||||||
|
let mut cur_y = y;
|
||||||
|
|
||||||
|
for view in &self.views {
|
||||||
|
let (vx, vy) = view.bounds(w, h);
|
||||||
|
|
||||||
|
let vx = match vx {
|
||||||
|
super::Bounds::MatchParent => w,
|
||||||
|
super::Bounds::Pixels(x) => x,
|
||||||
|
};
|
||||||
|
|
||||||
|
let vy = match vy {
|
||||||
|
super::Bounds::MatchParent => h,
|
||||||
|
super::Bounds::Pixels(x) => x,
|
||||||
|
};
|
||||||
|
|
||||||
|
view.draw(renderer, x, cur_y, w.min(vx), vy);
|
||||||
|
cur_y += vy;
|
||||||
|
if cur_y > h {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn bounds(&self, pw: f32, ph: f32) -> (Bounds, Bounds) {
|
||||||
|
let (mut maxx, mut totaly): (f32, f32) = (0., 0.);
|
||||||
|
for view in &self.views {
|
||||||
|
let (vx, vy) = view.bounds(pw, ph);
|
||||||
|
|
||||||
|
let vx = match vx {
|
||||||
|
super::Bounds::MatchParent => pw,
|
||||||
|
super::Bounds::Pixels(x) => x,
|
||||||
|
};
|
||||||
|
|
||||||
|
let vy = match vy {
|
||||||
|
super::Bounds::MatchParent => ph,
|
||||||
|
super::Bounds::Pixels(x) => x,
|
||||||
|
};
|
||||||
|
|
||||||
|
maxx = maxx.max(vx);
|
||||||
|
totaly += vy;
|
||||||
|
}
|
||||||
|
|
||||||
|
(Bounds::Pixels(maxx), Bounds::Pixels(totaly))
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user