package rajawali.animation.mesh; import java.nio.ByteBuffer; import java.nio.ByteOrder; import java.nio.FloatBuffer; import rajawali.BufferInfo; import rajawali.Camera; import rajawali.Geometry3D.BufferType; import rajawali.math.Number3D; import rajawali.math.Quaternion; import rajawali.util.BufferUtil; import rajawali.util.ObjectColorPicker.ColorPickerInfo; import rajawali.util.RajLog; import android.opengl.GLES20; import android.opengl.Matrix; import android.os.SystemClock; public class AnimationSkeleton extends AAnimationObject3D { public static final int FLOAT_SIZE_BYTES = 4; private SkeletonJoint[] mJoints; private BoneAnimationSequence mSequence; public float[][] mInverseBindPoseMatrix; public float[] uBoneMatrix; public BufferInfo mBoneMatricesBufferInfo = new BufferInfo(); /** * FloatBuffer containing joint transformation matrices */ protected FloatBuffer mBoneMatrices; public AnimationSkeleton() { } public void setJoints(SkeletonJoint[] joints) { mJoints = joints; if (mBoneMatrices == null) { if (mBoneMatrices != null) { mBoneMatrices.clear(); } mBoneMatrices = ByteBuffer .allocateDirect(joints.length * FLOAT_SIZE_BYTES * 16) .order(ByteOrder.nativeOrder()).asFloatBuffer(); BufferUtil.copy(uBoneMatrix, mBoneMatrices, uBoneMatrix.length, 0); mBoneMatrices.position(0); } else { BufferUtil.copy(uBoneMatrix, mBoneMatrices, uBoneMatrix.length, 0); } mGeometry.createBuffer(mBoneMatricesBufferInfo, BufferType.FLOAT_BUFFER, mBoneMatrices, GLES20.GL_ARRAY_BUFFER); } public SkeletonJoint getJoint(int index) { return mJoints[index]; } public SkeletonJoint[] getJoints() { return mJoints; } public void setAnimationSequence(BoneAnimationSequence sequence) { mSequence = sequence; if (sequence != null && sequence.getFrames() != null) { mNumFrames = sequence.getFrames().length; for (int i = 0, j = mChildren.size(); i < j; i++) if (mChildren.get(i) instanceof BoneAnimationObject3D) ((BoneAnimationObject3D) mChildren.get(i)).setAnimationSequence(sequence); } } public BoneAnimationSequence getAnimationSequence() { return mSequence; } public void setShaderParams(Camera camera) { //TODO setting light params for container objects //super.setShaderParams(camera); if (!mIsPlaying) return; mBoneMatrices.clear(); mBoneMatrices.position(0); long mCurrentTime = SystemClock.uptimeMillis(); BoneAnimationFrame currentFrame = (BoneAnimationFrame) mSequence.getFrame(mCurrentFrameIndex); BoneAnimationFrame nextFrame = (BoneAnimationFrame) mSequence.getFrame((mCurrentFrameIndex + 1) % mNumFrames); mInterpolation += (float) mFps * (mCurrentTime - mStartTime) / 1000.f; float[] boneTranslation = new float[16]; float[] boneRotation = new float[16]; float[] boneMatrix = new float[16]; float[] resultMatrix = new float[16]; for (int i = 0; i < mJoints.length; ++i) { SkeletonJoint joint = getJoint(i); SkeletonJoint fromJoint = currentFrame.getSkeleton().getJoint(i); SkeletonJoint toJoint = nextFrame.getSkeleton().getJoint(i); joint.setParentIndex(fromJoint.getParentIndex()); joint.getPosition().lerpSelf(fromJoint.getPosition(), toJoint.getPosition(), mInterpolation); joint.getOrientation().setAllFrom(Quaternion.slerp(mInterpolation, fromJoint.getOrientation(), toJoint.getOrientation(), false)); Matrix.setIdentityM(boneTranslation, 0); Matrix.setIdentityM(boneRotation, 0); Matrix.setIdentityM(boneMatrix, 0); Matrix.setIdentityM(resultMatrix, 0); Number3D jointPos = joint.getPosition(); Matrix.translateM(boneTranslation, 0, jointPos.x, jointPos.y, jointPos.z); joint.getOrientation().toRotationMatrix(boneRotation); Matrix.multiplyMM(boneMatrix, 0, boneTranslation, 0, boneRotation, 0); Matrix.multiplyMM(resultMatrix, 0, boneMatrix, 0, mInverseBindPoseMatrix[i], 0); joint.setMatrix(resultMatrix); int index = 16 * i; for (int j = 0; j < 16; j++) { uBoneMatrix[index + j] = resultMatrix[j]; mBoneMatrices.put(resultMatrix[j]); } } mGeometry.changeBufferData(mBoneMatricesBufferInfo, mBoneMatrices, 0); if (mInterpolation >= 1) { mInterpolation = 0; mCurrentFrameIndex++; if (mCurrentFrameIndex >= mNumFrames) mCurrentFrameIndex = 0; } mStartTime = mCurrentTime; } public void play() { if (mSequence == null) { RajLog.e("[BoneAnimationObject3D.play()] Cannot play animation. No sequence was set."); return; } super.play(); for (int i = 0, j = mChildren.size(); i < j; i++) if (mChildren.get(i) instanceof AAnimationObject3D) ((AAnimationObject3D) mChildren.get(i)).play(); } @Override public void render(Camera camera, float[] projMatrix, float[] vMatrix, float[] parentMatrix, ColorPickerInfo pickerInfo) { setShaderParams(camera); super.render(camera, projMatrix, vMatrix, parentMatrix, pickerInfo); } @Override public void reload() { super.reload(); mGeometry.createBuffer(mBoneMatricesBufferInfo, BufferType.FLOAT_BUFFER, mBoneMatrices, GLES20.GL_ARRAY_BUFFER); } @Override public void destroy() { int[] buffers = new int[1]; if(mBoneMatricesBufferInfo != null) buffers[0] = mBoneMatricesBufferInfo.bufferHandle; GLES20.glDeleteBuffers(buffers.length, buffers, 0); if(mBoneMatrices != null) mBoneMatrices.clear(); mBoneMatrices=null; if(mBoneMatricesBufferInfo != null && mBoneMatricesBufferInfo.buffer != null) { mBoneMatricesBufferInfo.buffer.clear(); mBoneMatricesBufferInfo.buffer=null; } super.destroy(); } }