use bevy::camera::visibility::RenderLayers;
use bevy::ecs::change_detection::Tick;
use bevy::ecs::query::FilteredAccessSet;
use bevy::ecs::system::{SystemMeta, SystemParam};
use bevy::ecs::world::unsafe_world_cell::UnsafeWorldCell;
use bevy::platform::cell::SyncCell;
use bevy::prelude::*;
use crate::prelude::*;
use crate::render::ShapePipelineType;
#[derive(Clone, Reflect)]
pub struct ShapeConfig {
pub transform: Transform,
pub alignment: Alignment,
pub origin: Option<Vec3>,
pub color: Color,
pub hollow: bool,
pub thickness: f32,
pub thickness_type: ThicknessType,
pub cap: Cap,
pub roundness: f32,
pub corner_radii: Vec4,
#[reflect(ignore)]
pub render_layers: Option<RenderLayers>,
pub alpha_mode: ShapeAlphaMode,
pub disable_laa: bool,
pub canvas: Option<Entity>,
pub texture: Option<Handle<Image>>,
pub pipeline: ShapePipelineType,
pub reset: bool,
}
impl ShapeConfig {
pub fn translate(&mut self, dir: Vec3) {
self.transform.translation += self.transform.rotation * dir * self.transform.scale;
}
pub fn set_translation(&mut self, translation: Vec3) {
self.transform.translation = translation;
}
pub fn rotate(&mut self, quat: Quat) {
self.transform.rotation *= quat;
}
pub fn set_rotation(&mut self, rotation: Quat) {
self.transform.rotation = rotation;
}
pub fn rotate_x(&mut self, angle: f32) {
self.rotate(Quat::from_rotation_x(angle))
}
pub fn rotate_y(&mut self, angle: f32) {
self.rotate(Quat::from_rotation_y(angle))
}
pub fn rotate_z(&mut self, angle: f32) {
self.rotate(Quat::from_rotation_z(angle))
}
pub fn scale(&mut self, scale: Vec3) {
self.transform.scale *= scale;
}
pub fn set_scale(&mut self, scale: Vec3) {
self.transform.scale = scale;
}
pub fn set_canvas(&mut self, canvas: Entity) {
self.pipeline = ShapePipelineType::Shape2d;
self.canvas = Some(canvas);
}
pub fn set_3d(&mut self) {
self.pipeline = ShapePipelineType::Shape3d;
}
pub fn set_2d(&mut self) {
self.pipeline = ShapePipelineType::Shape2d;
}
pub fn without_transform(&self) -> Self {
let mut config = self.clone();
config.transform = Transform::IDENTITY;
config
}
pub fn set_color(&mut self, color: impl Into<Color>) {
self.color = color.into();
}
}
impl ShapeConfig {
pub fn default_2d() -> Self {
Self {
transform: default(),
origin: None,
color: Color::WHITE,
thickness: 0.1,
thickness_type: default(),
alignment: default(),
hollow: false,
cap: default(),
roundness: default(),
corner_radii: default(),
render_layers: None,
alpha_mode: ShapeAlphaMode::Blend,
disable_laa: false,
canvas: None,
texture: None,
pipeline: ShapePipelineType::Shape2d,
reset: true,
}
}
}
impl ShapeConfig {
pub fn default_3d() -> Self {
let mut config = Self::default_2d();
config.pipeline = ShapePipelineType::Shape3d;
config
}
}
impl FromWorld for ShapeConfig {
fn from_world(world: &mut World) -> Self {
let config = world.resource::<BaseShapeConfig>();
config.0.clone()
}
}
pub struct ShapeConfigState {
shape_config: SyncCell<ShapeConfig>,
resource_state: <Res<'static, BaseShapeConfig> as SystemParam>::State,
}
unsafe impl SystemParam for &mut ShapeConfig {
type State = ShapeConfigState;
type Item<'w, 's> = &'s mut ShapeConfig;
fn init_state(world: &mut World) -> Self::State {
ShapeConfigState {
shape_config: SyncCell::new(ShapeConfig::from_world(world)),
resource_state: Res::<BaseShapeConfig>::init_state(world),
}
}
fn init_access(
state: &Self::State,
system_meta: &mut SystemMeta,
component_access_set: &mut FilteredAccessSet,
world: &mut World,
) {
Res::<BaseShapeConfig>::init_access(
&state.resource_state,
system_meta,
component_access_set,
world,
);
}
#[inline]
unsafe fn get_param<'w, 's>(
state: &'s mut Self::State,
_system_meta: &SystemMeta,
_world: UnsafeWorldCell<'w>,
_change_tick: Tick,
) -> Self::Item<'w, 's> {
state.shape_config.get()
}
fn apply(state: &mut Self::State, _system_meta: &SystemMeta, world: &mut World) {
let state = state.shape_config.get();
if state.reset {
*state = world.resource::<BaseShapeConfig>().0.clone();
}
}
}