📄 keyframecontroller.java
字号:
dataCopy.setColorBuffer(dcColors);
}
dcColors.put(mmColors);
dcColors.flip();
}
if (morphMesh.getVertexBuffer() != null) {
FloatBuffer dcVerts = dataCopy.getVertexBuffer();
if (dcVerts != null)
dcVerts.clear();
FloatBuffer mmVerts = morphMesh.getVertexBuffer();
mmVerts.clear();
if (dcVerts == null || dcVerts.capacity() != mmVerts.capacity()) {
dcVerts = BufferUtils.createFloatBuffer(mmVerts.capacity());
dcVerts.clear();
dataCopy.setVertexBuffer(dcVerts);
}
dcVerts.put(mmVerts);
dcVerts.flip();
}
if (morphMesh.getNormalBuffer() != null) {
FloatBuffer dcNorms = dataCopy.getNormalBuffer();
if (dcNorms != null)
dcNorms.clear();
FloatBuffer mmNorms = morphMesh.getNormalBuffer();
mmNorms.clear();
if (dcNorms == null || dcNorms.capacity() != mmNorms.capacity()) {
dcNorms = BufferUtils.createFloatBuffer(mmNorms.capacity());
dcNorms.clear();
dataCopy.setNormalBuffer(dcNorms);
}
dcNorms.put(mmNorms);
dcNorms.flip();
}
if (morphMesh.getIndexBuffer() != null) {
IntBuffer dcInds = dataCopy.getIndexBuffer();
if (dcInds != null)
dcInds.clear();
IntBuffer mmInds = morphMesh.getIndexBuffer();
mmInds.clear();
if (dcInds == null || dcInds.capacity() != mmInds.capacity()) {
dcInds = BufferUtils.createIntBuffer(mmInds.capacity());
dcInds.clear();
dataCopy.setIndexBuffer(dcInds);
}
dcInds.put(mmInds);
dcInds.flip();
}
if (morphMesh.getTextureCoords(0) != null) {
FloatBuffer dcTexs = dataCopy.getTextureCoords(0).coords;
if (dcTexs != null)
dcTexs.clear();
FloatBuffer mmTexs = morphMesh.getTextureCoords(0).coords;
mmTexs.clear();
if (dcTexs == null || dcTexs.capacity() != mmTexs.capacity()) {
dcTexs = BufferUtils.createFloatBuffer(mmTexs.capacity());
dcTexs.clear();
dataCopy.setTextureCoords(new TexCoords(dcTexs), 0);
}
dcTexs.put(mmTexs);
dcTexs.flip();
}
}
/**
* As defined in Controller
*
* @param time
* as defined in Controller
*/
public void update(float time) {
if (easyQuit()) return;
if (movingForward)
curTime += time * this.getSpeed();
else
curTime -= time * this.getSpeed();
findFrame();
before = keyframes.get(curFrame);
// Change this bit so the next frame we're heading towards isn't always going
// to be one frame ahead since now we coule be animating from the last to first
// frames.
//after = keyframes.get(curFrame + 1));
after = keyframes.get(nextFrame);
float delta = (curTime - before.time) / (after.time - before.time);
// If we doing that wrapping bit then delta should be caculated based
// on the time before the start of the animation we are.
if (nextFrame < curFrame) {
delta = blendTime - (getMinTime()-curTime);
}
TriMesh oldShape = before.newShape;
TriMesh newShape = after.newShape;
FloatBuffer verts = morphMesh.getVertexBuffer();
FloatBuffer norms = morphMesh.getNormalBuffer();
FloatBuffer texts = morphMesh.getTextureCoords(0) != null ? morphMesh.getTextureCoords(0).coords : null;
FloatBuffer colors = morphMesh.getColorBuffer();
FloatBuffer oldverts = oldShape.getVertexBuffer();
FloatBuffer oldnorms = oldShape.getNormalBuffer();
FloatBuffer oldtexts = oldShape.getTextureCoords(0) != null ? oldShape.getTextureCoords(0).coords : null;
FloatBuffer oldcolors = oldShape.getColorBuffer();
FloatBuffer newverts = newShape.getVertexBuffer();
FloatBuffer newnorms = newShape.getNormalBuffer();
FloatBuffer newtexts = newShape.getTextureCoords(0) != null ? newShape.getTextureCoords(0).coords : null;
FloatBuffer newcolors = newShape.getColorBuffer();
int vertQuantity = verts.capacity() / 3;
if (verts == null || oldverts == null || newverts == null) return;
verts.rewind(); oldverts.rewind(); newverts.rewind();
if (norms != null) norms.rewind(); // reset to start
if (oldnorms != null) oldnorms.rewind(); // reset to start
if (newnorms != null) newnorms.rewind(); // reset to start
if (texts != null) texts.rewind(); // reset to start
if (oldtexts != null) oldtexts.rewind(); // reset to start
if (newtexts != null) newtexts.rewind(); // reset to start
if (colors != null) colors.rewind(); // reset to start
if (oldcolors != null) oldcolors.rewind(); // reset to start
if (newcolors != null) newcolors.rewind(); // reset to start
for (int i = 0; i < vertQuantity; i++) {
for (int x = 0; x < 3; x++) // x, y, and z
verts.put(i*3+x, (1f-delta)*oldverts.get(i*3 + x) + delta*newverts.get(i*3 + x));
if (norms != null && oldnorms != null && newnorms != null)
for (int x = 0; x < 3; x++) // x, y, and z
norms.put(i*3+x, (1f-delta)*oldnorms.get(i*3 + x) + delta*newnorms.get(i*3 + x));
if (texts != null && oldtexts != null && newtexts != null)
for (int x = 0; x < 2; x++) // x and y
texts.put(i*2+x,(1f-delta)*oldtexts.get(i*2 + x) + delta*newtexts.get(i*2 + x));
if (colors != null && oldcolors != null && newcolors != null)
for (int x = 0; x < 4; x++) // r, g, b, a
colors.put(i*4+x,(1f-delta)*oldcolors.get(i*4 + x) + delta*newcolors.get(i*4 + x));
}
if (updatePerFrame) morphMesh.updateModelBound();
}
/**
* If both min and max time are equal and the model is already updated, then
* it's an easy quit, or if it's on CLAMP and I've exceeded my time it's
* also an easy quit.
*
* @return true if update doesn't need to be called, false otherwise
*/
private boolean easyQuit() {
if (getMaxTime() == getMinTime() && curTime != getMinTime())
return true;
else if (getRepeatType() == RT_CLAMP
&& (curTime > getMaxTime() || curTime < getMinTime()))
return true;
else if (keyframes.size() < 2) return true;
return false;
}
/**
* If true, the model's bounding volume will be updated every frame. If
* false, it will not.
*
* @param update
* The new update model volume per frame value.
*/
public void setModelUpdate(boolean update) {
updatePerFrame = update;
}
/**
* Returns true if the model's bounding volume is being updated every frame.
*
* @return True if bounding volume is updating.
*/
public boolean getModelUpdate() {
return updatePerFrame;
}
private float blendTime = 0;
/**
* If repeat type <CODE>RT_WRAP</CODE> is set, after reaching the last frame of the currently set
* animation maxTime (see <CODE>Controller.setMaxTime</CODE>), there will be an additional <CODE>blendTime</CODE>
* seconds long phase inserted, morphing from the last frame to the first.
* @param blendTime The blend time to set
*/
public void setBlendTime(float blendTime){ this.blendTime = blendTime; }
/**
* Gets the currently set blending time for smooth animation transitions
* @return The current blend time
* @see #setBlendTime(float blendTime)
*/
public float getBlendTime(){ return blendTime; }
/**
* This is used by update(float). It calculates PointInTime
* <code>before</code> and <code>after</code> as well as makes
* adjustments on what to do when <code>curTime</code> is beyond the
* MinTime and MaxTime bounds
*/
private void findFrame() {
// If we're in our special wrapping case then just ignore changing
// frames. Once we get back into the actual series we'll revert back
// to the normal process
if ((curTime < getMinTime()) && (nextFrame < curFrame)) {
return;
}
// Update the rest to maintain our new nextFrame marker as one infront
// of the curFrame in all cases. The wrap case is where the real work
// is done.
if (curTime > this.getMaxTime()) {
if (isSmooth) {
swapKeyframeSets();
isSmooth = false;
curTime = tempNewBeginTime;
curFrame = 0;
nextFrame = 1;
setNewAnimationTimes(tempNewBeginTime, tempNewEndTime);
return;
}
if (this.getRepeatType() == Controller.RT_WRAP) {
float delta = blendTime;
curTime = this.getMinTime() - delta;
curFrame = Math.min(curFrame + 1, keyframes.size() - 1);
for (nextFrame = 0; nextFrame < keyframes.size() - 1; nextFrame++) {
if (getMinTime() <= keyframes.get(nextFrame).time)
break;
}
return;
} else if (this.getRepeatType() == Controller.RT_CLAMP) {
return;
} else { // Then assume it's RT_CYCLE
movingForward = false;
curTime = this.getMaxTime();
}
} else if (curTime < this.getMinTime()) {
if (this.getRepeatType() == Controller.RT_WRAP) {
curTime = this.getMaxTime();
curFrame = 0;
} else if (this.getRepeatType() == Controller.RT_CLAMP) {
return;
} else { // Then assume it's RT_CYCLE
movingForward = true;
curTime = this.getMinTime();
}
}
nextFrame = curFrame+1;
if (curTime > keyframes.get(curFrame).time) {
if (curTime < keyframes.get(curFrame + 1).time) {
nextFrame = curFrame+1;
return;
}
for (; curFrame < keyframes.size() - 1; curFrame++) {
if (curTime <= keyframes.get(curFrame + 1).time) {
nextFrame = curFrame+1;
return;
}
}
// This -should- be unreachable because of the above
curTime = this.getMinTime();
curFrame = 0;
nextFrame = curFrame+1;
return;
}
for (; curFrame >= 0; curFrame--) {
if (curTime >= keyframes.get(curFrame).time) {
nextFrame = curFrame+1;
return;
}
}
// This should be unreachable because curTime>=0 and
// keyframes[0].time=0;
curFrame = 0;
nextFrame = curFrame+1;
}
/**
* This class defines a point in time that states <code>morphShape</code>
* should look like <code>newShape</code> at <code>time</code> seconds
*/
public static class PointInTime implements Serializable, Savable {
private static final long serialVersionUID = 1L;
public TriMesh newShape;
public float time;
public PointInTime() {}
public PointInTime(float time, TriMesh shape) {
this.time = time;
this.newShape = shape;
}
public void read(JMEImporter im) throws IOException {
InputCapsule cap = im.getCapsule(this);
time = cap.readFloat("time", 0);
newShape = (TriMesh)cap.readSavable("newShape", null);
}
public void write(JMEExporter ex) throws IOException {
OutputCapsule cap = ex.getCapsule(this);
cap.write(time, "time", 0);
cap.write(newShape, "newShape", null);
}
public Class getClassTag() {
return this.getClass();
}
}
@SuppressWarnings("unchecked")
private void readObject(java.io.ObjectInputStream in) throws IOException,
ClassNotFoundException {
in.defaultReadObject();
keyframes = (ArrayList) in.readObject();
movingForward = true;
}
private void writeObject(java.io.ObjectOutputStream out) throws IOException {
out.defaultWriteObject();
if (isSmooth)
out.writeObject(prevKeyframes);
else
out.writeObject(keyframes);
}
public TriMesh getMorphMesh() {
return morphMesh;
}
@Override
public void write(JMEExporter ex) throws IOException {
super.write(ex);
OutputCapsule cap = ex.getCapsule(this);
cap.write(updatePerFrame, "updatePerFrame", true);
cap.write(morphMesh, "morphMesh", null);
cap.writeSavableArrayList(keyframes, "keyframes", new ArrayList<PointInTime>());
}
@Override
@SuppressWarnings("unchecked")
public void read(JMEImporter im) throws IOException {
super.read(im);
InputCapsule cap = im.getCapsule(this);
updatePerFrame = cap.readBoolean("updatePerFrame", true);
morphMesh = (TriMesh) cap.readSavable("morphMesh", null);
keyframes = cap.readSavableArrayList("keyframes", new ArrayList<PointInTime>());
movingForward = true;
}
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -