drain all accumulated events in the channel per frame (#15)
This commit is contained in:
@@ -1,4 +1,6 @@
|
|||||||
use core::fmt;
|
use core::fmt;
|
||||||
|
use std::sync::mpsc::TryRecvError;
|
||||||
|
use std::cell::BorrowMutError;
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub enum WindowEvent {
|
pub enum WindowEvent {
|
||||||
@@ -111,3 +113,37 @@ impl KeyboardMessage {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub enum DrainEventError {
|
||||||
|
BorrowError(BorrowMutError),
|
||||||
|
ChannelDisconnected,
|
||||||
|
ChannelEmpty,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl fmt::Display for DrainEventError {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
|
match self {
|
||||||
|
DrainEventError::BorrowError(err) => write!(f, "Failed to borrow renderer: {}", err),
|
||||||
|
DrainEventError::ChannelDisconnected => write!(f, "Event channel disconnected"),
|
||||||
|
DrainEventError::ChannelEmpty => write!(f, "Event channel empty"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl std::error::Error for DrainEventError {}
|
||||||
|
|
||||||
|
impl From<TryRecvError> for DrainEventError {
|
||||||
|
fn from(err: TryRecvError) -> Self {
|
||||||
|
match err {
|
||||||
|
TryRecvError::Empty => DrainEventError::ChannelEmpty,
|
||||||
|
TryRecvError::Disconnected => DrainEventError::ChannelDisconnected,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<BorrowMutError> for DrainEventError {
|
||||||
|
fn from(err: BorrowMutError) -> Self {
|
||||||
|
DrainEventError::BorrowError(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,4 +1,10 @@
|
|||||||
use std::{cell::RefCell, collections::HashMap, marker::PhantomData, rc::Rc, sync::mpsc::Receiver};
|
use std::{
|
||||||
|
cell::RefCell,
|
||||||
|
collections::HashMap,
|
||||||
|
marker::PhantomData,
|
||||||
|
rc::Rc,
|
||||||
|
sync::mpsc::Receiver,
|
||||||
|
};
|
||||||
|
|
||||||
use futures::channel::oneshot;
|
use futures::channel::oneshot;
|
||||||
use log::info;
|
use log::info;
|
||||||
@@ -9,7 +15,7 @@ use web_sys::{DedicatedWorkerGlobalScope, File, MessageEvent};
|
|||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
gltf::{load_gltf_model, ImportError, ModelBounds},
|
gltf::{load_gltf_model, ImportError, ModelBounds},
|
||||||
message::{MouseMessage, ResizeMessage, WindowEvent},
|
message::{DrainEventError, MouseMessage, ResizeMessage, WindowEvent},
|
||||||
renderer::scene::Scene,
|
renderer::scene::Scene,
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -561,6 +567,8 @@ impl<T: Scene + 'static> Renderer<T> {
|
|||||||
}
|
}
|
||||||
WindowEvent::PointerClick(msg) => {
|
WindowEvent::PointerClick(msg) => {
|
||||||
{
|
{
|
||||||
|
log::info!("click start");
|
||||||
|
|
||||||
let mut r = renderer.borrow_mut();
|
let mut r = renderer.borrow_mut();
|
||||||
let x = (msg.offset_x * msg.scale_factor) as f32;
|
let x = (msg.offset_x * msg.scale_factor) as f32;
|
||||||
let y = (msg.offset_y * msg.scale_factor) as f32;
|
let y = (msg.offset_y * msg.scale_factor) as f32;
|
||||||
@@ -603,16 +611,32 @@ impl<T: Scene + 'static> Renderer<T> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn drain_events(renderer: &Rc<RefCell<Self>>) -> Result<(), DrainEventError> {
|
||||||
|
loop {
|
||||||
|
let event = renderer.try_borrow_mut()?
|
||||||
|
.events_chan.try_recv()?;
|
||||||
|
|
||||||
|
let renderer_clone = renderer.clone();
|
||||||
|
spawn_local(async move {
|
||||||
|
Self::handle_event(renderer_clone, event).await;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub fn run_render_loop(renderer: Rc<RefCell<Renderer<T>>>) {
|
pub fn run_render_loop(renderer: Rc<RefCell<Renderer<T>>>) {
|
||||||
let render_frame: Closure<dyn FnMut(f32)> = Closure::new(move |time: f32| {
|
let render_frame: Closure<dyn FnMut(f32)> = Closure::new(move |time: f32| {
|
||||||
{
|
{
|
||||||
if let Ok(r) = renderer.try_borrow_mut() {
|
if let Err(e) = Self::drain_events(&renderer) {
|
||||||
let event = r.events_chan.try_recv();
|
match e {
|
||||||
if let Ok(event) = event {
|
DrainEventError::ChannelEmpty => {
|
||||||
let renderer_clone = renderer.clone();
|
// Normal condition, no error needed
|
||||||
spawn_local(async move {
|
}
|
||||||
Self::handle_event(renderer_clone, event).await;
|
DrainEventError::ChannelDisconnected => {
|
||||||
});
|
log::warn!("Event channel disconnected; stopping event polling");
|
||||||
|
}
|
||||||
|
DrainEventError::BorrowError(_) => {
|
||||||
|
log::error!("Failed to borrow renderer: {}", e);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -672,10 +696,7 @@ impl<T: Scene + 'static> Renderer<T> {
|
|||||||
pub async fn load_assets_async(renderer: Rc<RefCell<Renderer<T>>>) -> Result<(), ImportError> {
|
pub async fn load_assets_async(renderer: Rc<RefCell<Renderer<T>>>) -> Result<(), ImportError> {
|
||||||
let (device, surface_format) = {
|
let (device, surface_format) = {
|
||||||
let r = renderer.borrow();
|
let r = renderer.borrow();
|
||||||
(
|
(r.context.device.clone(), r.context.surface_config.format)
|
||||||
r.context.device.clone(),
|
|
||||||
r.context.surface_config.format,
|
|
||||||
)
|
|
||||||
};
|
};
|
||||||
|
|
||||||
let mut meshes = Vec::new();
|
let mut meshes = Vec::new();
|
||||||
@@ -697,7 +718,7 @@ impl<T: Scene + 'static> Renderer<T> {
|
|||||||
{
|
{
|
||||||
let mut r = renderer.borrow_mut();
|
let mut r = renderer.borrow_mut();
|
||||||
r.resources = original_resources;
|
r.resources = original_resources;
|
||||||
|
|
||||||
for mesh in meshes {
|
for mesh in meshes {
|
||||||
r.scene.add_mesh(mesh);
|
r.scene.add_mesh(mesh);
|
||||||
}
|
}
|
||||||
@@ -734,7 +755,9 @@ impl<T: Scene + 'static> Renderer<T> {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn show_file_picker_and_load(renderer: Rc<RefCell<Renderer<T>>>) -> Result<(), ImportError> {
|
async fn show_file_picker_and_load(
|
||||||
|
renderer: Rc<RefCell<Renderer<T>>>,
|
||||||
|
) -> Result<(), ImportError> {
|
||||||
// For now, we'll just call load_assets_async which loads the default model
|
// For now, we'll just call load_assets_async which loads the default model
|
||||||
// In a full implementation, we'd modify load_gltf_model to accept the file data
|
// In a full implementation, we'd modify load_gltf_model to accept the file data
|
||||||
Self::load_assets_async(renderer).await
|
Self::load_assets_async(renderer).await
|
||||||
|
|||||||
Reference in New Issue
Block a user