use super::init::{calculate_surface_size_from_global_arrangement, format_entity_name};
use crate::ecs::graphics::wuc_resource::WucGraphicsResource;
use crate::ecs::graphics::{
GraphicsCommandList, GraphicsCore, SurfaceCreationStats, SurfaceGraphics, SurfaceGraphicsDirty,
VisualGraphics,
};
use crate::ecs::layout::GlobalArrangement;
use bevy_ecs::name::Name;
use bevy_ecs::prelude::*;
use tracing::{debug, error, trace, warn};
use windows::Foundation::Size;
use windows::Graphics::DirectX::{DirectXAlphaMode, DirectXPixelFormat};
use windows::UI::Composition::{CompositionBrush, SpriteVisual};
use windows::core::Interface;
pub fn mark_dirty_surfaces(
mut changed_query: Query<
(Entity, &mut SurfaceGraphicsDirty, Option<&Name>),
(
Or<(
Changed<GraphicsCommandList>,
Changed<SurfaceGraphics>,
Added<SurfaceGraphics>,
Changed<GlobalArrangement>,
)>,
With<SurfaceGraphics>,
),
>,
frame_count: Res<crate::ecs::world::FrameCount>,
) {
let mut count = 0;
for (entity, mut dirty, name) in changed_query.iter_mut() {
dirty.requested_frame = frame_count.0 as u64;
count += 1;
let _entity_name = format_entity_name(entity, name);
}
if count > 0 {
}
}
pub fn deferred_surface_creation_system(
graphics: Res<GraphicsCore>,
wuc_resource: Option<Res<WucGraphicsResource>>,
mut query: Query<
(
Entity,
&VisualGraphics,
&GraphicsCommandList,
&GlobalArrangement,
&mut SurfaceGraphics,
&mut SurfaceGraphicsDirty,
Option<&Name>,
),
Or<(Changed<GlobalArrangement>, Changed<GraphicsCommandList>)>,
>,
mut stats: ResMut<SurfaceCreationStats>,
) {
if !graphics.is_valid() {
return;
}
let (compositor, graphics_device) = match wuc_resource.as_ref() {
Some(r) => match (r.compositor(), r.graphics_device()) {
(Some(c), Some(gd)) => (c, gd),
_ => return,
},
None => return,
};
for (
entity,
visual_graphics,
_cmd_list,
global_arrangement,
mut surface_graphics,
mut dirty,
name,
) in query.iter_mut()
{
let entity_name = format_entity_name(entity, name);
let Some((width, height)) =
calculate_surface_size_from_global_arrangement(global_arrangement)
else {
trace!(
entity = %entity_name,
bounds = ?global_arrangement.bounds,
"[deferred_surface_creation] Entity skipped: invalid size from GlobalArrangement"
);
stats.record_skipped();
continue;
};
if surface_graphics.is_valid() && surface_graphics.size == (width, height) {
continue;
}
let is_new = !surface_graphics.is_valid();
if is_new {
debug!(
entity = %entity_name,
width = width,
height = height,
"[deferred_surface_creation] Creating Surface"
);
} else {
debug!(
entity = %entity_name,
old_size = ?surface_graphics.size,
new_width = width,
new_height = height,
"[deferred_surface_creation] Resizing Surface"
);
}
let surface_res = graphics_device.CreateDrawingSurface(
Size {
Width: width as f32,
Height: height as f32,
},
DirectXPixelFormat::B8G8R8A8UIntNormalized,
DirectXAlphaMode::Premultiplied,
);
match surface_res {
Ok(surface) => {
let brush = match compositor.CreateSurfaceBrushWithSurface(&surface) {
Ok(b) => b,
Err(e) => {
error!(
entity = %entity_name,
error = ?e,
"[deferred_surface_creation] CreateSurfaceBrushWithSurface FAILED"
);
continue;
}
};
if let Some(visual) = visual_graphics.visual() {
trace!(
entity = %entity_name,
"[deferred_surface_creation] SetBrush calling"
);
match visual.cast::<SpriteVisual>() {
Ok(sprite) => {
if let Err(e) = sprite.SetSize(windows_numerics::Vector2 {
X: width as f32,
Y: height as f32,
}) {
error!(
entity = %entity_name,
error = ?e,
"[deferred_surface_creation] SetSize FAILED"
);
}
match sprite.SetBrush(&brush) {
Ok(_) => trace!(
entity = %entity_name,
"[deferred_surface_creation] SetBrush SUCCESS"
),
Err(e) => error!(
entity = %entity_name,
error = ?e,
"[deferred_surface_creation] SetBrush FAILED"
),
}
}
Err(e) => error!(
entity = %entity_name,
error = ?e,
"[deferred_surface_creation] cast to SpriteVisual FAILED"
),
}
} else {
warn!(
entity = %entity_name,
"[deferred_surface_creation] NO VISUAL! SetBrush skipped"
);
}
surface_graphics.set_surface(surface, brush, (width, height));
dirty.requested_frame = dirty.requested_frame.wrapping_add(1);
if is_new {
stats.record_created();
debug!(
entity = %entity_name,
"[deferred_surface_creation] Surface created successfully"
);
} else {
stats.record_resized();
debug!(
entity = %entity_name,
"[deferred_surface_creation] Surface resized successfully"
);
}
}
Err(e) => {
error!(
entity = %entity_name,
error = ?e,
"[deferred_surface_creation] Failed to create/resize surface"
);
}
}
}
}
pub fn cleanup_surface_on_commandlist_removed(
mut removed: RemovedComponents<GraphicsCommandList>,
mut query: Query<(Entity, &VisualGraphics, &mut SurfaceGraphics, Option<&Name>)>,
mut stats: ResMut<SurfaceCreationStats>,
) {
for entity in removed.read() {
if let Ok((entity, visual_graphics, mut surface_graphics, name)) = query.get_mut(entity) {
if !surface_graphics.is_valid() {
continue;
}
let entity_name = format_entity_name(entity, name);
debug!(
entity = %entity_name,
"[cleanup_surface_on_commandlist_removed] Clearing SurfaceGraphics"
);
if let Some(visual) = visual_graphics.visual() {
if let Ok(sprite) = visual.cast::<SpriteVisual>() {
let _ = sprite.SetBrush(None::<&CompositionBrush>);
}
}
surface_graphics.clear();
stats.record_deleted();
debug!(
entity = %entity_name,
"[cleanup_surface_on_commandlist_removed] SurfaceGraphics cleared"
);
}
}
}