Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add(shared api): set_animation_blend, get_animation_clips, has_animation_clip #362

Merged
merged 3 commits into from
May 4, 2023
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions crates/wasm/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ ambient_core = { path = "../core" }
ambient_ecs = { path = "../ecs" }
ambient_input = { path = "../input" }
ambient_network = { path = "../network" }
ambient_model = { path = "../model" }
ambient_prefab = { path = "../prefab" }
ambient_physics = { path = "../physics" }
ambient_std = { path = "../std" }
Expand Down
27 changes: 27 additions & 0 deletions crates/wasm/src/client/implementation/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,33 @@ impl wit::entity::Host for Bindings {
)
}

fn set_animation_blend(
&mut self,
entity: wit::types::EntityId,
weights: Vec<f32>,
times: Vec<f32>,
absolute_time: bool,
) -> anyhow::Result<()> {
shared::implementation::entity::set_animation_blend(
self.world_mut(),
entity,
&weights,
&times,
absolute_time,
)
}

fn has_animation_clip(&mut self, clip_url: String) -> anyhow::Result<bool> {
shared::implementation::entity::has_animation_clip(self.world_mut(), &clip_url)
}

fn get_animation_clips(
&mut self,
clip_urls: Vec<String>,
) -> anyhow::Result<Vec<wit::entity::AnimationClip>> {
shared::implementation::entity::get_animation_clips(self.world_mut(), &clip_urls)
}

fn exists(&mut self, entity: wit::types::EntityId) -> anyhow::Result<bool> {
shared::implementation::entity::exists(self.world(), entity)
}
Expand Down
28 changes: 28 additions & 0 deletions crates/wasm/src/server/implementation/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,34 @@ impl wit::entity::Host for Bindings {
)
}


fn set_animation_blend(
&mut self,
entity: wit::types::EntityId,
weights: Vec<f32>,
times: Vec<f32>,
absolute_time: bool,
) -> anyhow::Result<()> {
shared::implementation::entity::set_animation_blend(
self.world_mut(),
entity,
&weights,
&times,
absolute_time,
)
}

fn has_animation_clip(&mut self, clip_url: String) -> anyhow::Result<bool> {
shared::implementation::entity::has_animation_clip(self.world_mut(), &clip_url)
}

fn get_animation_clips(
&mut self,
clip_urls: Vec<String>,
) -> anyhow::Result<Vec<wit::entity::AnimationClip>> {
shared::implementation::entity::get_animation_clips(self.world_mut(), &clip_urls)
}

fn exists(&mut self, entity: wit::types::EntityId) -> anyhow::Result<bool> {
shared::implementation::entity::exists(self.world(), entity)
}
Expand Down
115 changes: 112 additions & 3 deletions crates/wasm/src/shared/implementation/entity.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,16 @@
use std::collections::HashSet;
use std::{collections::HashSet, sync::Arc};

use ambient_animation::animation_controller;
use ambient_core::transform::translation;
use ambient_animation::{
animation_controller, AnimationActionTime, AnimationClip, AnimationClipFromUrl,
};
use ambient_core::{asset_cache, transform::translation};
use ambient_ecs::{query as ecs_query, with_component_registry, EntityId, World};
use ambient_model::ModelFromUrl;
use ambient_network::ServerWorldExt;
use ambient_std::{
asset_cache::{AssetCache, AsyncAssetKeyExt},
asset_url::{AnimationAssetType, TypedAssetUrl},
};
use anyhow::Context;

use super::{
Expand Down Expand Up @@ -46,6 +53,108 @@ pub fn set_animation_controller(
)?)
}


pub fn set_animation_blend(
world: &mut World,
entity: wit::types::EntityId,
weights: &[f32],
times: &[f32],
absolute_time: bool,
) -> anyhow::Result<()> {
let controller = world.get_mut(entity.from_bindgen(), animation_controller())?;
for (action, weight) in controller.actions.iter_mut().zip(weights.iter()) {
action.weight = *weight;
}

if absolute_time {
for (action, time) in controller.actions.iter_mut().zip(times.iter()) {
action.time = AnimationActionTime::Absolute { time: *time };
}
} else {
for (action, time) in controller.actions.iter_mut().zip(times.iter()) {
action.time = AnimationActionTime::Percentage { percentage: *time }
}
}
Ok(())
}

fn peek_loaded_clip(
assets: &AssetCache,
clip_url: &str,
) -> anyhow::Result<Option<Arc<AnimationClip>>> {
let asset_url: TypedAssetUrl<AnimationAssetType> =
TypedAssetUrl::parse(clip_url).context("Invalid clip url")?;
let clip_asset_url: TypedAssetUrl<AnimationAssetType> = asset_url
.abs()
.context(format!("Expected absolute url, got: {}", clip_url))?
.into();

if let Some(asset) = ModelFromUrl(
clip_asset_url
.model_crate()
.context("Invalid clip url")?
.model(),
)
.peek(&assets)
{
let _model = asset.context("No such model")?;
} else {
return Ok(None);
}

if let Some(clip) = AnimationClipFromUrl::new(asset_url.unwrap_abs(), true).peek(assets) {
Ok(Some(clip.context("No such clip")?))
} else {
Ok(None)
}
}

pub fn has_animation_clip(world: &mut World, clip_url: &str) -> anyhow::Result<bool> {
let assets = world.resource(asset_cache());
if let Ok(clip) = peek_loaded_clip(assets, clip_url) {
return Ok(clip.is_some());
}

Ok(true)
}

pub fn get_animation_clips(
world: &mut World,
clip_urls: &[String],
) -> anyhow::Result<Vec<wit::entity::AnimationClip>> {
let assets = world.resource(asset_cache());

let mut result: Vec<wit::entity::AnimationClip> = Vec::with_capacity(clip_urls.len());
for clip_url in clip_urls {
let (binders, duration, loaded, error) = match peek_loaded_clip(assets, clip_url) {
Ok(Some(clip)) => {
let binders: Vec<String> = clip
.tracks
.iter()
.map(|x| match &x.target {
ambient_animation::AnimationTarget::BinderId(binder) => binder.clone(),
ambient_animation::AnimationTarget::Entity(_entity) => String::default(),
})
.collect();

let duration = clip.duration();
(binders, duration, true, String::default())
}
Ok(None) => (Vec::default(), 0.0, false, String::default()),
Err(err) => (Vec::default(), 0.0, false, format!("{:?}", err)),
};
result.push(wit::entity::AnimationClip {
binders,
duration,
loaded,
error
});
}

Ok(result)
}


pub fn exists(world: &World, entity: wit::types::EntityId) -> anyhow::Result<bool> {
Ok(world.exists(entity.from_bindgen()))
}
Expand Down
16 changes: 16 additions & 0 deletions crates/wasm/wit/entity.wit
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,22 @@ default interface entity {
apply-base-pose: bool,
}

/// Animation clip data
philpax marked this conversation as resolved.
Show resolved Hide resolved
record animation-clip {
/// BinderId for the animation tracks
binders: list<string>,
/// Duration in seconds
duration: float32,
/// If the asset is loaded (duration will be 0 and binders empty if false)
loaded: bool,
/// Error that occured while fetching asset
error: string,
}

set-animation-blend: func(entity: entity-id, weights: list<float32>, time: list<float32>, absolute-time: bool)
has-animation-clip: func(clip-url: string) -> bool
devjobe marked this conversation as resolved.
Show resolved Hide resolved
get-animation-clips: func(clips: list<string>) -> list<animation-clip>

spawn: func(data: entity-data) -> entity-id
despawn: func(entity: entity-id) -> bool
set-animation-controller: func(entity: entity-id, animation-controller: animation-controller)
Expand Down
17 changes: 16 additions & 1 deletion guest/rust/api_core/src/entity.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ use crate::{
prelude::block_until,
};

pub use wit::entity::{AnimationAction, AnimationController};
pub use wit::entity::{AnimationAction, AnimationController, AnimationClip};

/// Spawns an entity containing the `components`.
///
Expand Down Expand Up @@ -40,6 +40,21 @@ pub fn set_animation_controller(entity: EntityId, controller: AnimationControlle
wit::entity::set_animation_controller(entity.into_bindgen(), controller)
}

/// Set the animation (controller) weights (optional) and times (optional) for `entity`.
pub fn set_animation_blend(entity: EntityId, weights: &[f32], times: &[f32], absolute_time: bool) {
wit::entity::set_animation_blend(entity.into_bindgen(), weights, times, absolute_time)
}

/// Peeks the asset cache for a existing of a animation clip
pub fn has_animation_clip(clip_url: &str) -> bool {
wit::entity::has_animation_clip(clip_url)
}

/// Fetches information about animation clips if loaded
pub fn get_animation_clips(clip_urls: &[&str]) -> Vec<AnimationClip> {
wit::entity::get_animation_clips(clip_urls)
}

/// Checks if the `entity` exists.
pub fn exists(entity: EntityId) -> bool {
wit::entity::exists(entity.into_bindgen())
Expand Down
Loading