use crate::Node;
use bevy_asset::{Asset, AssetId, Handle};
use bevy_derive::{Deref, DerefMut};
use bevy_ecs::{component::Component, reflect::ReflectComponent, template::FromTemplate};
use bevy_reflect::{prelude::ReflectDefault, Reflect};
use bevy_render::{
extract_component::ExtractComponent,
render_resource::{AsBindGroup, RenderPipelineDescriptor, TextureFormat},
};
use bevy_shader::ShaderRef;
use derive_more::derive::From;
pub trait UiMaterial: AsBindGroup + Asset + Clone + Sized {
fn vertex_shader() -> ShaderRef {
ShaderRef::Default
}
fn fragment_shader() -> ShaderRef {
ShaderRef::Default
}
fn stack_z_offset() -> f32 {
crate::stack_z_offsets::MATERIAL
}
#[expect(
unused_variables,
reason = "The parameters here are intentionally unused by the default implementation; however, putting underscores here will result in the underscores being copied by rust-analyzer's tab completion."
)]
#[inline]
fn specialize(descriptor: &mut RenderPipelineDescriptor, key: UiMaterialKey<Self>) {}
}
pub struct UiMaterialKey<M: UiMaterial> {
pub target_format: TextureFormat,
pub bind_group_data: M::Data,
}
impl<M: UiMaterial> Eq for UiMaterialKey<M> where M::Data: PartialEq {}
impl<M: UiMaterial> PartialEq for UiMaterialKey<M>
where
M::Data: PartialEq,
{
fn eq(&self, other: &Self) -> bool {
self.target_format == other.target_format && self.bind_group_data == other.bind_group_data
}
}
impl<M: UiMaterial> Clone for UiMaterialKey<M>
where
M::Data: Clone,
{
fn clone(&self) -> Self {
Self {
target_format: self.target_format,
bind_group_data: self.bind_group_data.clone(),
}
}
}
impl<M: UiMaterial> core::hash::Hash for UiMaterialKey<M>
where
M::Data: core::hash::Hash,
{
fn hash<H: core::hash::Hasher>(&self, state: &mut H) {
self.target_format.hash(state);
self.bind_group_data.hash(state);
}
}
#[derive(
Component,
FromTemplate,
Clone,
Debug,
Deref,
DerefMut,
Reflect,
PartialEq,
Eq,
ExtractComponent,
From,
)]
#[reflect(Component, Default)]
#[require(Node)]
pub struct MaterialNode<M: UiMaterial>(pub Handle<M>);
impl<M: UiMaterial> Default for MaterialNode<M> {
fn default() -> Self {
Self(Handle::default())
}
}
impl<M: UiMaterial> From<MaterialNode<M>> for AssetId<M> {
fn from(material: MaterialNode<M>) -> Self {
material.id()
}
}
impl<M: UiMaterial> From<&MaterialNode<M>> for AssetId<M> {
fn from(material: &MaterialNode<M>) -> Self {
material.id()
}
}