feat: add alpha hit-test to WebviewPointer

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
not-elm
2026-02-19 23:18:31 +09:00
parent 255dc27e1a
commit 19f7628a53

View File

@@ -1,3 +1,4 @@
use crate::common::WebviewSurface;
use crate::prelude::{WebviewSize, WebviewSource}; use crate::prelude::{WebviewSize, WebviewSource};
use crate::system_param::mesh_aabb::MeshAabb; use crate::system_param::mesh_aabb::MeshAabb;
use bevy::ecs::system::SystemParam; use bevy::ecs::system::SystemParam;
@@ -15,6 +16,8 @@ pub struct WebviewPointer<'w, 's, C: Component = Camera3d> {
(With<WebviewSource>, Without<Camera>), (With<WebviewSource>, Without<Camera>),
>, >,
parents: Query<'w, 's, (Option<&'static ChildOf>, Has<WebviewSource>)>, parents: Query<'w, 's, (Option<&'static ChildOf>, Has<WebviewSource>)>,
surfaces: Query<'w, 's, &'static WebviewSurface>,
images: Res<'w, Assets<Image>>,
} }
impl<C: Component> WebviewPointer<'_, '_, C> { impl<C: Component> WebviewPointer<'_, '_, C> {
@@ -31,7 +34,7 @@ impl<C: Component> WebviewPointer<'_, '_, C> {
let (min, max) = self.aabb.calculate_local(webview); let (min, max) = self.aabb.calculate_local(webview);
let aabb_size = Vec2::new(max.x - min.x, max.y - min.y); let aabb_size = Vec2::new(max.x - min.x, max.y - min.y);
let (webview_gtf, webview_size) = self.webviews.get(webview).ok()?; let (webview_gtf, webview_size) = self.webviews.get(webview).ok()?;
self.cameras.iter().find_map(|(camera, camera_gtf)| { let pos = self.cameras.iter().find_map(|(camera, camera_gtf)| {
pointer_to_webview_uv( pointer_to_webview_uv(
viewport_pos, viewport_pos,
camera, camera,
@@ -40,7 +43,32 @@ impl<C: Component> WebviewPointer<'_, '_, C> {
aabb_size, aabb_size,
webview_size.0, webview_size.0,
) )
}) })?;
if self.is_transparent_at(webview, pos) {
return None;
}
Some(pos)
}
fn is_transparent_at(&self, webview: Entity, pos: Vec2) -> bool {
let Ok(surface) = self.surfaces.get(webview) else {
return false;
};
let Some(image) = self.images.get(surface.0.id()) else {
return false;
};
let width = image.width();
let height = image.height();
if width == 0 || height == 0 {
return false;
}
let x = (pos.x.floor() as u32).min(width - 1);
let y = (pos.y.floor() as u32).min(height - 1);
let offset = ((y * width + x) * 4 + 3) as usize;
let Some(data) = image.data.as_ref() else {
return false;
};
data.len() > offset && data[offset] == 0
} }
} }