Skip to content

Commit

Permalink
Resizing capability
Browse files Browse the repository at this point in the history
By copying and scaling the output from an invisible canvas, I can ensure that I can always scale the context without dealing with pipeline internals (e.g. dynamic frame buffers)
  • Loading branch information
BobDaGithubAccount committed Nov 15, 2024
1 parent ffbb904 commit 93d7115
Show file tree
Hide file tree
Showing 5 changed files with 220 additions and 72 deletions.
2 changes: 1 addition & 1 deletion lib/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ edition = "2021"
[dependencies]
wasm-bindgen = "0.2"
wasm-bindgen-futures = "0.4"
web-sys = { version = "0.3", features = ["Window"] }
web-sys = { version = "0.3", features = ["Window", "Document", "HtmlCanvasElement", "CanvasRenderingContext2d"] }
three-d = "0.17.0"
log = "0.4"
winit = "0.28"
Expand Down
113 changes: 113 additions & 0 deletions lib/src/main copy.bak
Original file line number Diff line number Diff line change
@@ -0,0 +1,113 @@
use three_d::{context, renderer::*, FrameInputGenerator, SurfaceSettings, WindowedContext};
use std::sync::Mutex;

#[cfg(target_arch = "wasm32")]
use wasm_bindgen::prelude::*;

lazy_static::lazy_static! {
static ref CAMERA_INSTANCE: Mutex<Option<Camera>> = Mutex::new(None);
}

#[cfg(target_arch = "wasm32")]
#[wasm_bindgen]
pub fn resize_callback(width: u32, height: u32) {
log::info!("Resized to {:?}", (width, height));

}

pub fn main() {
let event_loop = winit::event_loop::EventLoop::new();

#[cfg(not(target_arch = "wasm32"))]
let window_builder = winit::window::WindowBuilder::new()
.with_title("Full-Screen Window")
.with_inner_size(winit::dpi::LogicalSize::new(1920, 1080))
.with_decorations(false)
.with_maximized(true);

#[cfg(target_arch = "wasm32")]
let window_builder = {
use wasm_bindgen::JsCast;
use winit::platform::web::WindowBuilderExtWebSys;
winit::window::WindowBuilder::new()
.with_canvas(Some(
web_sys::window()
.unwrap()
.document()
.unwrap()
.get_element_by_id("canvas")
.unwrap()
.dyn_into::<web_sys::HtmlCanvasElement>()
.unwrap(),
))
.with_inner_size(winit::dpi::LogicalSize::new(1920, 1080))
.with_prevent_default(true)
};

let window = window_builder.build(&event_loop).unwrap();
let context = WindowedContext::from_winit_window(&window, SurfaceSettings::default()).unwrap();

let mut camera = Camera::new_perspective(
Viewport::new_at_origo(1, 1),
vec3(0.0, 2.0, 4.0), // Camera position
vec3(0.0, 0.0, 0.0), // Target position (where the camera is looking)
vec3(0.0, 1.0, 0.0), // Up direction
degrees(45.0), // Field of view
0.1, // Near clipping plane
100.0, // Far clipping plane
);

*CAMERA_INSTANCE.lock().unwrap() = Some(camera.clone());

let mut control = OrbitControl::new(*camera.target(), 1.0, 100.0);

let mut model = Gm::new(
Mesh::new(&context, &CpuMesh::cube()),
ColorMaterial {
color: Srgba::GREEN,
..Default::default()
},
);
model.set_animation(|time| Mat4::from_angle_y(radians(time * 0.0005)));

let mut frame_input_generator = FrameInputGenerator::from_winit_window(&window);
event_loop.run(move |event, _, control_flow| match event {
winit::event::Event::MainEventsCleared => {
window.request_redraw();
}
winit::event::Event::RedrawRequested(_) => {
let mut frame_input = frame_input_generator.generate(&context);

control.handle_events(&mut camera, &mut frame_input.events);
camera.set_viewport(frame_input.viewport);
model.animate(frame_input.accumulated_time as f32);
frame_input
.screen()
.clear(ClearState::color_and_depth(0.8, 0.8, 0.8, 1.0, 1.0))
.render(&camera, &model, &[]);

context.swap_buffers().unwrap();
control_flow.set_poll();
window.request_redraw();
}
winit::event::Event::WindowEvent { ref event, .. } => {
frame_input_generator.handle_winit_window_event(event);
match event {
winit::event::WindowEvent::Resized(physical_size) => {
log::info!("Resized to {:?}", physical_size);
context.resize(*physical_size);
camera.set_viewport(Viewport::new_at_origo(physical_size.width, physical_size.height));
}
winit::event::WindowEvent::ScaleFactorChanged { new_inner_size, .. } => {
context.resize(**new_inner_size);
camera.set_viewport(Viewport::new_at_origo(new_inner_size.width, new_inner_size.height));
}
winit::event::WindowEvent::CloseRequested => {
control_flow.set_exit();
}
_ => (),
}
}
_ => {}
});
}
83 changes: 53 additions & 30 deletions lib/src/main.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
use three_d::{context, renderer::*, FrameInputGenerator, SurfaceSettings, WindowedContext};
use std::sync::Mutex;
use winit::dpi::{PhysicalSize, LogicalSize};
use web_sys::{window, CanvasRenderingContext2d, Document, HtmlCanvasElement};

#[cfg(target_arch = "wasm32")]
use wasm_bindgen::prelude::*;
Expand All @@ -8,25 +10,42 @@ lazy_static::lazy_static! {
static ref CAMERA_INSTANCE: Mutex<Option<Camera>> = Mutex::new(None);
}

#[cfg(target_arch = "wasm32")]
#[wasm_bindgen]
pub fn resize_callback(width: u32, height: u32) {
log::info!("Resized to {:?}", (width, height));
if let Some(camera) = CAMERA_INSTANCE.lock().unwrap().as_mut() {
camera.set_viewport(Viewport::new_at_origo(width, height));
}
pub fn copy_to_visible_canvas() -> Result<(), JsValue> {
let document = window().unwrap().document().unwrap();

let resizable_container = document.get_element_by_id("resizable-container")
.unwrap();

let visible_canvas = document.get_element_by_id("visible-canvas")
.unwrap()
.dyn_into::<HtmlCanvasElement>()
.unwrap();

let visible_ctx = visible_canvas
.get_context("2d")?
.unwrap()
.dyn_into::<CanvasRenderingContext2d>()
.unwrap();

let hidden_canvas = document.get_element_by_id("canvas")
.unwrap()
.dyn_into::<HtmlCanvasElement>()
.unwrap();

let width = resizable_container.client_width();
let height = resizable_container.client_height();

visible_canvas.set_width(width as u32);
visible_canvas.set_height(height as u32);

visible_ctx.draw_image_with_html_canvas_element_and_dw_and_dh(&hidden_canvas, 0.0, 0.0, width as f64, height as f64)?;

Ok(())
}

pub fn main() {
let event_loop = winit::event_loop::EventLoop::new();

#[cfg(not(target_arch = "wasm32"))]
let window_builder = winit::window::WindowBuilder::new()
.with_title("Full-Screen Window")
.with_inner_size(winit::dpi::LogicalSize::new(1920, 1080))
.with_decorations(false)
.with_maximized(true);

#[cfg(target_arch = "wasm32")]
let window_builder = {
use wasm_bindgen::JsCast;
Expand All @@ -42,21 +61,21 @@ pub fn main() {
.dyn_into::<web_sys::HtmlCanvasElement>()
.unwrap(),
))
.with_inner_size(winit::dpi::LogicalSize::new(1920, 1080))
.with_inner_size(LogicalSize::new(1920, 1080))
.with_prevent_default(true)
};

let window = window_builder.build(&event_loop).unwrap();
let context = WindowedContext::from_winit_window(&window, SurfaceSettings::default()).unwrap();
let render_window = window_builder.build(&event_loop).unwrap();
let context = WindowedContext::from_winit_window(&render_window, SurfaceSettings::default()).unwrap();

let mut camera = Camera::new_perspective(
Viewport::new_at_origo(1, 1),
vec3(0.0, 2.0, 4.0), // Camera position
vec3(0.0, 0.0, 0.0), // Target position (where the camera is looking)
vec3(0.0, 1.0, 0.0), // Up direction
degrees(45.0), // Field of view
0.1, // Near clipping plane
100.0, // Far clipping plane
vec3(0.0, 2.0, 4.0),// Camera position
vec3(0.0, 0.0, 0.0),// Target position (where the camera is looking)
vec3(0.0, 1.0, 0.0),// Up direction
degrees(45.0),// Field of view
0.1,// Near clipping plane
100.0,// Far clipping plane
);

*CAMERA_INSTANCE.lock().unwrap() = Some(camera.clone());
Expand All @@ -72,27 +91,28 @@ pub fn main() {
);
model.set_animation(|time| Mat4::from_angle_y(radians(time * 0.0005)));

let mut frame_input_generator = FrameInputGenerator::from_winit_window(&window);
let mut frame_input_generator = FrameInputGenerator::from_winit_window(&render_window);
event_loop.run(move |event, _, control_flow| match event {
winit::event::Event::MainEventsCleared => {
window.request_redraw();
render_window.request_redraw();
}
winit::event::Event::RedrawRequested(_) => {
let mut frame_input = frame_input_generator.generate(&context);

copy_to_visible_canvas().unwrap();
control.handle_events(&mut camera, &mut frame_input.events);
camera.set_viewport(frame_input.viewport);
model.animate(frame_input.accumulated_time as f32);
frame_input
.screen()
.clear(ClearState::color_and_depth(0.8, 0.8, 0.8, 1.0, 1.0))
.render(&camera, &model, &[]);

context.swap_buffers().unwrap();
control_flow.set_poll();
window.request_redraw();
render_window.request_redraw();

}
winit::event::Event::WindowEvent { ref event, .. } => {

frame_input_generator.handle_winit_window_event(event);
match event {
winit::event::WindowEvent::Resized(physical_size) => {
Expand All @@ -101,15 +121,18 @@ pub fn main() {
camera.set_viewport(Viewport::new_at_origo(physical_size.width, physical_size.height));
}
winit::event::WindowEvent::ScaleFactorChanged { new_inner_size, .. } => {
log::info!("Scale factor changed to {:?}", new_inner_size);
context.resize(**new_inner_size);
camera.set_viewport(Viewport::new_at_origo(new_inner_size.width, new_inner_size.height));
}
winit::event::WindowEvent::CloseRequested => {
control_flow.set_exit();
}
_ => (),
_ =>
log::info!("Event: {:?}", event),
}
}
_ => {}
_ => {
}
});
}
26 changes: 20 additions & 6 deletions src/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -9,16 +9,30 @@
margin: 0;
overflow: hidden;
}
#resizable-container {
width: 50vw;
height: 50vh;
resize: both;
overflow: auto;
display: flex;
}
#canvas {
display: block;
width: 100vw;
height: 100vh;
flex: 1;
width: 100%;
height: 100%;
visibility: hidden;
}
#visible-canvas {
width: 100%;
height: 100%;
}
</style>
</head>
<body>
<div id="resizable-container">
<canvas id="visible-canvas"></canvas>
</div>
<canvas id="canvas"></canvas>
<script type="module" src="index.js">
</script>
<script type="module" src="index.js"></script>
</body>
</html>
</html>
68 changes: 33 additions & 35 deletions src/index.js
Original file line number Diff line number Diff line change
@@ -1,44 +1,42 @@
import init, * as wasm_bindgen from './src.js';

function jsInit() {
console.log("Wasm module initialized");

if (typeof window.resize_callback === 'undefined' && typeof wasm_bindgen.resize_callback !== 'undefined') {
console.log("Setting resize callback");
window.resize_callback = wasm_bindgen.resize_callback;
}

const canvas = document.getElementById('canvas');

function resizeCanvas() {
const canvas = document.getElementById('canvas');
const width = window.innerWidth;
const height = window.innerHeight;
canvas.width = width;
canvas.height = height;

if (typeof window.resize_callback === 'function') {
window.resize_callback(width, height);
}
}

window.addEventListener('resize', resizeCanvas);
window.addEventListener('load', resizeCanvas);
}
init().then(() => {
jsInit();
console.log("Wasm module initialized without standard control flow error?");
}).catch(err => {
if (err.message.includes("Using exceptions for control flow")) {
console.warn("Ignoring expected Wasm initialization exception and proceeding.");
try {
jsInit();
} catch (err) {
console.error("Error in continuing initialisation:", err);
throw err;
}
console.warn("Ignoring expected Wasm initialisation exception and proceeding.");
} else {
console.error("Error initializing wasm module:", err);
throw err;
}
});
console.log("Wasm module initialization call made");
}).finally(() => {

console.log("Wasm module initialised!");

// if (typeof window.resize_callback === 'undefined' && typeof wasm_bindgen.resize_callback !== 'undefined') {
// console.log("Setting resize callback");
// window.resize_callback = wasm_bindgen.resize_callback;
// }
// const resizableContainer = document.getElementById('resizable-container');
// function resizeCanvas() {
// const canvas = document.getElementById('canvas');
// const width = resizableContainer.clientWidth;
// const height = resizableContainer.clientHeight;
// if (typeof window.resize_callback === 'function') {
// window.resize_callback(width, height);
// }
// canvas.width = width;
// canvas.height = height;
// }

// if (resizableContainer) {
// const resizeObserver = new ResizeObserver(() => {
// resizeCanvas();
// });

// resizeObserver.observe(resizableContainer);
// }

// window.addEventListener('load', resizeCanvas);

});

0 comments on commit 93d7115

Please sign in to comment.