pub mod labels;
pub mod physics;
pub mod scenes;
use crate::{
error::{objects::NoObjectError, textures::*},
prelude::*,
utils::color_art_to_array,
};
use color_art::{color, Color};
use scenes::Layer;
use anyhow::Result;
use glam::f32::{vec2, Vec2};
use hashbrown::HashMap;
use parking_lot::Mutex;
use std::{
default,
sync::{Arc, Weak},
};
type RigidBodyParent = Option<Option<Weak<Mutex<Node<Object>>>>>;
type ObjectsMap = HashMap<usize, NObject>;
pub(crate) type NObject = Arc<Mutex<Node<Object>>>;
type WeakObject = Weak<Mutex<Node<Object>>>;
#[derive(Clone, Copy, Debug, PartialEq)]
pub struct Transform {
pub position: Vec2,
pub size: Vec2,
pub rotation: f32,
}
impl Transform {
pub fn combine(self, rhs: Self) -> Self {
Self {
position: self.position + rhs.position.rotate(Vec2::from_angle(self.rotation)),
size: self.size * rhs.size,
rotation: self.rotation + rhs.rotation,
}
}
pub fn position(mut self, position: Vec2) -> Self {
self.position = position;
self
}
pub fn size(mut self, size: Vec2) -> Self {
self.size = size;
self
}
pub fn rotation(mut self, rotation: f32) -> Self {
self.rotation = rotation;
self
}
}
impl Default for Transform {
fn default() -> Self {
Self {
position: vec2(0.0, 0.0),
size: vec2(1.0, 1.0),
rotation: 0.0,
}
}
}
#[derive(Clone)]
pub(crate) struct VisualObject {
pub transform: Transform,
pub appearance: Appearance,
}
impl VisualObject {
pub fn combined(object: &Object, other: &Object) -> Self {
let transform = object.transform.combine(other.transform);
let appearance = other.appearance().clone();
Self {
transform,
appearance,
}
}
}
pub struct Node<T> {
pub object: T,
pub parent: Option<Weak<Mutex<Node<T>>>>,
pub rigid_body_parent: RigidBodyParent,
pub children: Vec<Arc<Mutex<Node<T>>>>,
}
impl Node<Object> {
pub(crate) fn order_position(order: &mut Vec<VisualObject>, objects: &Self) {
for child in objects.children.iter() {
let child = child.lock();
let object = VisualObject::combined(&objects.object, &child.object);
order.push(object.clone());
for child in child.children.iter() {
let child = child.lock();
order.push(VisualObject {
transform: object.transform.combine(child.object.transform),
appearance: child.object.appearance().clone(),
});
Self::order_position(order, &child);
}
}
}
pub fn update_children_position(&mut self, parent_pos: Transform) {
self.object.set_parent_transform(parent_pos);
for child in self.children.iter() {
child
.lock()
.update_children_position(self.object.public_transform());
}
}
pub fn remove_child(&mut self, object: &NObject) {
let index = self
.children
.clone()
.into_iter()
.position(|x| Arc::ptr_eq(&x, object))
.unwrap();
self.children.remove(index);
}
pub fn remove_children(&mut self, objects: &mut ObjectsMap, rigid_bodies: &mut ObjectsMap) {
self.object.physics.remove();
for child in self.children.iter() {
child.clone().lock().remove_children(objects, rigid_bodies);
}
objects.remove(&self.object.id());
rigid_bodies.remove(&self.object.id());
self.children = vec![];
}
pub fn end_transform(&self) -> Transform {
if let Some(parent) = &self.parent {
let parent = parent.upgrade().unwrap();
let parent = parent.lock();
parent.end_transform().combine(self.object.transform)
} else {
self.object.transform
}
}
}
#[derive(Debug, Clone, PartialEq)]
pub struct Appearance {
visible: bool,
material: Option<materials::Material>,
model: Option<Model>,
transform: Transform,
color: [f32; 4],
color_art: Color,
}
use paste::paste;
use self::physics::Collider;
macro_rules! getters_and_setters {
($field:ident, $title:expr, $type:ty) => {
#[doc=concat!("Sets ", $title, " of this appearance and returns self.")]
#[inline]
pub fn $field(mut self, $field: $type) -> Self {
self.$field = $field;
self
}
paste! {
#[doc=concat!("Sets ", $title, " of this appearance.")]
#[inline]
pub fn [<set_ $field>](&mut self, $field: $type) {
self.$field = $field;
}
}
paste! {
#[doc=concat!("Gets ", $title," of this appearance.")]
#[inline]
pub fn [<get_ $field>](&self) -> &$type {
&self.$field
}
}
paste! {
#[doc=concat!("Gets a mutable reference to ", $title," of this appearance.")]
#[inline]
pub fn [<get_mut_ $field>](&mut self) -> &mut $type {
&mut self.$field
}
}
};
}
impl Appearance {
pub fn new() -> Self {
Self {
..Default::default()
}
}
pub fn auto_scale(&mut self) -> Result<(), NoTextureError> {
let dimensions;
if let Some(material) = &self.material {
dimensions = if let Some(texture) = &material.texture {
texture.dimensions()
} else {
return Err(NoTextureError);
};
} else {
return Err(NoTextureError);
};
self.transform.size = vec2(dimensions.0 as f32 / 1000.0, dimensions.1 as f32 / 1000.0);
Ok(())
}
getters_and_setters!(visible, "the visibility", bool);
getters_and_setters!(model, "the model", Option<Model>);
getters_and_setters!(transform, "the transform", Transform);
getters_and_setters!(material, "the material", Option<materials::Material>);
#[inline]
pub fn color(mut self, color: Color) -> Self {
self.color_art = color;
self.color = color_art_to_array(color);
self
}
#[inline]
pub fn get_color(&self) -> Color {
self.color_art
}
#[inline]
pub fn get_color_array(&self) -> [f32; 4] {
self.color
}
#[inline]
pub fn set_color(mut self, color: Color) {
self.color_art = color;
self.color = color_art_to_array(color);
}
}
impl default::Default for Appearance {
fn default() -> Self {
Self {
visible: true,
material: None,
model: None,
transform: Transform::default(),
color_art: color!(rgba(255, 255, 255, 1.0)),
color: [1.0; 4],
}
}
}
#[derive(Default, Clone)]
pub struct Object {
pub transform: Transform,
parent_transform: Transform,
pub appearance: Appearance,
id: usize,
reference: Option<WeakObject>,
pub(crate) physics: ObjectPhysics,
layer: Option<Layer>,
}
impl Object {
pub fn new() -> Self {
Self::default()
}
pub fn init(&mut self, layer: &Layer) {
self.init_with_optional_parent(layer, None);
}
pub fn init_with_parent(&mut self, layer: &Layer, parent: &Object) {
self.init_with_optional_parent(layer, Some(parent));
}
pub fn init_with_optional_parent(&mut self, layer: &Layer, parent: Option<&Object>) {
self.layer = Some(layer.clone());
self.id = layer.increment_id();
self.physics.physics = Some(layer.physics().clone());
let mut rigid_body_parent;
let parent: NObject = if let Some(parent) = parent {
let parent = parent.as_node().unwrap(); rigid_body_parent = parent.lock().rigid_body_parent.clone();
parent.clone()
} else {
rigid_body_parent = None;
layer.root.clone()
};
self.parent_transform = self.physics.update(
&self.transform,
&parent,
&mut rigid_body_parent,
self.id as u128,
);
let node: NObject = std::sync::Arc::new(Mutex::new(Node {
object: self.clone(),
parent: Some(std::sync::Arc::downgrade(&parent)),
rigid_body_parent: rigid_body_parent.clone(),
children: vec![],
}));
self.reference = Some(std::sync::Arc::downgrade(&node));
if let Some(value) = &rigid_body_parent {
if value.is_none() && self.physics.rigid_body.is_some() {
layer
.rigid_body_roots()
.lock()
.insert(self.id, node.clone());
}
}
layer.add_object(self.id, &node);
parent.lock().children.push(node.clone());
}
pub fn remove(&mut self) -> Result<(), NoObjectError> {
let mut map = self
.layer
.as_ref()
.expect("uninitialized")
.objects_map
.lock(); let mut rigid_bodies = self.layer.as_ref().unwrap().rigid_body_roots().lock();
let node = if let Some(object) = map.remove(&self.id) {
object
} else {
return Err(NoObjectError);
};
rigid_bodies.remove(&self.id);
self.physics.remove();
let mut object = node.lock();
object.remove_children(&mut map, &mut rigid_bodies);
let parent = object.parent.clone().unwrap().upgrade().unwrap();
let mut parent = parent.lock();
parent.remove_child(&node);
self.id = 0;
Ok(())
}
}
impl Object {
pub fn set_isometry(&mut self, position: Vec2, rotation: f32) {
self.transform.position = position;
self.transform.rotation = rotation;
}
pub fn public_transform(&self) -> Transform {
self.transform.combine(self.parent_transform)
}
pub(crate) fn set_parent_transform(&mut self, transform: Transform) {
self.parent_transform = transform;
}
pub fn appearance(&self) -> &Appearance {
&self.appearance
}
pub fn id(&self) -> usize {
self.id
}
pub(crate) fn as_node(&self) -> Option<NObject> {
self.reference.as_ref()?.upgrade()
}
pub(crate) fn rigidbody_handle(&self) -> Option<rapier2d::dynamics::RigidBodyHandle> {
self.physics.rigid_body_handle
}
pub fn update(&mut self) {
if let Some(arc) = self.reference.clone().unwrap().upgrade() {
let object = &arc.lock().object;
self.transform = object.transform;
self.appearance = object.appearance().clone();
} else {
self.physics.remove();
}
}
pub fn sync(&mut self) {
let node = self.as_node().expect("uninitialized"); {
let mut node = node.lock();
self.parent_transform = self.physics.update(
&self.transform,
&node.parent.clone().unwrap().upgrade().unwrap(),
&mut node.rigid_body_parent,
self.id as u128,
);
}
node.lock()
.update_children_position(self.public_transform());
let arc = self.reference.clone().unwrap().upgrade().unwrap();
let mut object = arc.lock();
object.object = self.clone();
}
pub fn collider(&self) -> Option<&Collider> {
self.physics.collider.as_ref()
}
pub fn set_collider(&mut self, collider: Option<Collider>) {
self.physics.collider = collider;
}
pub fn collider_mut(&mut self) -> Option<&mut Collider> {
self.physics.collider.as_mut()
}
pub fn rigid_body(&self) -> Option<&RigidBody> {
self.physics.rigid_body.as_ref()
}
pub fn set_rigid_body(&mut self, rigid_body: Option<RigidBody>) {
self.physics.rigid_body = rigid_body;
}
pub fn rigid_body_mut(&mut self) -> Option<&mut RigidBody> {
self.physics.rigid_body.as_mut()
}
pub fn local_collider_position(&self) -> Vec2 {
self.physics.local_collider_position
}
pub fn set_local_collider_position(&mut self, pos: Vec2) {
self.physics.local_collider_position = pos;
}
}