use bevy_ecs::lifecycle::HookContext;
use bevy_ecs::prelude::*;
use bevy_ecs::world::DeferredWorld;
use windows::Win32::Graphics::Direct2D::*;
use windows::Win32::Graphics::DirectComposition::*;
use windows_numerics::Vector2;
use crate::com::dcomp::DCompositionVisualExt;
#[derive(Component, Default, Debug, Clone, Copy, PartialEq, Eq)]
pub struct HasGraphicsResources;
#[derive(Debug)]
struct WindowGraphicsInner {
pub target: IDCompositionTarget,
pub device_context: ID2D1DeviceContext,
}
#[derive(Component, Debug)]
#[component(storage = "SparseSet")]
pub struct WindowGraphics {
inner: Option<WindowGraphicsInner>,
generation: u32,
}
unsafe impl Send for WindowGraphics {}
unsafe impl Sync for WindowGraphics {}
impl WindowGraphics {
pub fn new(target: IDCompositionTarget, device_context: ID2D1DeviceContext) -> Self {
Self {
inner: Some(WindowGraphicsInner {
target,
device_context,
}),
generation: 0,
}
}
pub fn invalidate(&mut self) {
self.inner = None;
}
pub fn is_valid(&self) -> bool {
self.inner.is_some()
}
pub fn generation(&self) -> u32 {
self.generation
}
pub fn increment_generation(&mut self) {
self.generation = self.generation.wrapping_add(1);
}
pub fn get_target(&self) -> Option<&IDCompositionTarget> {
self.inner.as_ref().map(|i| &i.target)
}
pub fn get_dc(&self) -> Option<&ID2D1DeviceContext> {
self.inner.as_ref().map(|i| &i.device_context)
}
}
#[derive(Component)]
#[component(on_remove = on_visual_graphics_remove)]
pub struct VisualGraphics {
inner: Option<IDCompositionVisual3>,
parent_visual: Option<IDCompositionVisual3>,
}
fn on_visual_graphics_remove(world: DeferredWorld, hook: HookContext) {
if let Some(vg) = world.get::<VisualGraphics>(hook.entity) {
if let (Some(parent), Some(visual)) = (&vg.parent_visual, &vg.inner) {
let _ = parent.remove_visual(visual); }
}
}
unsafe impl Send for VisualGraphics {}
unsafe impl Sync for VisualGraphics {}
impl std::fmt::Debug for VisualGraphics {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("VisualGraphics")
.field("inner", &self.inner.is_some())
.field("parent_visual", &self.parent_visual.is_some())
.finish()
}
}
impl Default for VisualGraphics {
fn default() -> Self {
Self {
inner: None,
parent_visual: None,
}
}
}
impl VisualGraphics {
pub fn new(visual: IDCompositionVisual3) -> Self {
Self {
inner: Some(visual),
parent_visual: None,
}
}
pub fn new_with_parent(
visual: IDCompositionVisual3,
parent_visual: Option<IDCompositionVisual3>,
) -> Self {
Self {
inner: Some(visual),
parent_visual,
}
}
pub fn invalidate(&mut self) {
self.inner = None;
self.parent_visual = None;
}
pub fn is_valid(&self) -> bool {
self.inner.is_some()
}
pub fn visual(&self) -> Option<&IDCompositionVisual3> {
self.inner.as_ref()
}
pub fn parent_visual(&self) -> Option<&IDCompositionVisual3> {
self.parent_visual.as_ref()
}
pub fn set_parent_visual(&mut self, parent: Option<IDCompositionVisual3>) {
self.parent_visual = parent;
}
}
#[derive(Component, Debug, Default)]
pub struct SurfaceGraphics {
inner: Option<IDCompositionSurface>,
pub size: (u32, u32),
}
unsafe impl Send for SurfaceGraphics {}
unsafe impl Sync for SurfaceGraphics {}
impl SurfaceGraphics {
pub fn new(surface: IDCompositionSurface, size: (u32, u32)) -> Self {
Self {
inner: Some(surface),
size,
}
}
pub fn invalidate(&mut self) {
self.inner = None;
self.size = (0, 0);
}
pub fn is_valid(&self) -> bool {
self.inner.is_some()
}
pub fn surface(&self) -> Option<&IDCompositionSurface> {
self.inner.as_ref()
}
pub fn set_surface(&mut self, surface: IDCompositionSurface, size: (u32, u32)) {
self.inner = Some(surface);
self.size = size;
}
pub fn clear(&mut self) {
self.inner = None;
self.size = (0, 0);
}
}
#[derive(Component, Default, Debug, Clone, PartialEq)]
pub struct SurfaceGraphicsDirty {
pub requested_frame: u64,
}
#[derive(Component, Debug, Clone, PartialEq)]
#[component(on_add = on_visual_add)]
pub struct Visual {
pub is_visible: bool,
pub opacity: f32,
pub transform_origin: Vector2,
}
fn on_visual_add(mut world: DeferredWorld, context: HookContext) {
let entity = context.entity;
let needs_arrangement = world
.get::<crate::ecs::layout::Arrangement>(entity)
.is_none();
let needs_visual_graphics = world.get::<VisualGraphics>(entity).is_none();
let needs_surface_graphics = world.get::<SurfaceGraphics>(entity).is_none();
let needs_surface_dirty = world.get::<SurfaceGraphicsDirty>(entity).is_none();
let needs_brush_inherit = world
.get::<crate::ecs::widget::BrushInherit>(entity)
.is_none();
let mut cmds = world.commands();
let mut entity_cmds = cmds.entity(entity);
if needs_arrangement {
entity_cmds.insert(crate::ecs::layout::Arrangement::default());
}
if needs_visual_graphics {
entity_cmds.insert(VisualGraphics::default());
}
if needs_surface_graphics {
entity_cmds.insert(SurfaceGraphics::default());
}
if needs_surface_dirty {
entity_cmds.insert(SurfaceGraphicsDirty::default());
}
if needs_brush_inherit {
entity_cmds.insert(crate::ecs::widget::BrushInherit);
}
}
impl Default for Visual {
fn default() -> Self {
Self {
is_visible: true,
opacity: 1.0,
transform_origin: Vector2::default(),
}
}
}
#[derive(Resource, Default, Debug, Clone, PartialEq)]
pub struct SurfaceCreationStats {
pub created_count: u64,
pub skipped_count: u64,
pub deleted_count: u64,
pub resize_count: u64,
}
impl SurfaceCreationStats {
pub fn record_created(&mut self) {
self.created_count += 1;
}
pub fn record_skipped(&mut self) {
self.skipped_count += 1;
}
pub fn record_deleted(&mut self) {
self.deleted_count += 1;
}
pub fn record_resized(&mut self) {
self.resize_count += 1;
}
}