From 48eabb48531aa14aefbd29c63eed9e44241132aa Mon Sep 17 00:00:00 2001 From: diarmidmackenzie Date: Mon, 13 Feb 2023 10:40:28 +0000 Subject: [PATCH 1/5] Revert "Only one clip at a time" This reverts commit 0a7f8a03a2659af03d13163f0b472461e75c968e. --- examples/animation-controls/animation-controls.js | 3 ++- examples/animation-controls/index.html | 14 ++++++-------- 2 files changed, 8 insertions(+), 9 deletions(-) diff --git a/examples/animation-controls/animation-controls.js b/examples/animation-controls/animation-controls.js index 53996c5b..c79a2551 100644 --- a/examples/animation-controls/animation-controls.js +++ b/examples/animation-controls/animation-controls.js @@ -18,7 +18,8 @@ updateAnimationMixer = () => { el = document.getElementById(name[0]) if (el.checked) { - data.clip = name[1] + if (data.clip) data.clip += "*" + data.clip += name[1] } }) diff --git a/examples/animation-controls/index.html b/examples/animation-controls/index.html index d34f1bab..1ce4507e 100644 --- a/examples/animation-controls/index.html +++ b/examples/animation-controls/index.html @@ -14,20 +14,18 @@
Controls
- - - + - + - + - + - + - + From 3c2a1540229e07de9079f2fd7b2182f1c8028438 Mon Sep 17 00:00:00 2001 From: diarmidmackenzie Date: Mon, 13 Feb 2023 10:52:31 +0000 Subject: [PATCH 2/5] Support for multiple clips using regular expressions --- examples/animation-controls/animation-controls.js | 10 +++++++--- examples/bundle.js | 3 ++- src/loaders/README.md | 5 ++--- src/loaders/animation-mixer.js | 3 ++- 4 files changed, 13 insertions(+), 8 deletions(-) diff --git a/examples/animation-controls/animation-controls.js b/examples/animation-controls/animation-controls.js index c79a2551..aff0c8a4 100644 --- a/examples/animation-controls/animation-controls.js +++ b/examples/animation-controls/animation-controls.js @@ -12,14 +12,18 @@ animationNames = { updateAnimationMixer = () => { - const data = {} + const data = {useRegExp: true} data.clip = "none" Object.entries(animationNames).forEach((name) => { + const regExpEscape = (s) => { + return s.replace(/[|\\{}()[\]^$+*?.]/g, '\\$&'); + } + el = document.getElementById(name[0]) if (el.checked) { - if (data.clip) data.clip += "*" - data.clip += name[1] + if (data.clip) data.clip += "|" + data.clip += regExpEscape(name[1]) } }) diff --git a/examples/bundle.js b/examples/bundle.js index 17854e2b..ba5f285c 100644 --- a/examples/bundle.js +++ b/examples/bundle.js @@ -44864,6 +44864,7 @@ var LoopMode = { module.exports = AFRAME.registerComponent('animation-mixer', { schema: { clip: { default: '*' }, + useRegExp: { default: false }, duration: { default: 0 }, clampWhenFinished: { default: false, type: 'boolean' }, crossFadeDuration: { default: 0 }, @@ -44958,7 +44959,7 @@ module.exports = AFRAME.registerComponent('animation-mixer', { if (!clips.length) return; - var re = wildcardToRegExp(data.clip); + var re = data.useRegExp ? data.clip : wildcardToRegExp(data.clip); for (var clip, i = 0; clip = clips[i]; i++) { if (clip.name.match(re)) { diff --git a/src/loaders/README.md b/src/loaders/README.md index f70dc0f1..8eb54ba9 100644 --- a/src/loaders/README.md +++ b/src/loaders/README.md @@ -33,6 +33,7 @@ an animation and its duration: | Property | Default | Description | |-------------------|----------|-----------------------------------------------------------| | clip | * | Name of the animation clip(s) to play. Accepts wildcards. | +| useRegExp | false | If true, interpret the `clip` string as a regular expression. If false, it is treated as a literal string, except for the * character, which is treated as a variable-length wildcard. | | duration | 0 | Duration of the animation, in seconds. 0 indicates automatic calculation based on loop & repetitions settings. | | crossFadeDuration | 0 | Duration of cross-fades between clips, in seconds. | | loop | repeat | `once`, `repeat`, or `pingpong`. In `repeat` and `pingpong` modes, the clip plays once plus the specified number of repetitions. For `pingpong`, every second clip plays in reverse. | @@ -41,9 +42,7 @@ an animation and its duration: | clampWhenFinished | false | If true, halts the animation at the last frame. | | startAt | 0 | Configures the animation clip to begin at a specific start time (in milliseconds). This is useful when you need to jump to an exact time in an animation. The input parameter will be scaled by the mixer's timeScale. Negative values will result in a pause before the animation begins. | -A list of available animations can usually be found by inspecting the model file or its documentation. All animations will play by default. To play only a specific set of animations, use wildcards: `animation-mixer="clip: run_*"`. - -There is no provided syntax to specify multiple animations, except via the * wildcard. For example: `animation-mixer="clip: run,walk"` will match neither `run` nor `walk`, and would only match a clip named `run,walk`. +A list of available animations can usually be found by inspecting the model file or its documentation. All animations will play by default. To play only a specific set of animations, use wildcards: `animation-mixer="clip: run_*"`, or use the useRegExp flag to enable full regular expression matching, e.g. `animation-mixer="useRegExp: true; clip: run|walk"`. ### Animation Events diff --git a/src/loaders/animation-mixer.js b/src/loaders/animation-mixer.js index d9a2211c..b04e0bdf 100644 --- a/src/loaders/animation-mixer.js +++ b/src/loaders/animation-mixer.js @@ -14,6 +14,7 @@ const LoopMode = { module.exports = AFRAME.registerComponent('animation-mixer', { schema: { clip: { default: '*' }, + useRegExp: {default: false}, duration: { default: 0 }, clampWhenFinished: { default: false, type: 'boolean' }, crossFadeDuration: { default: 0 }, @@ -108,7 +109,7 @@ module.exports = AFRAME.registerComponent('animation-mixer', { if (!clips.length) return; - const re = wildcardToRegExp(data.clip); + const re = data.useRegExp ? data.clip : wildcardToRegExp(data.clip); for (let clip, i = 0; (clip = clips[i]); i++) { if (clip.name.match(re)) { From f1a20697a7741784ef116844e8086efc35d3e208 Mon Sep 17 00:00:00 2001 From: diarmidmackenzie Date: Tue, 14 Feb 2023 15:33:37 +0000 Subject: [PATCH 3/5] Code review feedback --- .../animation-controls/animation-controls.js | 35 +++++++------------ 1 file changed, 12 insertions(+), 23 deletions(-) diff --git a/examples/animation-controls/animation-controls.js b/examples/animation-controls/animation-controls.js index aff0c8a4..7d0aec66 100644 --- a/examples/animation-controls/animation-controls.js +++ b/examples/animation-controls/animation-controls.js @@ -1,5 +1,5 @@ -animationNames = { +const animationNames = { attack: 'Armature|TRex_Attack', death: 'Armature|TRex_Death', idle: 'Armature|TRex_Idle', @@ -8,8 +8,6 @@ animationNames = { walk: 'Armature|TRex_Walk', }; - - updateAnimationMixer = () => { const data = {useRegExp: true} @@ -20,49 +18,40 @@ updateAnimationMixer = () => { return s.replace(/[|\\{}()[\]^$+*?.]/g, '\\$&'); } - el = document.getElementById(name[0]) + const el = document.getElementById(name[0]) if (el.checked) { if (data.clip) data.clip += "|" data.clip += regExpEscape(name[1]) } }) - const getValue = (key) => { + const keys = ["duration", + "clampWhenFinished", + "crossFadeDuration", + "loop", + "repetitions", + "timeScale", + "startAt"] + keys.forEach((key) => { const value = document.getElementById(key).value if (AFRAME.components['animation-mixer'].schema[key].type === 'number' && isNaN(value)) { return; } data[key] = value - } - getValue("duration") - getValue("clampWhenFinished") - getValue("crossFadeDuration") - getValue("loop") - getValue("repetitions") - getValue("timeScale") - getValue("startAt") + }) const target = document.getElementById("trex1") target.setAttribute("animation-mixer", data) } - document.addEventListener('DOMContentLoaded', () => { - const inputs = document.querySelectorAll("input") + const inputs = document.querySelectorAll("input, select") inputs.forEach((input) => { input.addEventListener("change", updateAnimationMixer) }) - const selectors = document.querySelectorAll("select") - - selectors.forEach((selector) => { - selector.addEventListener("change", updateAnimationMixer) - }) - updateAnimationMixer() }) - - From 6b5ac7d19718cecf94f20cec3abd729cefe70d9e Mon Sep 17 00:00:00 2001 From: diarmidmackenzie Date: Tue, 14 Feb 2023 16:00:45 +0000 Subject: [PATCH 4/5] Revert "Code review feedback" This reverts commit f1a20697a7741784ef116844e8086efc35d3e208. --- .../animation-controls/animation-controls.js | 35 ++++++++++++------- 1 file changed, 23 insertions(+), 12 deletions(-) diff --git a/examples/animation-controls/animation-controls.js b/examples/animation-controls/animation-controls.js index 7d0aec66..aff0c8a4 100644 --- a/examples/animation-controls/animation-controls.js +++ b/examples/animation-controls/animation-controls.js @@ -1,5 +1,5 @@ -const animationNames = { +animationNames = { attack: 'Armature|TRex_Attack', death: 'Armature|TRex_Death', idle: 'Armature|TRex_Idle', @@ -8,6 +8,8 @@ const animationNames = { walk: 'Armature|TRex_Walk', }; + + updateAnimationMixer = () => { const data = {useRegExp: true} @@ -18,40 +20,49 @@ updateAnimationMixer = () => { return s.replace(/[|\\{}()[\]^$+*?.]/g, '\\$&'); } - const el = document.getElementById(name[0]) + el = document.getElementById(name[0]) if (el.checked) { if (data.clip) data.clip += "|" data.clip += regExpEscape(name[1]) } }) - const keys = ["duration", - "clampWhenFinished", - "crossFadeDuration", - "loop", - "repetitions", - "timeScale", - "startAt"] - keys.forEach((key) => { + const getValue = (key) => { const value = document.getElementById(key).value if (AFRAME.components['animation-mixer'].schema[key].type === 'number' && isNaN(value)) { return; } data[key] = value - }) + } + getValue("duration") + getValue("clampWhenFinished") + getValue("crossFadeDuration") + getValue("loop") + getValue("repetitions") + getValue("timeScale") + getValue("startAt") const target = document.getElementById("trex1") target.setAttribute("animation-mixer", data) } + document.addEventListener('DOMContentLoaded', () => { - const inputs = document.querySelectorAll("input, select") + const inputs = document.querySelectorAll("input") inputs.forEach((input) => { input.addEventListener("change", updateAnimationMixer) }) + const selectors = document.querySelectorAll("select") + + selectors.forEach((selector) => { + selector.addEventListener("change", updateAnimationMixer) + }) + updateAnimationMixer() }) + + From 27cc6f6e88f37584127b8845c3aabacc6f2d43e3 Mon Sep 17 00:00:00 2001 From: diarmidmackenzie Date: Sun, 19 Nov 2023 15:57:00 +0000 Subject: [PATCH 5/5] Use single quotes --- examples/animation-controls/animation-controls.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/animation-controls/animation-controls.js b/examples/animation-controls/animation-controls.js index 72872933..0c9400f3 100644 --- a/examples/animation-controls/animation-controls.js +++ b/examples/animation-controls/animation-controls.js @@ -11,7 +11,7 @@ const animationNames = { updateAnimationMixer = () => { const data = {useRegExp: true} - data.clip = "none" + data.clip = 'none' Object.entries(animationNames).forEach((name) => { const regExpEscape = (s) => {