use bevy::asset::AssetId;
use bevy::prelude::*;
use bevy::render::render_resource::AsBindGroup;
use bevy::shader::ShaderRef;
use bevy::window::PrimaryWindow;
use bevy_cef::prelude::*;
fn main() {
App::new()
.add_plugins((
DefaultPlugins,
CefPlugin::default(),
UiMaterialPlugin::<TintedWebviewMaterial>::default(),
WebviewTargetUiMaterialPlugin::<TintedWebviewMaterial>::default(),
))
.add_systems(Startup, (spawn_camera, spawn_headless_webview))
.add_systems(Update, sync_webview_size_to_window)
.run();
}
fn spawn_camera(mut commands: Commands) {
commands.spawn(Camera2d);
}
fn spawn_headless_webview(
mut commands: Commands,
mut images: ResMut<Assets<Image>>,
mut materials: ResMut<Assets<TintedWebviewMaterial>>,
) {
let target = images.add(Image::default());
commands.spawn((
WebviewSource::new("https://github.com/not-elm/bevy_cef"),
WebviewTextureTarget(target.clone()),
));
commands.spawn((
Node {
width: Val::Percent(100.0),
height: Val::Percent(100.0),
..default()
},
MaterialNode(materials.add(TintedWebviewMaterial {
webview: Some(target),
})),
));
}
fn sync_webview_size_to_window(
window: Single<&Window, With<PrimaryWindow>>,
mut webviews: Query<&mut WebviewSize, With<WebviewTextureTarget>>,
) {
let size = Vec2::new(window.width(), window.height());
for mut webview_size in webviews.iter_mut() {
if webview_size.0 != size {
webview_size.0 = size;
}
}
}
#[derive(Asset, TypePath, AsBindGroup, Debug, Clone, Default)]
struct TintedWebviewMaterial {
#[texture(0)]
#[sampler(1)]
webview: Option<Handle<Image>>,
}
impl UiMaterial for TintedWebviewMaterial {
fn fragment_shader() -> ShaderRef {
"shaders/headless_texture.wgsl".into()
}
}
impl WebviewTextureSlot for TintedWebviewMaterial {
fn webview_targets(&self) -> impl Iterator<Item = AssetId<Image>> {
self.webview.iter().map(Handle::id)
}
}