#[cfg(feature = "client")]
mod appearance;
#[cfg(feature = "client")]
mod color;
#[cfg(feature = "client")]
pub use appearance::*;
#[cfg(feature = "client")]
pub use color::Color;
#[cfg(feature = "labels")]
pub mod labels;
#[cfg(feature = "physics")]
pub mod physics;
pub mod scenes;
use crate::prelude::*;
use anyhow::{Error, Result};
use scenes::Layer;
use derive_builder::Builder;
use glam::f32::{vec2, Vec2};
use parking_lot::Mutex;
use std::{
collections::HashMap,
sync::{Arc, Weak},
};
#[cfg(feature = "physics")]
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 Eq for Transform {}
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)]
#[cfg(feature = "client")]
pub(crate) struct VisualObject {
pub transform: Transform,
pub appearance: Appearance,
}
#[cfg(feature = "client")]
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(crate) struct Node<T> {
pub object: T,
pub parent: Option<Weak<Mutex<Node<T>>>>,
#[cfg(feature = "physics")]
pub rigid_body_parent: RigidBodyParent,
pub children: Vec<Arc<Mutex<Node<T>>>>,
}
impl PartialEq for Node<Object> {
fn eq(&self, other: &Self) -> bool {
self.object == other.object
}
}
impl Node<Object> {
#[cfg(feature = "client")]
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) -> Result<()> {
let index = self
.children
.clone()
.into_iter()
.position(|x| Arc::ptr_eq(&x, object))
.ok_or(Error::msg("No child found"))?;
self.children.remove(index);
Ok(())
}
pub fn remove_children(
&mut self,
objects: &mut ObjectsMap,
#[cfg(feature = "physics")] rigid_bodies: &mut ObjectsMap,
) {
#[cfg(feature = "physics")]
{
let layer = self.object.layer().clone();
self.object.physics.remove(layer.physics());
}
for child in self.children.iter() {
child.clone().lock().remove_children(
objects,
#[cfg(feature = "physics")]
rigid_bodies,
);
}
objects.remove(&self.object.id());
#[cfg(feature = "physics")]
rigid_bodies.remove(&self.object.id());
self.children = vec![];
}
}
#[derive(Default, Clone, Builder, PartialEq, Debug)]
pub struct NewObject {
#[builder(setter(into))]
pub transform: Transform,
#[builder(setter(into))]
#[cfg(feature = "client")]
pub appearance: Appearance,
#[builder(setter(skip))]
#[cfg(feature = "physics")]
pub(crate) physics: ObjectPhysics,
}
#[derive(Clone)]
pub struct Object {
pub transform: Transform,
parent_transform: Transform,
#[cfg(feature = "client")]
pub appearance: Appearance,
id: usize,
node: Option<WeakObject>,
#[cfg(feature = "physics")]
pub(crate) physics: ObjectPhysics,
layer: Option<Arc<Layer>>,
}
impl std::fmt::Debug for Object {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("Object")
.field("id", &self.id)
.field("transform", &self.transform)
.field("parent_transform", &self.parent_transform)
.finish()
}
}
impl Eq for NewObject {}
impl PartialEq for Object {
fn eq(&self, other: &Self) -> bool {
#[cfg(not(feature = "client"))]
{
self.transform == other.transform
&& self.parent_transform == other.parent_transform
&& self.id == other.id
&& self.layer == other.layer
}
#[cfg(feature = "client")]
{
self.transform == other.transform
&& self.parent_transform == other.parent_transform
&& self.appearance == other.appearance
&& self.id == other.id
&& self.layer == other.layer
}
}
}
impl Eq for Object {}
impl NewObject {
pub fn new() -> Self {
Self::default()
}
pub fn init(self, layer: &Arc<Layer>) -> Result<Object> {
self.init_with_optional_parent(layer, None)
}
pub fn init_with_parent(self, layer: &Arc<Layer>, parent: &Object) -> Result<Object> {
self.init_with_optional_parent(layer, Some(parent))
}
#[allow(unused_mut)]
pub fn init_with_optional_parent(
mut self,
layer: &Arc<Layer>,
parent: Option<&Object>,
) -> Result<Object> {
let id = layer.increment_id();
#[cfg(feature = "physics")]
let mut rigid_body_parent;
let parent: NObject = if let Some(parent) = parent {
let parent = parent.as_node();
#[cfg(feature = "physics")]
{
rigid_body_parent = parent.lock().rigid_body_parent.clone();
}
parent.clone()
} else {
#[cfg(feature = "physics")]
{
rigid_body_parent = None;
}
layer.root.clone()
};
#[cfg(feature = "physics")]
let parent_transform = self
.physics
.update(
&self.transform,
&parent,
&mut rigid_body_parent,
id as u128,
layer.physics(),
)
.ok_or(Error::msg(
"Could not update the physics side of this object.",
))?;
#[cfg(not(feature = "physics"))]
let parent_transform = parent.lock().object.public_transform();
let mut initialized = Object {
transform: self.transform,
parent_transform,
#[cfg(feature = "client")]
appearance: self.appearance,
id,
node: None,
#[cfg(feature = "physics")]
physics: self.physics,
layer: Some(layer.clone()),
};
let node: NObject = std::sync::Arc::new(Mutex::new(Node {
object: initialized.clone(),
parent: Some(std::sync::Arc::downgrade(&parent)),
#[cfg(feature = "physics")]
rigid_body_parent: rigid_body_parent.clone(),
children: vec![],
}));
let reference = Some(std::sync::Arc::downgrade(&node));
node.lock().object.node = reference.clone();
initialized.node = reference;
#[cfg(feature = "physics")]
if let Some(value) = &rigid_body_parent {
if value.is_none() && initialized.physics.rigid_body.is_some() {
layer.rigid_body_roots().lock().insert(id, node.clone());
}
}
layer.add_object(id, &node);
parent.lock().children.push(node.clone());
Ok(initialized)
}
}
impl NewObject {
pub fn set_isometry(&mut self, position: Vec2, rotation: f32) {
self.transform.position = position;
self.transform.rotation = rotation;
}
#[cfg(feature = "client")]
pub fn appearance(&self) -> &Appearance {
&self.appearance
}
}
#[cfg(feature = "physics")]
impl NewObject {
#[cfg(feature = "physics")]
pub fn collider(&self) -> Option<&Collider> {
self.physics.collider.as_ref()
}
#[cfg(feature = "physics")]
pub fn set_collider(&mut self, collider: Option<Collider>) {
self.physics.collider = collider;
}
#[cfg(feature = "physics")]
pub fn collider_mut(&mut self) -> Option<&mut Collider> {
self.physics.collider.as_mut()
}
#[cfg(feature = "physics")]
pub fn rigid_body(&self) -> Option<&RigidBody> {
self.physics.rigid_body.as_ref()
}
#[cfg(feature = "physics")]
pub fn set_rigid_body(&mut self, rigid_body: Option<RigidBody>) {
self.physics.rigid_body = rigid_body;
}
#[cfg(feature = "physics")]
pub fn rigid_body_mut(&mut self) -> Option<&mut RigidBody> {
self.physics.rigid_body.as_mut()
}
#[cfg(feature = "physics")]
pub fn local_collider_position(&self) -> Vec2 {
self.physics.local_collider_position
}
#[cfg(feature = "physics")]
pub fn set_local_collider_position(&mut self, pos: Vec2) {
self.physics.local_collider_position = pos;
}
}
impl Object {
pub(crate) fn root() -> Self {
Self {
transform: Transform::default(),
parent_transform: Transform::default(),
#[cfg(feature = "client")]
appearance: Appearance::default(),
id: 0,
node: None,
#[cfg(feature = "physics")]
physics: ObjectPhysics::default(),
layer: None,
}
}
pub fn layer(&self) -> &Arc<Layer> {
self.layer.as_ref().unwrap()
}
#[allow(unused_mut)]
pub fn remove(mut self) -> NewObject {
let layer = self.layer.unwrap();
let mut map = layer.objects_map.lock();
#[cfg(feature = "physics")]
let mut rigid_bodies = layer.rigid_body_roots().lock();
let node = map.remove(&self.id).unwrap();
#[cfg(feature = "physics")]
{
rigid_bodies.remove(&self.id);
self.physics.remove(layer.physics());
}
let mut object = node.lock();
object.remove_children(
&mut map,
#[cfg(feature = "physics")]
&mut rigid_bodies,
);
let parent = object.parent.clone().unwrap().upgrade().unwrap();
let mut parent = parent.lock();
parent.remove_child(&node).unwrap();
NewObject {
transform: self.transform,
#[cfg(feature = "client")]
appearance: self.appearance,
#[cfg(feature = "physics")]
physics: self.physics,
}
}
pub fn to_new(&self) -> NewObject {
NewObject {
transform: self.transform,
#[cfg(feature = "client")]
appearance: self.appearance.clone(),
#[cfg(feature = "physics")]
physics: self.physics.clone(),
}
}
pub fn copy_new(&mut self, object: NewObject) {
self.transform = object.transform;
#[cfg(feature = "physics")]
{
self.physics = object.physics;
}
#[cfg(feature = "client")]
{
self.appearance = object.appearance;
}
}
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;
}
#[cfg(feature = "client")]
pub fn appearance(&self) -> &Appearance {
&self.appearance
}
pub fn id(&self) -> usize {
self.id
}
pub(crate) fn as_node(&self) -> NObject {
self.node.as_ref().unwrap().upgrade().unwrap()
}
pub fn update(&mut self) {
let node = self.as_node();
let object = &node.lock().object;
self.transform = object.transform;
#[cfg(feature = "client")]
{
self.appearance = object.appearance().clone();
}
}
pub fn sync(&mut self) {
let node = self.as_node().clone();
#[cfg(feature = "physics")]
{
let mut node = node.lock();
let layer = self.layer().clone();
self.parent_transform = self
.physics
.update(
&self.transform,
&node.parent.clone().unwrap().upgrade().unwrap(),
&mut node.rigid_body_parent,
self.id as u128,
layer.physics(),
)
.unwrap();
}
node.lock()
.update_children_position(self.public_transform());
let arc = self.as_node();
let mut object = arc.lock();
object.object = self.clone();
}
}
#[cfg(feature = "physics")]
impl Object {
pub(crate) fn rigidbody_handle(&self) -> Option<rapier2d::dynamics::RigidBodyHandle> {
self.physics.rigid_body_handle
}
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;
}
}