use crate::com::d2d::D2D1DeviceExt;
use crate::com::wuc::CompositorDesktopInteropExt;
use crate::ecs::graphics::wuc_resource::WucGraphicsResource;
use crate::ecs::graphics::{GraphicsCore, HasGraphicsResources, WindowGraphics};
use crate::ecs::layout::GlobalArrangement;
use bevy_ecs::name::Name;
use bevy_ecs::prelude::*;
use tracing::{debug, error, info};
use windows::Win32::Foundation::*;
use windows::Win32::System::WinRT::Composition::ICompositorDesktopInterop;
use windows::core::Interface;
pub fn format_entity_name(entity: Entity, name: Option<&Name>) -> String {
match name {
Some(n) => n.to_string(),
None => format!("Entity({:?})", entity),
}
}
pub fn calculate_surface_size_from_global_arrangement(
global_arrangement: &GlobalArrangement,
) -> Option<(u32, u32)> {
let width = global_arrangement.bounds.right - global_arrangement.bounds.left;
let height = global_arrangement.bounds.bottom - global_arrangement.bounds.top;
if width <= 0.0 || height <= 0.0 {
return None;
}
let width_px = width.ceil() as u32;
let height_px = height.ceil() as u32;
if width_px == 0 || height_px == 0 {
return None;
}
Some((width_px, height_px))
}
fn create_window_graphics_for_hwnd(
graphics: &GraphicsCore,
wuc_resource: &WucGraphicsResource,
hwnd: HWND,
) -> windows::core::Result<WindowGraphics> {
use windows::Win32::Graphics::Direct2D::D2D1_DEVICE_CONTEXT_OPTIONS_NONE;
if !graphics.is_valid() || !wuc_resource.is_valid() {
return Err(windows::core::Error::from(E_FAIL));
}
let compositor = wuc_resource
.compositor()
.ok_or(windows::core::Error::from(E_FAIL))?;
let desktop_interop = compositor.cast::<ICompositorDesktopInterop>()?;
let target = desktop_interop.create_desktop_window_target(hwnd, true)?;
let d2d = graphics
.d2d_device()
.ok_or(windows::core::Error::from(E_FAIL))?;
let device_context = d2d.create_device_context(D2D1_DEVICE_CONTEXT_OPTIONS_NONE)?;
Ok(WindowGraphics::new(target, device_context))
}
pub fn init_graphics_core(
graphics: Option<ResMut<GraphicsCore>>,
mut query: Query<&mut HasGraphicsResources>,
mut commands: Commands,
frame_count: Res<crate::ecs::world::FrameCount>,
) {
if !graphics.as_ref().is_some_and(|gc| gc.is_valid()) {
crate::ecs::world::tick_wake::mark(crate::ecs::world::tick_wake::GRAPHICS);
}
match graphics {
Some(mut gc) => {
if gc.is_valid() {
return;
}
info!(
frame = frame_count.0,
"[init_graphics_core] GraphicsCore re-initialization started"
);
match GraphicsCore::new() {
Ok(new_gc) => {
*gc = new_gc;
info!(
frame = frame_count.0,
"[init_graphics_core] GraphicsCore re-initialization completed"
);
let count = query.iter().count();
debug!(
frame = frame_count.0,
count = count,
"[init_graphics_core] Triggering set_changed() on entities (re-init)"
);
for mut res in query.iter_mut() {
res.set_changed();
}
}
Err(e) => {
error!(
frame = frame_count.0,
error = ?e,
"[init_graphics_core] GraphicsCore re-initialization failed"
);
}
}
}
None => {
info!(
frame = frame_count.0,
"[init_graphics_core] GraphicsCore initialization started"
);
match GraphicsCore::new() {
Ok(gc) => {
info!(
frame = frame_count.0,
"[init_graphics_core] GraphicsCore initialization completed"
);
commands.insert_resource(gc);
let count = query.iter().count();
debug!(
frame = frame_count.0,
count = count,
"[init_graphics_core] Triggering set_changed() on entities (init)"
);
for mut res in query.iter_mut() {
res.set_changed();
}
}
Err(e) => {
error!(
frame = frame_count.0,
error = ?e,
"[init_graphics_core] GraphicsCore initialization failed"
);
}
}
}
}
}
pub fn init_window_graphics(
graphics: Res<GraphicsCore>,
wuc_resource: Option<ResMut<WucGraphicsResource>>,
mut query: Query<
(
Entity,
&crate::ecs::window::Window,
&crate::ecs::window::WindowHandle,
&HasGraphicsResources,
Option<&mut WindowGraphics>,
Option<&Name>,
),
Or<(Without<WindowGraphics>, Changed<HasGraphicsResources>)>,
>,
mut commands: Commands,
frame_count: Res<crate::ecs::world::FrameCount>,
) {
if !graphics.is_valid() {
return;
}
if query.iter().next().is_none() {
return;
}
let wuc_valid = wuc_resource.as_ref().map_or(false, |r| r.is_valid());
if !wuc_valid {
if let Some(d2d) = graphics.d2d_device() {
match WucGraphicsResource::new(d2d) {
Ok(new_resource) => {
info!(
frame = frame_count.0,
"[init_window_graphics] WucGraphicsResource lazily initialized"
);
commands.insert_resource(new_resource);
return;
}
Err(e) => {
error!(
frame = frame_count.0,
error = ?e,
"[init_window_graphics] WucGraphicsResource initialization failed"
);
return;
}
}
} else {
return;
}
}
let wuc_res = wuc_resource.unwrap();
for (entity, _window, handle, _res, window_graphics, name) in query.iter_mut() {
let entity_name = format_entity_name(entity, name);
match window_graphics {
None => {
debug!(
frame = frame_count.0,
entity = %entity_name,
"[init_window_graphics] WindowGraphics creating new"
);
match create_window_graphics_for_hwnd(&graphics, &wuc_res, handle.hwnd) {
Ok(wg) => {
debug!(
frame = frame_count.0,
entity = %entity_name,
"[init_window_graphics] WindowGraphics created"
);
commands.entity(entity).insert(wg);
}
Err(e) => {
error!(
frame = frame_count.0,
entity = %entity_name,
error = ?e,
"[init_window_graphics] Error creating WindowGraphics"
);
}
}
}
Some(mut wg) => {
if !wg.is_valid() {
debug!(
frame = frame_count.0,
entity = %entity_name,
"[init_window_graphics] WindowGraphics re-initializing"
);
let old_generation = wg.generation();
match create_window_graphics_for_hwnd(&graphics, &wuc_res, handle.hwnd) {
Ok(new_wg) => {
let new_generation = old_generation.wrapping_add(1);
*wg = new_wg;
while wg.generation() < new_generation {
wg.increment_generation();
}
debug!(
frame = frame_count.0,
entity = %entity_name,
old_generation = old_generation,
new_generation = wg.generation(),
"[init_window_graphics] WindowGraphics re-initialized"
);
}
Err(e) => {
error!(
frame = frame_count.0,
entity = %entity_name,
error = ?e,
"[init_window_graphics] Re-initialization error"
);
}
}
}
}
}
}
}