mirror of
https://github.com/lisk77/comet.git
synced 2025-12-12 17:18:50 +00:00
Compare commits
5 commits
a01a52766d
...
053f1f48da
| Author | SHA1 | Date | |
|---|---|---|---|
| 053f1f48da | |||
| 64bf88c229 | |||
| 2a37205c22 | |||
| 607bf94f1e | |||
| eced6ddf3f |
14 changed files with 449 additions and 197 deletions
|
|
@ -1,5 +1,7 @@
|
||||||
use comet_colors::{Color as ColorTrait, LinearRgba};
|
use comet_colors::{Color as ColorTrait, LinearRgba};
|
||||||
use comet_ecs::{Camera2D, Component, Entity, Render2D, Scene, Text, Transform2D, Transform3D};
|
use comet_ecs::{
|
||||||
|
Camera2D, Component, Entity, EntityId, Render2D, Scene, Text, Transform2D, Transform3D,
|
||||||
|
};
|
||||||
use comet_input::keyboard::Key;
|
use comet_input::keyboard::Key;
|
||||||
use comet_log::*;
|
use comet_log::*;
|
||||||
use comet_renderer::renderer::Renderer;
|
use comet_renderer::renderer::Renderer;
|
||||||
|
|
@ -163,22 +165,22 @@ impl App {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Creates a new entity and returns its ID.
|
/// Creates a new entity and returns its ID.
|
||||||
pub fn new_entity(&mut self) -> usize {
|
pub fn new_entity(&mut self) -> EntityId {
|
||||||
self.scene.new_entity() as usize
|
self.scene.new_entity()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Deletes an entity by its ID.
|
/// Deletes an entity by its ID.
|
||||||
pub fn delete_entity(&mut self, entity_id: usize) {
|
pub fn delete_entity(&mut self, entity_id: EntityId) {
|
||||||
self.scene.delete_entity(entity_id)
|
self.scene.delete_entity(entity_id)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Gets an immutable reference to an entity by its ID.
|
/// Gets an immutable reference to an entity by its ID.
|
||||||
pub fn get_entity(&self, entity_id: usize) -> Option<&Entity> {
|
pub fn get_entity(&self, entity_id: EntityId) -> Option<&Entity> {
|
||||||
self.scene.get_entity(entity_id)
|
self.scene.get_entity(entity_id)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Gets a mutable reference to an entity by its ID.
|
/// Gets a mutable reference to an entity by its ID.
|
||||||
pub fn get_entity_mut(&mut self, entity_id: usize) -> Option<&mut Entity> {
|
pub fn get_entity_mut(&mut self, entity_id: EntityId) -> Option<&mut Entity> {
|
||||||
self.scene.get_entity_mut(entity_id)
|
self.scene.get_entity_mut(entity_id)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -194,29 +196,29 @@ impl App {
|
||||||
|
|
||||||
/// Adds a component to an entity by its ID and an instance of the component.
|
/// Adds a component to an entity by its ID and an instance of the component.
|
||||||
/// Overwrites the previous component if another component of the same type is added.
|
/// Overwrites the previous component if another component of the same type is added.
|
||||||
pub fn add_component<C: Component>(&mut self, entity_id: usize, component: C) {
|
pub fn add_component<C: Component>(&mut self, entity_id: EntityId, component: C) {
|
||||||
self.scene.add_component(entity_id, component)
|
self.scene.add_component(entity_id, component)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Removes a component from an entity by its ID.
|
/// Removes a component from an entity by its ID.
|
||||||
pub fn remove_component<C: Component>(&mut self, entity_id: usize) {
|
pub fn remove_component<C: Component>(&mut self, entity_id: EntityId) {
|
||||||
self.scene.remove_component::<C>(entity_id)
|
self.scene.remove_component::<C>(entity_id)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns a reference to a component of an entity by its ID.
|
/// Returns a reference to a component of an entity by its ID.
|
||||||
pub fn get_component<C: Component>(&self, entity_id: usize) -> Option<&C> {
|
pub fn get_component<C: Component>(&self, entity_id: EntityId) -> Option<&C> {
|
||||||
self.scene.get_component::<C>(entity_id)
|
self.scene.get_component::<C>(entity_id)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns a mutable reference to a component of an entity by its ID.
|
/// Returns a mutable reference to a component of an entity by its ID.
|
||||||
pub fn get_component_mut<C: Component>(&mut self, entity_id: usize) -> Option<&mut C> {
|
pub fn get_component_mut<C: Component>(&mut self, entity_id: EntityId) -> Option<&mut C> {
|
||||||
self.scene.get_component_mut::<C>(entity_id)
|
self.scene.get_component_mut::<C>(entity_id)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns a list of entities that have the given components.
|
/// Returns a list of entities that have the given components.
|
||||||
/// The amount of queriable components is limited to 3 such that the `Archetype` creation is more efficient.
|
/// The amount of queriable components is limited to 3 such that the `Archetype` creation is more efficient.
|
||||||
/// Otherwise it would be a factorial complexity chaos.
|
/// Otherwise it would be a factorial complexity chaos.
|
||||||
pub fn get_entities_with(&self, components: Vec<TypeId>) -> Vec<usize> {
|
pub fn get_entities_with(&self, components: Vec<TypeId>) -> Vec<EntityId> {
|
||||||
self.scene.get_entities_with(components)
|
self.scene.get_entities_with(components)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -233,7 +235,7 @@ impl App {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns whether an entity has the given component.
|
/// Returns whether an entity has the given component.
|
||||||
pub fn has<C: Component>(&self, entity_id: usize) -> bool {
|
pub fn has<C: Component>(&self, entity_id: EntityId) -> bool {
|
||||||
self.scene.has::<C>(entity_id)
|
self.scene.has::<C>(entity_id)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -243,7 +245,7 @@ impl App {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Spawns a prefab with the given name.
|
/// Spawns a prefab with the given name.
|
||||||
pub fn spawn_prefab(&mut self, name: &str) -> Option<usize> {
|
pub fn spawn_prefab(&mut self, name: &str) -> Option<EntityId> {
|
||||||
self.scene.spawn_prefab(name)
|
self.scene.spawn_prefab(name)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -27,6 +27,13 @@ pub fn component_derive(input: TokenStream) -> TokenStream {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
let clone_fields = fields.iter().map(|field| {
|
||||||
|
let field_name = &field.ident;
|
||||||
|
quote! {
|
||||||
|
#field_name: self.#field_name.clone()
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
let default_fields = if let Data::Struct(data) = &input.data {
|
let default_fields = if let Data::Struct(data) = &input.data {
|
||||||
match &data.fields {
|
match &data.fields {
|
||||||
Fields::Named(fields) => fields
|
Fields::Named(fields) => fields
|
||||||
|
|
@ -83,13 +90,11 @@ pub fn component_derive(input: TokenStream) -> TokenStream {
|
||||||
impl Clone for #name {
|
impl Clone for #name {
|
||||||
fn clone(&self) -> Self {
|
fn clone(&self) -> Self {
|
||||||
Self {
|
Self {
|
||||||
..*self
|
#(#clone_fields),*
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Copy for #name {}
|
|
||||||
|
|
||||||
impl std::fmt::Debug for #name {
|
impl std::fmt::Debug for #name {
|
||||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
f.debug_struct(stringify!(#name))
|
f.debug_struct(stringify!(#name))
|
||||||
|
|
|
||||||
|
|
@ -1,9 +1,9 @@
|
||||||
use comet_structs::ComponentSet;
|
use comet_structs::ComponentSet;
|
||||||
use std::collections::{HashMap, HashSet};
|
use std::collections::HashMap;
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub struct Archetypes {
|
pub struct Archetypes {
|
||||||
archetypes: HashMap<ComponentSet, HashSet<u32>>,
|
archetypes: HashMap<ComponentSet, Vec<u32>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Archetypes {
|
impl Archetypes {
|
||||||
|
|
@ -13,27 +13,31 @@ impl Archetypes {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn component_sets(&self) -> Vec<ComponentSet> {
|
pub fn component_sets(&self) -> impl Iterator<Item = &ComponentSet> {
|
||||||
self.archetypes.keys().cloned().collect()
|
self.archetypes.keys()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn create_archetype(&mut self, components: ComponentSet) {
|
pub fn create_archetype(&mut self, components: ComponentSet) {
|
||||||
self.archetypes.insert(components, HashSet::new());
|
self.archetypes.entry(components).or_insert_with(Vec::new);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_archetype(&self, components: &ComponentSet) -> Option<&HashSet<u32>> {
|
pub fn get_archetype(&self, components: &ComponentSet) -> Option<&Vec<u32>> {
|
||||||
self.archetypes.get(components)
|
self.archetypes.get(components)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn add_entity_to_archetype(&mut self, components: &ComponentSet, entity: u32) {
|
pub fn add_entity_to_archetype(&mut self, components: &ComponentSet, entity: u32) {
|
||||||
if let Some(archetype) = self.archetypes.get_mut(components) {
|
if let Some(archetype) = self.archetypes.get_mut(components) {
|
||||||
archetype.insert(entity);
|
if !archetype.iter().any(|&e| e == entity) {
|
||||||
|
archetype.push(entity);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn remove_entity_from_archetype(&mut self, components: &ComponentSet, entity: u32) {
|
pub fn remove_entity_from_archetype(&mut self, components: &ComponentSet, entity: u32) {
|
||||||
if let Some(archetype) = self.archetypes.get_mut(components) {
|
if let Some(archetype) = self.archetypes.get_mut(components) {
|
||||||
archetype.retain(|&id| id != entity);
|
if let Some(pos) = archetype.iter().position(|&id| id == entity) {
|
||||||
|
archetype.swap_remove(pos);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -5,6 +5,7 @@
|
||||||
// They are intended to work with the base suite of systems provided by the engine.
|
// They are intended to work with the base suite of systems provided by the engine.
|
||||||
use crate::math::{v2, v3};
|
use crate::math::{v2, v3};
|
||||||
use crate::{Entity, Scene};
|
use crate::{Entity, Scene};
|
||||||
|
use comet_log::*;
|
||||||
use comet_colors::Color as ColorTrait;
|
use comet_colors::Color as ColorTrait;
|
||||||
use comet_math::m4;
|
use comet_math::m4;
|
||||||
use component_derive::Component;
|
use component_derive::Component;
|
||||||
|
|
@ -110,10 +111,13 @@ pub struct Transform3D {
|
||||||
// # TRAITS #
|
// # TRAITS #
|
||||||
// ##################################################
|
// ##################################################
|
||||||
|
|
||||||
pub trait Component: Send + Sync + PartialEq + Default + 'static {
|
pub trait Component: Send + Sync + 'static {
|
||||||
fn new() -> Self
|
fn new() -> Self
|
||||||
where
|
where
|
||||||
Self: Sized;
|
Self: Sized + Default,
|
||||||
|
{
|
||||||
|
Default::default()
|
||||||
|
}
|
||||||
|
|
||||||
fn type_id() -> std::any::TypeId {
|
fn type_id() -> std::any::TypeId {
|
||||||
std::any::TypeId::of::<Self>()
|
std::any::TypeId::of::<Self>()
|
||||||
|
|
@ -136,7 +140,7 @@ pub trait Render {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub trait Camera {
|
pub trait Camera {
|
||||||
fn get_visible_entities(&self, camera_position: Position2D, scene: Scene) -> Vec<Entity>;
|
fn get_visible_entities(&self, camera_position: &Position2D, scene: &Scene) -> Vec<Entity>;
|
||||||
fn get_projection_matrix(&self) -> m4;
|
fn get_projection_matrix(&self) -> m4;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -246,8 +250,8 @@ impl Rectangle2D {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn position(&self) -> Position2D {
|
pub fn position(&self) -> &Position2D {
|
||||||
self.position
|
&self.position
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn set_position(&mut self, position: Position2D) {
|
pub fn set_position(&mut self, position: Position2D) {
|
||||||
|
|
@ -417,7 +421,7 @@ impl Camera2D {
|
||||||
self.priority = priority;
|
self.priority = priority;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn in_view_frustum(&self, camera_pos: Position2D, entity: Position2D) -> bool {
|
pub fn in_view_frustum(&self, camera_pos: &Position2D, entity: &Position2D) -> bool {
|
||||||
let left = camera_pos.x() - self.zoom;
|
let left = camera_pos.x() - self.zoom;
|
||||||
let right = camera_pos.x() + self.zoom;
|
let right = camera_pos.x() + self.zoom;
|
||||||
let bottom = camera_pos.y() - self.zoom;
|
let bottom = camera_pos.y() - self.zoom;
|
||||||
|
|
@ -428,18 +432,19 @@ impl Camera2D {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Camera for Camera2D {
|
impl Camera for Camera2D {
|
||||||
fn get_visible_entities(&self, camera_position: Position2D, scene: Scene) -> Vec<Entity> {
|
fn get_visible_entities(&self, camera_position: &Position2D, scene: &Scene) -> Vec<Entity> {
|
||||||
let entities = scene.entities();
|
let entities = scene.entities();
|
||||||
let mut visible_entities = Vec::new();
|
let mut visible_entities = Vec::new();
|
||||||
for entity in entities {
|
for entity in entities {
|
||||||
if self.in_view_frustum(
|
if let Some(ent) = entity.clone() {
|
||||||
camera_position,
|
let id = ent.id();
|
||||||
*scene
|
if let Some(transform) = scene.get_component::<Transform2D>(id) {
|
||||||
.get_component::<Transform2D>(*entity.clone().unwrap().id() as usize)
|
if self.in_view_frustum(camera_position, transform.position()) {
|
||||||
.unwrap()
|
visible_entities.push(ent);
|
||||||
.position(),
|
}
|
||||||
) {
|
} else {
|
||||||
visible_entities.push(entity.clone().unwrap());
|
error!("Entity {} missing Transform2D", id.index);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
visible_entities
|
visible_entities
|
||||||
|
|
@ -498,7 +503,7 @@ impl Text {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn color(&self) -> Color {
|
pub fn color(&self) -> Color {
|
||||||
self.color
|
self.color.clone()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn set_visibility(&mut self, visibility: bool) {
|
pub fn set_visibility(&mut self, visibility: bool) {
|
||||||
|
|
|
||||||
|
|
@ -1,32 +1,46 @@
|
||||||
use bit_set::BitSet;
|
use bit_set::BitSet;
|
||||||
|
|
||||||
|
/// Handle used to reference entities safely. Contains an index into the entity
|
||||||
|
/// storage and a generation counter to detect stale handles.
|
||||||
|
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord)]
|
||||||
|
pub struct EntityId {
|
||||||
|
pub index: u32,
|
||||||
|
pub gen: u32,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Default for EntityId {
|
||||||
|
fn default() -> Self {
|
||||||
|
Self { index: 0, gen: 0 }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq)]
|
#[derive(Debug, Clone, PartialEq)]
|
||||||
pub struct Entity {
|
pub struct Entity {
|
||||||
id: u32,
|
id: EntityId,
|
||||||
components: BitSet
|
components: BitSet,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Entity {
|
impl Entity {
|
||||||
pub(crate) fn new(id: u32) -> Self {
|
pub(crate) fn new(index: u32, gen: u32) -> Self {
|
||||||
Self {
|
Self {
|
||||||
id,
|
id: EntityId { index, gen },
|
||||||
components: BitSet::new()
|
components: BitSet::new(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn id(&self) -> &u32 {
|
pub fn id(&self) -> EntityId {
|
||||||
&self.id
|
self.id
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn add_component(&mut self, component_index: usize) {
|
pub(crate) fn add_component(&mut self, component_index: usize) {
|
||||||
self.components.insert(component_index);
|
self.components.insert(component_index);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn remove_component(&mut self, component_index: usize) {
|
pub(crate) fn remove_component(&mut self, component_index: usize) {
|
||||||
self.components.remove(component_index);
|
self.components.remove(component_index);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn get_components(&self) -> &BitSet {
|
pub(crate) fn get_components(&self) -> &BitSet {
|
||||||
&self.components
|
&self.components
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
use comet_structs::FlatMap;
|
use comet_structs::FlatMap;
|
||||||
|
|
||||||
pub type PrefabFactory = fn(&mut crate::Scene) -> usize;
|
pub type PrefabFactory = fn(&mut crate::Scene) -> crate::EntityId;
|
||||||
|
|
||||||
pub(crate) struct PrefabManager {
|
pub(crate) struct PrefabManager {
|
||||||
pub(crate) prefabs: FlatMap<String, PrefabFactory>,
|
pub(crate) prefabs: FlatMap<String, PrefabFactory>,
|
||||||
|
|
@ -26,8 +26,8 @@ impl PrefabManager {
|
||||||
macro_rules! register_prefab {
|
macro_rules! register_prefab {
|
||||||
($scene:expr, $name:expr, $($component:expr),* $(,)?) => {
|
($scene:expr, $name:expr, $($component:expr),* $(,)?) => {
|
||||||
{
|
{
|
||||||
fn prefab_factory(scene: &mut $crate::Scene) -> usize {
|
fn prefab_factory(scene: &mut $crate::Scene) -> $crate::EntityId {
|
||||||
let entity = scene.new_entity() as usize;
|
let entity = scene.new_entity();
|
||||||
$(
|
$(
|
||||||
scene.add_component(entity, $component);
|
scene.add_component(entity, $component);
|
||||||
)*
|
)*
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
use crate::archetypes::Archetypes;
|
use crate::archetypes::Archetypes;
|
||||||
use crate::prefabs::PrefabManager;
|
use crate::prefabs::PrefabManager;
|
||||||
use crate::{Component, Entity, IdQueue};
|
use crate::{Component, Entity, EntityId, IdQueue};
|
||||||
use comet_log::*;
|
use comet_log::*;
|
||||||
use comet_structs::*;
|
use comet_structs::*;
|
||||||
use std::any::TypeId;
|
use std::any::TypeId;
|
||||||
|
|
@ -8,6 +8,7 @@ use std::any::TypeId;
|
||||||
pub struct Scene {
|
pub struct Scene {
|
||||||
id_queue: IdQueue,
|
id_queue: IdQueue,
|
||||||
next_id: u32,
|
next_id: u32,
|
||||||
|
generations: Vec<u32>,
|
||||||
entities: Vec<Option<Entity>>,
|
entities: Vec<Option<Entity>>,
|
||||||
components: ComponentStorage,
|
components: ComponentStorage,
|
||||||
archetypes: Archetypes,
|
archetypes: Archetypes,
|
||||||
|
|
@ -19,6 +20,7 @@ impl Scene {
|
||||||
Self {
|
Self {
|
||||||
id_queue: IdQueue::new(),
|
id_queue: IdQueue::new(),
|
||||||
next_id: 0,
|
next_id: 0,
|
||||||
|
generations: Vec::new(),
|
||||||
entities: Vec::new(),
|
entities: Vec::new(),
|
||||||
components: ComponentStorage::new(),
|
components: ComponentStorage::new(),
|
||||||
archetypes: Archetypes::new(),
|
archetypes: Archetypes::new(),
|
||||||
|
|
@ -43,48 +45,78 @@ impl Scene {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn is_alive(&self, id: EntityId) -> bool {
|
||||||
|
self.generations
|
||||||
|
.get(id.index as usize)
|
||||||
|
.is_some_and(|g| *g == id.gen)
|
||||||
|
&& self
|
||||||
|
.entities
|
||||||
|
.get(id.index as usize)
|
||||||
|
.is_some_and(|e| e.is_some())
|
||||||
|
}
|
||||||
|
|
||||||
/// Retuns the `Vec` of `Option<Entity>` which contains all the entities in the current Scene.
|
/// Retuns the `Vec` of `Option<Entity>` which contains all the entities in the current Scene.
|
||||||
pub fn entities(&self) -> &Vec<Option<Entity>> {
|
pub fn entities(&self) -> &Vec<Option<Entity>> {
|
||||||
&self.entities
|
&self.entities
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Creates a new entity and returns its ID.
|
/// Creates a new entity and returns its ID.
|
||||||
pub fn new_entity(&mut self) -> u32 {
|
pub fn new_entity(&mut self) -> EntityId {
|
||||||
let id = self.next_id;
|
let index = self.next_id;
|
||||||
if (self.next_id as usize) >= self.entities.len() {
|
let gen = if (index as usize) >= self.generations.len() {
|
||||||
self.entities.push(Some(Entity::new(self.next_id)));
|
self.generations.push(0);
|
||||||
self.get_next_id();
|
0
|
||||||
info!("Created entity! ID: {}", id);
|
} else {
|
||||||
return id;
|
self.generations[index as usize]
|
||||||
|
};
|
||||||
|
|
||||||
|
if (index as usize) >= self.entities.len() {
|
||||||
|
self.entities.push(Some(Entity::new(index, gen)));
|
||||||
|
} else {
|
||||||
|
self.entities[index as usize] = Some(Entity::new(index, gen));
|
||||||
}
|
}
|
||||||
self.entities[self.next_id as usize] = Some(Entity::new(self.next_id));
|
|
||||||
|
let id = EntityId { index, gen };
|
||||||
self.get_next_id();
|
self.get_next_id();
|
||||||
info!("Created entity! ID: {}", id);
|
info!("Created entity! ID: {} (gen {})", id.index, id.gen);
|
||||||
id
|
id
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Gets an immutable reference to an entity by its ID.
|
/// Gets an immutable reference to an entity by its ID.
|
||||||
pub fn get_entity(&self, entity_id: usize) -> Option<&Entity> {
|
pub fn get_entity(&self, entity_id: EntityId) -> Option<&Entity> {
|
||||||
self.entities.get(entity_id).unwrap().as_ref()
|
if !self.is_alive(entity_id) {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
self.entities
|
||||||
|
.get(entity_id.index as usize)
|
||||||
|
.and_then(|e| e.as_ref())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Gets a mutable reference to an entity by its ID.
|
/// Gets a mutable reference to an entity by its ID.
|
||||||
pub fn get_entity_mut(&mut self, entity_id: usize) -> Option<&mut Entity> {
|
pub fn get_entity_mut(&mut self, entity_id: EntityId) -> Option<&mut Entity> {
|
||||||
self.entities.get_mut(entity_id).unwrap().as_mut()
|
if !self.is_alive(entity_id) {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
self.entities
|
||||||
|
.get_mut(entity_id.index as usize)
|
||||||
|
.and_then(|e| e.as_mut())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Deletes an entity by its ID.
|
/// Deletes an entity by its ID.
|
||||||
pub fn delete_entity(&mut self, entity_id: usize) {
|
pub fn delete_entity(&mut self, entity_id: EntityId) {
|
||||||
self.remove_entity_from_archetype_subsets(
|
if !self.is_alive(entity_id) {
|
||||||
entity_id as u32,
|
return;
|
||||||
self.get_component_set(entity_id),
|
|
||||||
);
|
|
||||||
self.entities[entity_id] = None;
|
|
||||||
info!("Deleted entity! ID: {}", entity_id);
|
|
||||||
for (_, value) in self.components.iter_mut() {
|
|
||||||
value.remove::<u8>(entity_id);
|
|
||||||
}
|
}
|
||||||
self.id_queue.sorted_enqueue(entity_id as u32);
|
|
||||||
|
let idx = entity_id.index as usize;
|
||||||
|
self.remove_entity_from_archetype(entity_id.index, self.get_component_set(idx));
|
||||||
|
self.entities[idx] = None;
|
||||||
|
info!("Deleted entity! ID: {}", entity_id.index);
|
||||||
|
self.components.remove_entity(idx);
|
||||||
|
if let Some(gen) = self.generations.get_mut(idx) {
|
||||||
|
*gen = gen.wrapping_add(1);
|
||||||
|
}
|
||||||
|
self.id_queue.sorted_enqueue(entity_id.index);
|
||||||
self.get_next_id();
|
self.get_next_id();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -107,24 +139,6 @@ impl Scene {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_keys(&self, components: ComponentSet) -> Vec<ComponentSet> {
|
|
||||||
let component_sets = self.archetypes.component_sets();
|
|
||||||
component_sets
|
|
||||||
.iter()
|
|
||||||
.enumerate()
|
|
||||||
.filter_map(|(i, &ref elem)| {
|
|
||||||
if elem.is_subset(&components) {
|
|
||||||
Some(i)
|
|
||||||
} else {
|
|
||||||
None
|
|
||||||
}
|
|
||||||
})
|
|
||||||
.collect::<Vec<usize>>()
|
|
||||||
.iter()
|
|
||||||
.map(|index| component_sets[*index].clone())
|
|
||||||
.collect::<Vec<ComponentSet>>()
|
|
||||||
}
|
|
||||||
|
|
||||||
fn add_entity_to_archetype(&mut self, entity_id: u32, components: ComponentSet) {
|
fn add_entity_to_archetype(&mut self, entity_id: u32, components: ComponentSet) {
|
||||||
self.archetypes
|
self.archetypes
|
||||||
.add_entity_to_archetype(&components, entity_id);
|
.add_entity_to_archetype(&components, entity_id);
|
||||||
|
|
@ -135,18 +149,6 @@ impl Scene {
|
||||||
.remove_entity_from_archetype(&components, entity_id);
|
.remove_entity_from_archetype(&components, entity_id);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn remove_entity_from_archetype_subsets(&mut self, entity_id: u32, components: ComponentSet) {
|
|
||||||
let keys = self.get_keys(components);
|
|
||||||
|
|
||||||
for key in keys {
|
|
||||||
self.remove_entity_from_archetype(entity_id, key.clone());
|
|
||||||
if self.archetypes.get_archetype(&key).unwrap().len() == 0 {
|
|
||||||
self.archetypes.remove_archetype(&key);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
info!("Removed entity {} from all archetypes!", entity_id);
|
|
||||||
}
|
|
||||||
|
|
||||||
fn get_component_set(&self, entity_id: usize) -> ComponentSet {
|
fn get_component_set(&self, entity_id: usize) -> ComponentSet {
|
||||||
let components = match self.entities.get(entity_id) {
|
let components = match self.entities.get(entity_id) {
|
||||||
Some(cmp) => match cmp.as_ref() {
|
Some(cmp) => match cmp.as_ref() {
|
||||||
|
|
@ -192,120 +194,152 @@ impl Scene {
|
||||||
|
|
||||||
/// Adds a component to an entity by its ID and an instance of the component.
|
/// Adds a component to an entity by its ID and an instance of the component.
|
||||||
/// Overwrites the previous component if another component of the same type is added.
|
/// Overwrites the previous component if another component of the same type is added.
|
||||||
pub fn add_component<C: Component + 'static>(&mut self, entity_id: usize, component: C) {
|
pub fn add_component<C: Component + 'static>(&mut self, entity_id: EntityId, component: C) {
|
||||||
let old_component_set = self.get_component_set(entity_id);
|
if !self.is_alive(entity_id) {
|
||||||
if !old_component_set.to_vec().is_empty() {
|
error!(
|
||||||
self.remove_entity_from_archetype_subsets(entity_id as u32, old_component_set);
|
"Attempted to add component {} to dead entity {}",
|
||||||
|
C::type_name(),
|
||||||
|
entity_id.index
|
||||||
|
);
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
self.components.set_component(entity_id, component);
|
let old_component_set = self.get_component_set(entity_id.index as usize);
|
||||||
let component_index = self
|
if !old_component_set.to_vec().is_empty() {
|
||||||
|
self.remove_entity_from_archetype(entity_id.index, old_component_set);
|
||||||
|
}
|
||||||
|
|
||||||
|
self.components
|
||||||
|
.set_component(entity_id.index as usize, component);
|
||||||
|
if let Some(component_index) = self
|
||||||
.components
|
.components
|
||||||
.keys()
|
.keys()
|
||||||
.iter_mut()
|
.iter()
|
||||||
.position(|x| *x == C::type_id())
|
.position(|x| *x == C::type_id())
|
||||||
.unwrap();
|
{
|
||||||
self.get_entity_mut(entity_id)
|
if let Some(entity) = self.get_entity_mut(entity_id) {
|
||||||
.unwrap()
|
entity.add_component(component_index);
|
||||||
.add_component(component_index);
|
} else {
|
||||||
|
error!(
|
||||||
|
"Attempted to add component to non-existent entity {}",
|
||||||
|
entity_id.index
|
||||||
|
);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
error!(
|
||||||
|
"Component {} not registered, cannot add to entity {}",
|
||||||
|
C::type_name(),
|
||||||
|
entity_id.index
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
let new_component_set = self.get_component_set(entity_id);
|
let new_component_set = self.get_component_set(entity_id.index as usize);
|
||||||
|
|
||||||
if !self.archetypes.contains_archetype(&new_component_set) {
|
if !self.archetypes.contains_archetype(&new_component_set) {
|
||||||
self.create_archetype(new_component_set.clone());
|
self.create_archetype(new_component_set.clone());
|
||||||
}
|
}
|
||||||
|
|
||||||
let subsets = ComponentSet::compute_subsets_up_to_size_3(new_component_set.to_vec());
|
self.add_entity_to_archetype(entity_id.index, new_component_set);
|
||||||
|
|
||||||
for subset in subsets {
|
|
||||||
if !self.archetypes.contains_archetype(&subset) {
|
|
||||||
self.create_archetype(subset.clone());
|
|
||||||
}
|
|
||||||
|
|
||||||
self.add_entity_to_archetype(entity_id as u32, subset);
|
|
||||||
}
|
|
||||||
|
|
||||||
info!(
|
info!(
|
||||||
"Added component {} to entity {}!",
|
"Added component {} to entity {}!",
|
||||||
C::type_name(),
|
C::type_name(),
|
||||||
entity_id
|
entity_id.index
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn remove_component<C: Component + 'static>(&mut self, entity_id: usize) {
|
pub fn remove_component<C: Component + 'static>(&mut self, entity_id: EntityId) {
|
||||||
let old_component_set = self.get_component_set(entity_id);
|
if !self.is_alive(entity_id) {
|
||||||
self.remove_entity_from_archetype_subsets(entity_id as u32, old_component_set);
|
return;
|
||||||
|
}
|
||||||
|
let old_component_set = self.get_component_set(entity_id.index as usize);
|
||||||
|
self.remove_entity_from_archetype(entity_id.index, old_component_set);
|
||||||
|
|
||||||
self.components.remove_component::<C>(entity_id);
|
self.components
|
||||||
let component_index = self
|
.remove_component::<C>(entity_id.index as usize);
|
||||||
|
if let Some(component_index) = self
|
||||||
.components
|
.components
|
||||||
.keys()
|
.keys()
|
||||||
.iter()
|
.iter()
|
||||||
.position(|x| *x == C::type_id())
|
.position(|x| *x == C::type_id())
|
||||||
.unwrap();
|
{
|
||||||
self.get_entity_mut(entity_id)
|
if let Some(entity) = self.get_entity_mut(entity_id) {
|
||||||
.unwrap()
|
entity.remove_component(component_index);
|
||||||
.remove_component(component_index);
|
}
|
||||||
|
}
|
||||||
|
|
||||||
let new_component_set = self.get_component_set(entity_id);
|
let new_component_set = self.get_component_set(entity_id.index as usize);
|
||||||
|
|
||||||
if !new_component_set.to_vec().is_empty() {
|
if !new_component_set.to_vec().is_empty() {
|
||||||
if !self.archetypes.contains_archetype(&new_component_set) {
|
if !self.archetypes.contains_archetype(&new_component_set) {
|
||||||
self.create_archetype(new_component_set.clone());
|
self.create_archetype(new_component_set.clone());
|
||||||
}
|
}
|
||||||
|
|
||||||
let subsets = ComponentSet::compute_subsets_up_to_size_3(new_component_set.to_vec());
|
self.add_entity_to_archetype(entity_id.index, new_component_set);
|
||||||
|
|
||||||
for subset in subsets {
|
|
||||||
if !self.archetypes.contains_archetype(&subset) {
|
|
||||||
self.create_archetype(subset.clone());
|
|
||||||
}
|
|
||||||
|
|
||||||
self.add_entity_to_archetype(entity_id as u32, subset);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
info!(
|
info!(
|
||||||
"Removed component {} from entity {}!",
|
"Removed component {} from entity {}!",
|
||||||
C::type_name(),
|
C::type_name(),
|
||||||
entity_id
|
entity_id.index
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns a reference to a component of an entity by its ID.
|
/// Returns a reference to a component of an entity by its ID.
|
||||||
pub fn get_component<C: Component + 'static>(&self, entity_id: usize) -> Option<&C> {
|
pub fn get_component<C: Component + 'static>(&self, entity_id: EntityId) -> Option<&C> {
|
||||||
self.components.get_component::<C>(entity_id)
|
if !self.is_alive(entity_id) {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
self.components
|
||||||
|
.get_component::<C>(entity_id.index as usize)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_component_mut<C: Component + 'static>(
|
pub fn get_component_mut<C: Component + 'static>(
|
||||||
&mut self,
|
&mut self,
|
||||||
entity_id: usize,
|
entity_id: EntityId,
|
||||||
) -> Option<&mut C> {
|
) -> Option<&mut C> {
|
||||||
self.components.get_component_mut::<C>(entity_id)
|
if !self.is_alive(entity_id) {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
self.components
|
||||||
|
.get_component_mut::<C>(entity_id.index as usize)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn has<C: Component + 'static>(&self, entity_id: usize) -> bool {
|
pub fn has<C: Component + 'static>(&self, entity_id: EntityId) -> bool {
|
||||||
self.components.get_component::<C>(entity_id).is_some()
|
self.is_alive(entity_id)
|
||||||
|
&& self
|
||||||
|
.components
|
||||||
|
.get_component::<C>(entity_id.index as usize)
|
||||||
|
.is_some()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns a list of entities that have the given components.
|
/// Returns a list of entities that have the given components.
|
||||||
pub fn get_entities_with(&self, components: Vec<TypeId>) -> Vec<usize> {
|
pub fn get_entities_with(&self, components: Vec<TypeId>) -> Vec<EntityId> {
|
||||||
let component_set = ComponentSet::from_ids(components);
|
let component_set = ComponentSet::from_ids(components);
|
||||||
if component_set.size() > 3 {
|
let mut result = Vec::new();
|
||||||
error!("An entity query should only contain at most 3 different components!");
|
|
||||||
return Vec::new();
|
for archetype_set in self.archetypes.component_sets() {
|
||||||
|
if component_set.is_subset(archetype_set) {
|
||||||
|
if let Some(entities) = self.archetypes.get_archetype(archetype_set) {
|
||||||
|
for index in entities.iter() {
|
||||||
|
if let Some(gen) = self.generations.get(*index as usize) {
|
||||||
|
if self
|
||||||
|
.entities
|
||||||
|
.get(*index as usize)
|
||||||
|
.is_some_and(|e| e.is_some())
|
||||||
|
{
|
||||||
|
result.push(EntityId {
|
||||||
|
index: *index,
|
||||||
|
gen: *gen,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if self.archetypes.contains_archetype(&component_set) {
|
|
||||||
return self
|
result
|
||||||
.archetypes
|
|
||||||
.get_archetype(&component_set)
|
|
||||||
.unwrap()
|
|
||||||
.clone()
|
|
||||||
.iter()
|
|
||||||
.map(|x| *x as usize)
|
|
||||||
.collect();
|
|
||||||
}
|
|
||||||
Vec::new()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Deletes all entities that have the given components.
|
/// Deletes all entities that have the given components.
|
||||||
|
|
@ -317,14 +351,31 @@ impl Scene {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Iterates over all entities that have the two given components and calls the given function.
|
/// Iterates over all entities that have the two given components and calls the given function.
|
||||||
pub fn foreach<C: Component, K: Component>(&mut self, func: fn(&mut C, &mut K)) {
|
pub fn foreach<C: Component, K: Component>(&mut self, mut func: impl FnMut(&mut C, &mut K)) {
|
||||||
let entities = self.get_entities_with(vec![C::type_id(), K::type_id()]);
|
if std::any::TypeId::of::<C>() == std::any::TypeId::of::<K>() {
|
||||||
for entity in entities {
|
error!("foreach called with identical component types");
|
||||||
let c_ptr = self.get_component_mut::<C>(entity).unwrap() as *mut C;
|
return;
|
||||||
let k_ptr = self.get_component_mut::<K>(entity).unwrap() as *mut K;
|
}
|
||||||
|
|
||||||
unsafe {
|
let required = ComponentSet::from_ids(vec![C::type_id(), K::type_id()]);
|
||||||
func(&mut *c_ptr, &mut *k_ptr);
|
let (c_set, k_set) = self
|
||||||
|
.components
|
||||||
|
.get_two_mut(&C::type_id(), &K::type_id());
|
||||||
|
|
||||||
|
if let (Some(c_store), Some(k_store)) = (c_set, k_set) {
|
||||||
|
for archetype_set in self.archetypes.component_sets() {
|
||||||
|
if required.is_subset(archetype_set) {
|
||||||
|
if let Some(entities) = self.archetypes.get_archetype(archetype_set) {
|
||||||
|
for &idx in entities {
|
||||||
|
let idx = idx as usize;
|
||||||
|
if let (Some(c), Some(k)) =
|
||||||
|
(c_store.get_mut::<C>(idx), k_store.get_mut::<K>(idx))
|
||||||
|
{
|
||||||
|
func(c, k);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -335,7 +386,7 @@ impl Scene {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Spawns a prefab with the given name.
|
/// Spawns a prefab with the given name.
|
||||||
pub fn spawn_prefab(&mut self, name: &str) -> Option<usize> {
|
pub fn spawn_prefab(&mut self, name: &str) -> Option<EntityId> {
|
||||||
if self.prefabs.has_prefab(name) {
|
if self.prefabs.has_prefab(name) {
|
||||||
if let Some(factory) = self.prefabs.prefabs.get(&name.to_string()) {
|
if let Some(factory) = self.prefabs.prefabs.get(&name.to_string()) {
|
||||||
let factory = *factory; // Copy the function pointer
|
let factory = *factory; // Copy the function pointer
|
||||||
|
|
|
||||||
|
|
@ -18,7 +18,11 @@ impl CameraManager {
|
||||||
self.cameras.get(self.active_camera).unwrap()
|
self.cameras.get(self.active_camera).unwrap()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn update_from_scene(&mut self, scene: &comet_ecs::Scene, camera_entities: Vec<usize>) {
|
pub fn update_from_scene(
|
||||||
|
&mut self,
|
||||||
|
scene: &comet_ecs::Scene,
|
||||||
|
camera_entities: Vec<comet_ecs::EntityId>,
|
||||||
|
) {
|
||||||
self.cameras.clear();
|
self.cameras.clear();
|
||||||
|
|
||||||
let mut cameras_with_priority: Vec<(RenderCamera, u8)> = Vec::new();
|
let mut cameras_with_priority: Vec<(RenderCamera, u8)> = Vec::new();
|
||||||
|
|
|
||||||
|
|
@ -11,6 +11,7 @@ use comet_math::{m4, v2};
|
||||||
use comet_resources::{
|
use comet_resources::{
|
||||||
font::Font, graphic_resource_manager::GraphicResourceManager, texture_atlas::*, Texture, Vertex,
|
font::Font, graphic_resource_manager::GraphicResourceManager, texture_atlas::*, Texture, Vertex,
|
||||||
};
|
};
|
||||||
|
use std::collections::HashSet;
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
use wgpu::util::DeviceExt;
|
use wgpu::util::DeviceExt;
|
||||||
use winit::{dpi::PhysicalSize, window::Window};
|
use winit::{dpi::PhysicalSize, window::Window};
|
||||||
|
|
@ -61,6 +62,7 @@ pub struct Renderer2D<'a> {
|
||||||
resource_manager: GraphicResourceManager,
|
resource_manager: GraphicResourceManager,
|
||||||
camera_manager: CameraManager,
|
camera_manager: CameraManager,
|
||||||
render_passes: Vec<RenderPass>,
|
render_passes: Vec<RenderPass>,
|
||||||
|
cached_render_entities: Vec<comet_ecs::EntityId>,
|
||||||
last_frame_time: std::time::Instant,
|
last_frame_time: std::time::Instant,
|
||||||
delta_time: f32,
|
delta_time: f32,
|
||||||
}
|
}
|
||||||
|
|
@ -744,16 +746,45 @@ impl<'a> Renderer2D<'a> {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut entities = scene.get_entities_with(vec![
|
let unsorted_entities = scene.get_entities_with(vec![
|
||||||
comet_ecs::Transform2D::type_id(),
|
comet_ecs::Transform2D::type_id(),
|
||||||
comet_ecs::Render2D::type_id(),
|
comet_ecs::Render2D::type_id(),
|
||||||
]);
|
]);
|
||||||
|
|
||||||
entities.sort_by(|&a, &b| {
|
let mut dirty_sort = self.cached_render_entities.len() != unsorted_entities.len();
|
||||||
let ra = scene.get_component::<comet_ecs::Render2D>(a).unwrap();
|
|
||||||
let rb = scene.get_component::<comet_ecs::Render2D>(b).unwrap();
|
if !dirty_sort {
|
||||||
ra.draw_index().cmp(&rb.draw_index())
|
let unsorted_set: HashSet<comet_ecs::EntityId> =
|
||||||
});
|
unsorted_entities.iter().copied().collect();
|
||||||
|
dirty_sort = self
|
||||||
|
.cached_render_entities
|
||||||
|
.iter()
|
||||||
|
.any(|e| !unsorted_set.contains(e));
|
||||||
|
}
|
||||||
|
|
||||||
|
if !dirty_sort {
|
||||||
|
dirty_sort = !self.cached_render_entities.windows(2).all(|w| {
|
||||||
|
let a = scene
|
||||||
|
.get_component::<comet_ecs::Render2D>(w[0])
|
||||||
|
.map(|r| r.draw_index());
|
||||||
|
let b = scene
|
||||||
|
.get_component::<comet_ecs::Render2D>(w[1])
|
||||||
|
.map(|r| r.draw_index());
|
||||||
|
matches!((a, b), (Some(da), Some(db)) if da <= db)
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
if dirty_sort {
|
||||||
|
let mut entities = unsorted_entities;
|
||||||
|
entities.sort_by(|&a, &b| {
|
||||||
|
let ra = scene.get_component::<comet_ecs::Render2D>(a).unwrap();
|
||||||
|
let rb = scene.get_component::<comet_ecs::Render2D>(b).unwrap();
|
||||||
|
ra.draw_index().cmp(&rb.draw_index())
|
||||||
|
});
|
||||||
|
self.cached_render_entities = entities;
|
||||||
|
}
|
||||||
|
|
||||||
|
let entities = self.cached_render_entities.clone();
|
||||||
|
|
||||||
let texts = scene.get_entities_with(vec![
|
let texts = scene.get_entities_with(vec![
|
||||||
comet_ecs::Transform2D::type_id(),
|
comet_ecs::Transform2D::type_id(),
|
||||||
|
|
@ -922,7 +953,7 @@ impl<'a> Renderer2D<'a> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn setup_camera(&mut self, scene: &comet_ecs::Scene, cameras: Vec<usize>) {
|
fn setup_camera(&mut self, scene: &comet_ecs::Scene, cameras: Vec<comet_ecs::EntityId>) {
|
||||||
if cameras.is_empty() {
|
if cameras.is_empty() {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
@ -1012,6 +1043,7 @@ impl<'a> Renderer for Renderer2D<'a> {
|
||||||
resource_manager: GraphicResourceManager::new(),
|
resource_manager: GraphicResourceManager::new(),
|
||||||
camera_manager: CameraManager::new(),
|
camera_manager: CameraManager::new(),
|
||||||
render_passes: Vec::new(),
|
render_passes: Vec::new(),
|
||||||
|
cached_render_entities: Vec::new(),
|
||||||
last_frame_time: std::time::Instant::now(),
|
last_frame_time: std::time::Instant::now(),
|
||||||
delta_time: 0.0,
|
delta_time: 0.0,
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -272,6 +272,33 @@ impl Column {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Remove an element without knowing its concrete type. Drops in place.
|
||||||
|
pub fn remove_any(&mut self, index: usize) {
|
||||||
|
if index >= self.data.len() {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
unsafe {
|
||||||
|
let ptr = self.data.swap_remove_and_forget_unchecked(index);
|
||||||
|
(self.data.drop)(ptr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Overwrites an existing element in place, dropping the previous value.
|
||||||
|
pub fn set<T: 'static>(&mut self, index: usize, item: T) -> Option<()> {
|
||||||
|
assert_eq!(TypeId::of::<T>(), TypeId::of::<T>(), "Type mismatch");
|
||||||
|
if index >= self.data.len() {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
|
||||||
|
unsafe {
|
||||||
|
let ptr = self.data.get_unchecked_mut(index) as *mut T;
|
||||||
|
ptr::drop_in_place(ptr);
|
||||||
|
ptr::write(ptr, item);
|
||||||
|
}
|
||||||
|
|
||||||
|
Some(())
|
||||||
|
}
|
||||||
|
|
||||||
pub fn swap(&mut self, index1: usize, index2: usize) {
|
pub fn swap(&mut self, index1: usize, index2: usize) {
|
||||||
assert!(
|
assert!(
|
||||||
index1 < self.data.len() && index2 < self.data.len(),
|
index1 < self.data.len() && index2 < self.data.len(),
|
||||||
|
|
|
||||||
|
|
@ -55,4 +55,11 @@ impl ComponentStorage {
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Removes all components belonging to the given entity index.
|
||||||
|
pub fn remove_entity(&mut self, index: usize) {
|
||||||
|
for (_, value) in self.iter_mut() {
|
||||||
|
value.remove_any(index);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -67,6 +67,10 @@ impl ComponentSet {
|
||||||
self.set.is_subset(&other.set)
|
self.set.is_subset(&other.set)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn is_superset(&self, other: &ComponentSet) -> bool {
|
||||||
|
self.set.is_superset(&other.set)
|
||||||
|
}
|
||||||
|
|
||||||
pub fn to_vec(&self) -> Vec<TypeId> {
|
pub fn to_vec(&self) -> Vec<TypeId> {
|
||||||
self.set.iter().cloned().collect()
|
self.set.iter().cloned().collect()
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -44,6 +44,39 @@ impl<K: PartialEq + Clone, V: Clone> FlatMap<K, V> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn get_two_mut(&mut self, a: &K, b: &K) -> (Option<&mut V>, Option<&mut V>) {
|
||||||
|
if a == b {
|
||||||
|
let first = self.get_mut(a);
|
||||||
|
return (first, None);
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut first_index = None;
|
||||||
|
let mut second_index = None;
|
||||||
|
|
||||||
|
for (idx, (key, _)) in self.map.iter().enumerate() {
|
||||||
|
if key == a {
|
||||||
|
first_index = Some(idx);
|
||||||
|
} else if key == b {
|
||||||
|
second_index = Some(idx);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
match (first_index, second_index) {
|
||||||
|
(Some(i), Some(j)) => {
|
||||||
|
if i < j {
|
||||||
|
let (left, right) = self.map.split_at_mut(j);
|
||||||
|
(Some(&mut left[i].1), Some(&mut right[0].1))
|
||||||
|
} else {
|
||||||
|
let (left, right) = self.map.split_at_mut(i);
|
||||||
|
(Some(&mut right[0].1), Some(&mut left[j].1))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
(Some(i), None) => (self.map.get_mut(i).map(|pair| &mut pair.1), None),
|
||||||
|
(None, Some(j)) => (None, self.map.get_mut(j).map(|pair| &mut pair.1)),
|
||||||
|
_ => (None, None),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub fn contains(&self, key: &K) -> bool {
|
pub fn contains(&self, key: &K) -> bool {
|
||||||
self.map.iter().any(|node| node.0 == *key)
|
self.map.iter().any(|node| node.0 == *key)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -28,6 +28,12 @@ impl SparseSet {
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(page_vec) = &mut self.sparse[page] {
|
if let Some(page_vec) = &mut self.sparse[page] {
|
||||||
|
// If there is already a mapping, overwrite the existing dense value instead of pushing.
|
||||||
|
if let Some(sparse_index) = page_vec[index % self.page_size] {
|
||||||
|
let _ = self.dense.set::<T>(sparse_index, value);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
page_vec[index % self.page_size] = Some(self.dense.data.len());
|
page_vec[index % self.page_size] = Some(self.dense.data.len());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -69,6 +75,64 @@ impl SparseSet {
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Removes an element by external index without knowing its type. Returns true if something was removed.
|
||||||
|
pub fn remove_any(&mut self, index: usize) -> bool {
|
||||||
|
if let Some(page_vec) = self
|
||||||
|
.sparse
|
||||||
|
.get(index / self.page_size)
|
||||||
|
.and_then(|x| x.as_ref())
|
||||||
|
{
|
||||||
|
if let Some(sparse_index) = page_vec
|
||||||
|
.get(index % self.page_size)
|
||||||
|
.and_then(|x| x.as_ref())
|
||||||
|
{
|
||||||
|
let dense_index = *sparse_index;
|
||||||
|
let last_dense_index = self.dense.data.len() - 1;
|
||||||
|
|
||||||
|
if dense_index != last_dense_index {
|
||||||
|
if let Some(ext_index) = self.find_external_index(last_dense_index) {
|
||||||
|
if let Some(page_vec) = self
|
||||||
|
.sparse
|
||||||
|
.get_mut(ext_index / self.page_size)
|
||||||
|
.and_then(|x| x.as_mut())
|
||||||
|
{
|
||||||
|
page_vec[ext_index % self.page_size] = Some(dense_index);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
self.dense.swap(dense_index, last_dense_index);
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Some(page_vec) = self
|
||||||
|
.sparse
|
||||||
|
.get_mut(index / self.page_size)
|
||||||
|
.and_then(|x| x.as_mut())
|
||||||
|
{
|
||||||
|
page_vec[index % self.page_size] = None;
|
||||||
|
}
|
||||||
|
|
||||||
|
self.dense.remove_any(dense_index);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
false
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Finds the external index that maps to a given dense index.
|
||||||
|
fn find_external_index(&self, dense_index: usize) -> Option<usize> {
|
||||||
|
for (page_idx, page_opt) in self.sparse.iter().enumerate() {
|
||||||
|
if let Some(page) = page_opt {
|
||||||
|
for (offset, entry) in page.iter().enumerate() {
|
||||||
|
if let Some(idx) = entry {
|
||||||
|
if *idx == dense_index {
|
||||||
|
return Some(page_idx * self.page_size + offset);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
None
|
||||||
|
}
|
||||||
|
|
||||||
pub fn get<T: 'static>(&self, index: usize) -> Option<&T> {
|
pub fn get<T: 'static>(&self, index: usize) -> Option<&T> {
|
||||||
if let Some(page_vec) = self
|
if let Some(page_vec) = self
|
||||||
.sparse
|
.sparse
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue