Skip to content

Commit 216d2c4

Browse files
authored
resolve issue #1499 (more constructors and methods for ArmatureMask) (#1504)
1 parent 1296eb2 commit 216d2c4

File tree

2 files changed

+222
-0
lines changed

2 files changed

+222
-0
lines changed

jme3-core/src/main/java/com/jme3/anim/ArmatureMask.java

Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,57 @@ public class ArmatureMask implements AnimationMask {
66

77
final private BitSet affectedJoints = new BitSet();
88

9+
/**
10+
* Instantiate a mask that affects no joints.
11+
*/
12+
public ArmatureMask() {
13+
// do nothing
14+
}
15+
16+
/**
17+
* Instantiate a mask that affects all joints in the specified Armature.
18+
*
19+
* @param armature the Armature containing the joints (not null, unaffected)
20+
*/
21+
public ArmatureMask(Armature armature) {
22+
int numJoints = armature.getJointCount();
23+
affectedJoints.set(0, numJoints);
24+
}
25+
26+
/**
27+
* Remove all joints affected by the specified ArmatureMask.
28+
*
29+
* @param removeMask the set of joints to remove (not null, unaffected)
30+
* @return this
31+
*/
32+
public ArmatureMask remove(ArmatureMask removeMask) {
33+
BitSet removeBits = removeMask.getAffectedJoints();
34+
affectedJoints.andNot(removeBits);
35+
36+
return this;
37+
}
38+
39+
private BitSet getAffectedJoints() {
40+
return affectedJoints;
41+
}
42+
43+
/**
44+
* Remove the named joints.
45+
*
46+
* @param armature the Armature containing the joints (not null, unaffected)
47+
* @param jointNames the names of the joints to be removed
48+
* @return this
49+
*/
50+
public ArmatureMask removeJoints(Armature armature, String... jointNames) {
51+
for (String jointName : jointNames) {
52+
Joint joint = findJoint(armature, jointName);
53+
int jointId = joint.getId();
54+
affectedJoints.clear(jointId);
55+
}
56+
57+
return this;
58+
}
59+
960
@Override
1061
public boolean contains(Object target) {
1162
return affectedJoints.get(((Joint) target).getId());
@@ -65,4 +116,33 @@ private void recurseAddJoint(Joint joint) {
65116
}
66117
}
67118

119+
/**
120+
* Add the specified Joint and all its ancestors.
121+
*
122+
* @param start the starting point (may be null, unaffected)
123+
* @return this
124+
*/
125+
public ArmatureMask addAncestors(Joint start) {
126+
for (Joint cur = start; cur != null; cur = cur.getParent()) {
127+
int jointId = cur.getId();
128+
affectedJoints.set(jointId);
129+
}
130+
131+
return this;
132+
}
133+
134+
/**
135+
* Remove the specified Joint and all its ancestors.
136+
*
137+
* @param start the starting point (may be null, unaffected)
138+
* @return this
139+
*/
140+
public ArmatureMask removeAncestors(Joint start) {
141+
for (Joint cur = start; cur != null; cur = cur.getParent()) {
142+
int jointId = cur.getId();
143+
affectedJoints.clear(jointId);
144+
}
145+
146+
return this;
147+
}
68148
}
Lines changed: 142 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,142 @@
1+
/*
2+
* Copyright (c) 2021 jMonkeyEngine
3+
* All rights reserved.
4+
*
5+
* Redistribution and use in source and binary forms, with or without
6+
* modification, are permitted provided that the following conditions are
7+
* met:
8+
*
9+
* * Redistributions of source code must retain the above copyright
10+
* notice, this list of conditions and the following disclaimer.
11+
*
12+
* * Redistributions in binary form must reproduce the above copyright
13+
* notice, this list of conditions and the following disclaimer in the
14+
* documentation and/or other materials provided with the distribution.
15+
*
16+
* * Neither the name of 'jMonkeyEngine' nor the names of its contributors
17+
* may be used to endorse or promote products derived from this software
18+
* without specific prior written permission.
19+
*
20+
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21+
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
22+
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
23+
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
24+
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
25+
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
26+
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
27+
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
28+
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
29+
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
30+
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31+
*/
32+
package com.jme3.anim;
33+
34+
import org.junit.Assert;
35+
import org.junit.Test;
36+
37+
/**
38+
* Test constructors and modification methods of the ArmatureMask class.
39+
*/
40+
public class ArmatureMaskTest {
41+
42+
final private Joint j0 = createJoint("j0", 0); // leaf
43+
final private Joint j1 = createJoint("j1", 1); // leaf
44+
final private Joint j2 = createJoint("j2", 2, j0, j1);
45+
final private Joint j3 = createJoint("j3", 3, j2); // root
46+
final private Joint j4 = createJoint("j4", 4); // leaf
47+
final private Joint j5 = createJoint("j5", 5, j4); // root
48+
final private Joint j6 = createJoint("j6", 6); // root and leaf
49+
final private Joint[] jointList = {j0, j1, j2, j3, j4, j5, j6};
50+
final private Armature arm = new Armature(jointList);
51+
52+
private Joint createJoint(String name, int id, Joint... children) {
53+
Joint result = new Joint(name);
54+
result.setId(id);
55+
for (Joint child : children) {
56+
result.addChild(child);
57+
}
58+
return result;
59+
}
60+
61+
/**
62+
* Test varous ways to instantiate a mask that affects all joints.
63+
*/
64+
@Test
65+
public void testMaskAll() {
66+
ArmatureMask[] maskArray = new ArmatureMask[5];
67+
maskArray[0] = new ArmatureMask(arm);
68+
maskArray[1] = ArmatureMask.createMask(arm,
69+
"j0", "j1", "j2", "j3", "j4", "j5", "j6");
70+
71+
maskArray[2] = ArmatureMask.createMask(arm, "j3");
72+
maskArray[2].addFromJoint(arm, "j5");
73+
maskArray[2].addFromJoint(arm, "j6");
74+
75+
maskArray[3] = ArmatureMask.createMask(arm, "j3")
76+
.addAncestors(j4)
77+
.addAncestors(j6);
78+
79+
maskArray[4] = ArmatureMask.createMask(arm, "j3");
80+
maskArray[4].addBones(arm, "j4", "j5", "j6");
81+
82+
for (ArmatureMask testMask : maskArray) {
83+
for (Joint testJoint : jointList) {
84+
Assert.assertTrue(testMask.contains(testJoint));
85+
}
86+
}
87+
}
88+
89+
/**
90+
* Instantiate masks that affect no joints.
91+
*/
92+
@Test
93+
public void testMaskNone() {
94+
ArmatureMask[] maskArray = new ArmatureMask[4];
95+
maskArray[0] = new ArmatureMask();
96+
maskArray[1] = ArmatureMask.createMask(arm);
97+
98+
maskArray[2] = ArmatureMask.createMask(arm, "j2")
99+
.removeAncestors(j0)
100+
.removeAncestors(j1);
101+
102+
maskArray[3] = ArmatureMask.createMask(arm, "j0", "j1")
103+
.removeJoints(arm, "j0", "j1");
104+
105+
for (ArmatureMask testMask : maskArray) {
106+
for (Joint testJoint : jointList) {
107+
Assert.assertFalse(testMask.contains(testJoint));
108+
}
109+
}
110+
}
111+
112+
/**
113+
* Instantiate masks that affect only j1 and j2.
114+
*/
115+
@Test
116+
public void testMask12() {
117+
ArmatureMask[] maskArray = new ArmatureMask[4];
118+
maskArray[0] = new ArmatureMask();
119+
maskArray[0].addBones(arm, "j1", "j2");
120+
121+
maskArray[1] = ArmatureMask.createMask(arm, "j3")
122+
.removeJoints(arm, "j0", "j3");
123+
124+
maskArray[2] = new ArmatureMask()
125+
.addAncestors(j1)
126+
.removeAncestors(j3);
127+
128+
ArmatureMask mask0 = ArmatureMask.createMask(arm, "j0");
129+
maskArray[3] = ArmatureMask.createMask(arm, "j2")
130+
.remove(mask0);
131+
132+
for (ArmatureMask testMask : maskArray) {
133+
for (Joint testJoint : jointList) {
134+
if (testJoint == j1 || testJoint == j2) {
135+
Assert.assertTrue(testMask.contains(testJoint));
136+
} else {
137+
Assert.assertFalse(testMask.contains(testJoint));
138+
}
139+
}
140+
}
141+
}
142+
}

0 commit comments

Comments
 (0)