El repo publico se habia quedado en julio: el README anunciaba vello 0.7 + wgpu 27 (dos bumps atras) y faltaban los crates del ultimo mes. - refresco con scripts/actualizar-standalone.py --llimphi (cargo check OK) - llegan llimphi-cpu, llimphi-hybrid, llimphi-glifos y llimphi-wire-escena: los cuatro caminos a pixeles con un solo compositor - MANUAL.md / SDD.md / LEEME.md sincronizados con el monorepo - README: versiones al dia, install por crates.io (cargo add llimphi), seccion "beyond the 2D widget kit" y el indice de crates que apuntaba al propio README ahora apunta a MANUAL.md §19
102 lines
3.9 KiB
Rust
102 lines
3.9 KiB
Rust
//! El `clear_screen` del navegador: pinta un `<canvas>` de gris plomo con
|
||
//! [`CanvasSurface`], el HAL de wasm32.
|
||
//!
|
||
//! Es el gemelo web de `clear_screen.rs` y cumple la misma función que aquel:
|
||
//! ser el consumidor mínimo del HAL, para que un cambio de API rompa acá y no
|
||
//! meses después en una app. Ejercita el camino entero —canvas del DOM →
|
||
//! `Hal::for_canvas` → `resize_to_css` → `acquire` → render pass → `present`—
|
||
//! sin depender del event loop de `llimphi-ui`, que todavía no cruzó a web.
|
||
//!
|
||
//! Verificación (no linkea, no necesita navegador ni wasm-bindgen-cli):
|
||
//!
|
||
//! ```sh
|
||
//! cargo check -p llimphi-hal --target wasm32-unknown-unknown --examples
|
||
//! ```
|
||
//!
|
||
//! Para correrlo de verdad hace falta empaquetarlo con `wasm-bindgen-cli` y
|
||
//! servir un HTML con un `<canvas id="llimphi">`. No hay script de eso todavía
|
||
//! — ver `PORTING.md` §wasm32.
|
||
|
||
// En cualquier target nativo este example no aplica: la `CanvasSurface` sólo
|
||
// existe en wasm32. Un `main` vacío deja que `--examples` lo compile en el
|
||
// smoke test del workspace sin ensuciar la salida.
|
||
#[cfg(not(target_arch = "wasm32"))]
|
||
fn main() {
|
||
eprintln!(
|
||
"llimphi · canvas_clear — este example es sólo para wasm32-unknown-unknown \
|
||
(usa CanvasSurface). En escritorio el equivalente es `clear_screen`."
|
||
);
|
||
}
|
||
|
||
#[cfg(target_arch = "wasm32")]
|
||
fn main() {
|
||
wasm_bindgen_futures::spawn_local(async {
|
||
if let Err(e) = correr().await {
|
||
web_sys::console::error_1(&format!("llimphi · canvas_clear: {e}").into());
|
||
}
|
||
});
|
||
}
|
||
|
||
#[cfg(target_arch = "wasm32")]
|
||
const LEAD_GRAY: llimphi_hal::wgpu::Color = llimphi_hal::wgpu::Color {
|
||
r: 0.235,
|
||
g: 0.239,
|
||
b: 0.247,
|
||
a: 1.0,
|
||
};
|
||
|
||
#[cfg(target_arch = "wasm32")]
|
||
async fn correr() -> Result<(), String> {
|
||
use llimphi_hal::{wgpu, Hal, Surface};
|
||
use wasm_bindgen::JsCast;
|
||
|
||
let canvas: web_sys::HtmlCanvasElement = web_sys::window()
|
||
.ok_or("sin `window`")?
|
||
.document()
|
||
.ok_or("sin `document`")?
|
||
.get_element_by_id("llimphi")
|
||
.ok_or("no hay ningún elemento con id=\"llimphi\"")?
|
||
.dyn_into()
|
||
.map_err(|_| "el elemento #llimphi no es un <canvas>")?;
|
||
|
||
// Surface-first, igual que en Android: el adapter se pide contra ESTA
|
||
// surface. `for_canvas` es async porque en el main thread del navegador no
|
||
// se puede bloquear.
|
||
let (hal, mut surface) = Hal::for_canvas(canvas).await.map_err(|e| e.to_string())?;
|
||
|
||
// El backing store del canvas por `devicePixelRatio`. Sin esto el canvas se
|
||
// ve borroso en HiDPI (el navegador escala un buffer chico).
|
||
let (w, h) = surface.resize_to_css();
|
||
web_sys::console::log_1(&format!("llimphi · canvas_clear — surface {w}×{h} px físicos").into());
|
||
|
||
let frame = surface.acquire().map_err(|e| e.to_string())?;
|
||
let mut encoder = hal
|
||
.device
|
||
.create_command_encoder(&wgpu::CommandEncoderDescriptor {
|
||
label: Some("canvas_clear-encoder"),
|
||
});
|
||
{
|
||
let _pass = encoder.begin_render_pass(&wgpu::RenderPassDescriptor {
|
||
label: Some("canvas_clear-pass"),
|
||
color_attachments: &[Some(wgpu::RenderPassColorAttachment {
|
||
// La intermedia, no el swapchain: es el mismo contrato que en
|
||
// escritorio (vello pinta acá y `present` blittea).
|
||
view: frame.view(),
|
||
resolve_target: None,
|
||
depth_slice: None,
|
||
ops: wgpu::Operations {
|
||
load: wgpu::LoadOp::Clear(LEAD_GRAY),
|
||
store: wgpu::StoreOp::Store,
|
||
},
|
||
})],
|
||
depth_stencil_attachment: None,
|
||
timestamp_writes: None,
|
||
occlusion_query_set: None,
|
||
multiview_mask: None,
|
||
});
|
||
}
|
||
hal.queue.submit(std::iter::once(encoder.finish()));
|
||
surface.present(frame, &hal);
|
||
Ok(())
|
||
}
|