Files
dioxus/examples/10-integrations/bevy/src/bevy_renderer.rs
T
Nico Burns 9359446017 Upgrade to Blitz v0.2.0 (#4731)
* Bump Rust CI version to 1.88

Signed-off-by: Nico Burns <nico@nicoburns.com>

* Upgrade to Blitz v0.2.0

Signed-off-by: Nico Burns <nico@nicoburns.com>

* Native: enable clipboard and file_dialog support by default

* Fix clippy errors

Signed-off-by: Nico Burns <nico@nicoburns.com>

* See if cargo update magically fixes build

Signed-off-by: Nico Burns <nico@nicoburns.com>

* Fix compile err

Signed-off-by: Nico Burns <nico@nicoburns.com>

* Remove unused wasm-opt dep

* Fix wgpu_child_window example

Signed-off-by: Nico Burns <nico@nicoburns.com>

* Update blitz-shell

Signed-off-by: Nico Burns <nico@nicoburns.com>

* cargo fmt

Signed-off-by: Nico Burns <nico@nicoburns.com>

* Allow clippy lint

Signed-off-by: Nico Burns <nico@nicoburns.com>

* CI: Bump pinned nightly version

Signed-off-by: Nico Burns <nico@nicoburns.com>

* Allow clippy lint in whole module

Signed-off-by: Nico Burns <nico@nicoburns.com>

* Fix more clippy lints

Signed-off-by: Nico Burns <nico@nicoburns.com>

* Use Rust 1.90 for clippy

Signed-off-by: Nico Burns <nico@nicoburns.com>

* cargo update --ignore-rust-version

* revert cargo updates

Signed-off-by: Nico Burns <nico@nicoburns.com>

* Revert another silly clippy lint

---------

Signed-off-by: Nico Burns <nico@nicoburns.com>
2025-10-07 11:18:59 -07:00

164 lines
5.9 KiB
Rust

use crate::bevy_scene_plugin::BevyScenePlugin;
use bevy::{
camera::{ManualTextureViewHandle, RenderTarget},
prelude::*,
render::{
render_resource::TextureFormat,
renderer::{
RenderAdapter, RenderAdapterInfo, RenderDevice, RenderInstance, RenderQueue,
WgpuWrapper,
},
settings::{RenderCreation, RenderResources},
texture::ManualTextureView,
RenderPlugin,
},
};
use dioxus_native::{CustomPaintCtx, DeviceHandle, TextureHandle};
use std::sync::Arc;
#[derive(Resource, Default)]
pub struct UIData {
pub color: [f32; 3],
}
pub struct BevyRenderer {
app: App,
wgpu_device: wgpu::Device,
last_texture_size: (u32, u32),
texture_handle: Option<TextureHandle>,
manual_texture_view_handle: Option<ManualTextureViewHandle>,
}
impl BevyRenderer {
pub fn new(device_handle: &DeviceHandle) -> Self {
// Create a headless Bevy App.
let mut app = App::new();
app.add_plugins(
DefaultPlugins
.set(RenderPlugin {
// Reuse the render resources from the Dioxus native renderer.
render_creation: RenderCreation::Manual(RenderResources(
RenderDevice::new(WgpuWrapper::new(device_handle.device.clone())),
RenderQueue(Arc::new(WgpuWrapper::new(device_handle.queue.clone()))),
RenderAdapterInfo(WgpuWrapper::new(device_handle.adapter.get_info())),
RenderAdapter(Arc::new(WgpuWrapper::new(device_handle.adapter.clone()))),
RenderInstance(Arc::new(WgpuWrapper::new(device_handle.instance.clone()))),
)),
synchronous_pipeline_compilation: true,
..default()
})
.set(WindowPlugin {
primary_window: None,
exit_condition: bevy::window::ExitCondition::DontExit,
close_when_requested: false,
..Default::default()
})
.disable::<bevy::winit::WinitPlugin>(),
);
// Setup the rendering to texture.
app.insert_resource(ManualTextureViews::default());
// Add data from the UI.
app.insert_resource(UIData::default());
// Add the Bevy scene.
app.add_plugins(BevyScenePlugin {});
// Initialize the app to set up the render world properly.
app.finish();
app.cleanup();
Self {
app,
wgpu_device: device_handle.device.clone(),
last_texture_size: (0, 0),
texture_handle: None,
manual_texture_view_handle: None,
}
}
pub fn render(
&mut self,
ctx: CustomPaintCtx<'_>,
color: [f32; 3],
width: u32,
height: u32,
_start_time: &std::time::Instant,
) -> Option<TextureHandle> {
// Update the UI data.
if let Some(mut ui) = self.app.world_mut().get_resource_mut::<UIData>() {
ui.color = color;
}
// Init self.texture_handle if None or if width/height changed.
self.init_texture(ctx, width, height);
// Run one frame of the Bevy app to render the 3D scene.
self.app.update();
self.texture_handle.clone()
}
fn init_texture(&mut self, mut ctx: CustomPaintCtx<'_>, width: u32, height: u32) {
// Reuse self.texture_handle if already initialized to the correct size.
let current_size = (width, height);
if self.texture_handle.is_some() && self.last_texture_size == current_size {
return;
}
let world = self.app.world_mut();
// Skip if no camera.
if world.query::<&Camera>().single(world).is_err() {
return;
}
if let Some(mut manual_texture_views) = world.get_resource_mut::<ManualTextureViews>() {
// Clean previous texture if any.
if self.texture_handle.is_some() {
ctx.unregister_texture(self.texture_handle.take().unwrap());
}
if let Some(old_handle) = self.manual_texture_view_handle {
manual_texture_views.remove(&old_handle);
self.manual_texture_view_handle = None;
}
// Create the texture for the camera target and the CustomPaintCtx.
let format = TextureFormat::Rgba8UnormSrgb;
let wgpu_texture = self.wgpu_device.create_texture(&wgpu::TextureDescriptor {
label: None,
size: wgpu::Extent3d {
width,
height,
depth_or_array_layers: 1,
},
mip_level_count: 1,
sample_count: 1,
dimension: wgpu::TextureDimension::D2,
format,
usage: wgpu::TextureUsages::TEXTURE_BINDING
| wgpu::TextureUsages::RENDER_ATTACHMENT
| wgpu::TextureUsages::COPY_SRC,
view_formats: &[],
});
let wgpu_texture_view =
wgpu_texture.create_view(&wgpu::TextureViewDescriptor::default());
let manual_texture_view = ManualTextureView {
texture_view: wgpu_texture_view.into(),
size: bevy::math::UVec2::new(width, height),
format,
};
let manual_texture_view_handle = ManualTextureViewHandle(0);
manual_texture_views.insert(manual_texture_view_handle, manual_texture_view);
if let Ok(mut camera) = world.query::<&mut Camera>().single_mut(world) {
camera.target = RenderTarget::TextureView(manual_texture_view_handle);
self.last_texture_size = current_size;
self.manual_texture_view_handle = Some(manual_texture_view_handle);
self.texture_handle = Some(ctx.register_texture(wgpu_texture));
}
}
}
}