Implement async node graph execution

This commit is contained in:
Dennis Kobert 2025-03-02 00:28:45 +01:00
parent 8e0607c9af
commit cfc95a3e14
No known key found for this signature in database
GPG key ID: 5A4358CB9530F933
4 changed files with 92 additions and 20 deletions

View file

@ -9,7 +9,9 @@ pub struct OverlaysMessageData<'a> {
#[derive(Debug, Clone, Default)]
pub struct OverlaysMessageHandler {
pub overlay_providers: HashSet<OverlayProvider>,
#[cfg(target_arch = "wasm32")]
canvas: Option<web_sys::HtmlCanvasElement>,
#[cfg(target_arch = "wasm32")]
context: Option<web_sys::CanvasRenderingContext2d>,
device_pixel_ratio: Option<f64>,
}
@ -65,10 +67,7 @@ impl MessageHandler<OverlaysMessage, OverlaysMessageData<'_>> for OverlaysMessag
}
#[cfg(not(target_arch = "wasm32"))]
OverlaysMessage::Draw => {
warn!(
"Cannot render overlays on non-Wasm targets.\n{responses:?} {overlays_visible} {ipp:?} {:?} {:?}",
self.canvas, self.context
);
warn!("Cannot render overlays on non-Wasm targets.\n{responses:?} {overlays_visible} {ipp:?}",);
}
OverlaysMessage::SetDevicePixelRatio { ratio } => {
self.device_pixel_ratio = Some(ratio);

View file

@ -1,3 +1,4 @@
#[cfg(target_arch = "wasm32")]
use super::utility_functions::overlay_canvas_context;
use crate::consts::{
COLOR_OVERLAY_BLUE, COLOR_OVERLAY_GREEN, COLOR_OVERLAY_RED, COLOR_OVERLAY_WHITE, COLOR_OVERLAY_YELLOW, COMPASS_ROSE_ARROW_SIZE, COMPASS_ROSE_HOVER_RING_DIAMETER, COMPASS_ROSE_MAIN_RING_DIAMETER,
@ -21,12 +22,79 @@ pub fn empty_provider() -> OverlayProvider {
|_| Message::NoOp
}
#[derive(PartialEq, Clone, Debug, serde::Serialize, serde::Deserialize, specta::Type)]
pub struct MockOverlay;
impl MockOverlay {
fn begin_path(&self) {}
fn move_to(&self, _x: f64, _y: f64) {}
fn line_to(&self, _x: f64, _y: f64) {}
fn close_path(&self) {}
fn set_fill_style_str(&self, _color_fill: &str) {}
fn set_stroke_style_str(&self, _color_stroke: &str) {}
fn fill(&self) {}
fn stroke(&self) {}
fn set_line_dash(&self, _new: &JsValue) -> Result<JsValue, JsValue> {
Err(JsValue::from("test".to_owned()))
}
fn set_line_dash_offset(&self, _arg: f64) {}
fn arc(&self, _x: f64, _y: f64, _manipulator_group_marker_size: f64, _arg: f64, _tau: f64) -> Result<JsValue, JsValue> {
Err(JsValue::from("test".to_owned()))
}
fn set_transform(&self, _a: f64, _b: f64, _c: f64, _d: f64, _e: f64, _f: f64) -> Result<JsValue, JsValue> {
Err(JsValue::from("test".to_owned()))
}
fn reset_transform(&self) -> Result<JsValue, JsValue> {
Err(JsValue::from("test".to_owned()))
}
fn rect(&self, _x: f64, _y: f64, _size_1: f64, _size_22: f64) {}
fn line_width(&self) -> f64 {
0.
}
fn set_line_width(&self, _hover_ring_stroke_width: f64) {}
fn set_line_cap(&self, _arg: &str) {}
fn quadratic_curve_to(&self, _x_1: f64, _y_1: f64, _x_2: f64, _y_2: f64) {}
fn bezier_curve_to(&self, _x_1: f64, _y_1: f64, _x_2: f64, _y_2: f64, _x_3: f64, _y_3: f64) {}
fn measure_text(&self, _text: &str) -> Result<web_sys::TextMetrics, JsValue> {
Err(JsValue::from("test".to_owned()))
}
fn fill_rect(&self, _padding_1: f64, _padding_2: f64, _padding_3: f64, _padding_4: f64) {}
fn set_font(&self, _arg: &str) {}
fn fill_text(&self, _text: &str, _arg_1: f64, _arg_2: f64) -> Result<JsValue, JsValue> {
Err(JsValue::from("test".to_owned()))
}
}
#[derive(PartialEq, Clone, Debug, serde::Serialize, serde::Deserialize, specta::Type)]
pub struct OverlayContext {
// Serde functionality isn't used but is required by the message system macros
#[serde(skip, default = "overlay_canvas_context")]
#[specta(skip)]
#[cfg(target_arch = "wasm32")]
pub render_context: web_sys::CanvasRenderingContext2d,
#[cfg(not(target_arch = "wasm32"))]
pub render_context: MockOverlay,
pub size: DVec2,
// The device pixel ratio is a property provided by the browser window and is the CSS pixel size divided by the physical monitor's pixel size.
// It allows better pixel density of visualizations on high-DPI displays where the OS display scaling is not 100%, or where the browser is zoomed.

View file

@ -27,7 +27,7 @@ serde_json = { workspace = true }
serde = { workspace = true }
axum = { workspace = true }
chrono = { workspace = true }
tokio = { workspace = true, features = ["macros", "rt-multi-thread"] }
tokio = { workspace = true, features = ["macros", "rt"] }
ron = { workspace = true }
log = { workspace = true }
fern = { workspace = true }

View file

@ -11,14 +11,12 @@ use axum::routing::get;
use axum::Router;
use fern::colors::{Color, ColoredLevelConfig};
// use http::{Response, StatusCode};
use std::cell::RefCell;
use std::sync::Mutex;
// use std::collections::HashMap;
// use std::sync::Arc;
// use std::sync::Mutex;
thread_local! {
static EDITOR: RefCell<Option<Editor>> = const { RefCell::new(None) };
}
static EDITOR: Mutex<Option<Editor>> = const { Mutex::new(None) };
// async fn respond_to(id: Path<String>) -> impl IntoResponse {
// let builder = Response::builder().header("Access-Control-Allow-Origin", "*").status(StatusCode::OK);
@ -54,9 +52,21 @@ async fn main() {
.apply()
.unwrap();
std::thread::spawn(|| {
let set = tokio::task::LocalSet::new();
loop {
set.spawn_local(graphite_editor::node_graph_executor::run_node_graph());
std::thread::sleep(std::time::Duration::from_millis(16))
}
});
// *(IMAGES.lock().unwrap()) = Some(HashMap::new());
graphite_editor::application::set_uuid_seed(0);
EDITOR.with(|editor| editor.borrow_mut().replace(Editor::new()));
let mut editor_lock = EDITOR.lock().unwrap();
*editor_lock = Some(Editor::new());
drop(editor_lock);
let app = Router::new().route("/", get(|| async { "Hello, World!" }))/*.route("/image/:id", get(respond_to))*/;
// run it with hyper on localhost:3000
@ -83,13 +93,11 @@ fn set_random_seed(seed: f64) {
}
#[tauri::command]
async fn poll_node_graph() -> String {
return "[]".into();
// return "[]".into();
let mut responses = VecDeque::new();
let responses = EDITOR.with(|editor| {
let mut editor = editor.borrow_mut();
editor.as_mut().unwrap().poll_node_graph_evaluation(&mut responses)
});
let mut editor_lock = EDITOR.lock().unwrap();
editor_lock.as_mut().unwrap().poll_node_graph_evaluation(&mut responses);
for response in &responses {
let serialized = ron::to_string(&response.clone()).unwrap();
@ -97,7 +105,6 @@ async fn poll_node_graph() -> String {
log::error!("Error deserializing message: {error}");
}
}
println!("handling messages");
// Process any `FrontendMessage` responses resulting from the backend processing the dispatched message
let result: Vec<_> = responses.into_iter().collect();
@ -110,10 +117,8 @@ fn handle_message(message: String) -> String {
let Ok(message) = ron::from_str::<graphite_editor::messages::message::Message>(&message) else {
panic!("Error parsing message: {message}")
};
let responses = EDITOR.with(|editor| {
let mut editor = editor.borrow_mut();
editor.as_mut().unwrap().handle_message(message)
});
let mut editor_lock = EDITOR.lock().unwrap();
let responses = editor_lock.as_mut().unwrap().handle_message(message);
for response in &responses {
let serialized = ron::to_string(&response.clone()).unwrap();