/// <summary> /// Returns a list of all keyframe data belonging to this specific layer. /// </summary> /// <param name="layer">The layer to get the keyframes for.</param> /// <param name="header">Header of the file from which the keyframes are sourced.</param> /// <param name="keySpan">The buffer to place the keyframes in.</param> /// <returns>The supplied buffer, sliced.</returns> public static unsafe Span <BlittablePointer <Keyframe> > GetKeyFrames(Layer *layer, MetadataHeader *header, Span <BlittablePointer <Keyframe> > keySpan) { int remainingFrames = layer->NumKeyframes; var currentPointer = (byte *)(layer + 1); int numItems = 0; if (layer->MaybeAnimationDurationFrames <= 0 && remainingFrames <= 0) { return(keySpan.Slice(0, numItems)); } while (remainingFrames > 1) { var keyFramePtr = (Keyframe *)currentPointer; var keyFrameLength = Keyframe.GetKeyframeSize(keyFramePtr, layer, header); var keyFrameType = (short)(keyFramePtr->KeyframeType & (KeyframeType)0x7FFF); keySpan[numItems++] = keyFramePtr; // Animation ends if no duration, unless keyframes type 0/1 if (keyFramePtr->AnimationActivationPointFrames < 1 && keyFrameType != 0 && keyFrameType != 1) { break; } remainingFrames--; currentPointer += keyFrameLength; } return(keySpan.Slice(0, numItems)); }
/// <summary> /// Gets the size of this keyframe, in bytes. /// </summary> /// <param name="keyframe">The keyframe for which to get the size for.</param> /// <param name="layer">The layer in question.</param> /// <param name="header">The header.</param> /// <returns></returns> public static unsafe int GetKeyframeSize(Keyframe *keyframe, Layer *layer, MetadataHeader *header) { switch ((keyframe->KeyframeType & (KeyframeType)0x7FFF)) { default: case KeyframeType.HalfByteCount: return(layer->NumBytes + sizeof(Keyframe)); // +8 may be an error here, but parses existing files. case KeyframeType.SizeFromHeader: return(header->AnimationType1Offset * 4); // Typically 0x14 * 4 case KeyframeType.SizeFromSameStructSimpleHeader: case KeyframeType.SizeFromSameStructComplexHeader: return(keyframe->NumberOfBytesDivBy4 * 4); } }
/// <summary> /// Gets the individual data items for a given keyframe. /// </summary> /// <param name="keyframe">Pointer to the keyframe in question.</param> /// <param name="layer">Pointer to the layer in question.</param> /// <param name="header">Pointer to the archive header.</param> /// <param name="stack">Preallocated stack memory. Recommend 32 items.</param> /// <returns></returns> public unsafe Span <DataHeaderWrapper> GetData(Keyframe *keyframe, Layer *layer, MetadataHeader *header, Span <DataHeaderWrapper> stack) { // Invalid. if (keyframe->NumberOfChangedProperties < 0) { return(stack.Slice(0, 0)); } var keyframeType = (keyframe->KeyframeType & (KeyframeType)0x7FFF); switch (keyframeType) { default: case KeyframeType.HalfByteCount: // 0 { var result = new DataHeaderWrapper() { DataType = DataHeaderWrapper.InvalidDataType, NumBytes = layer->NumBytes, DataPtr = (byte *)(keyframe + 1) }; stack[0] = result; return(stack.Slice(0, 1)); } case KeyframeType.SizeFromHeader: // 1 { var result = new DataHeaderWrapper() { DataType = DataHeaderWrapper.InvalidDataType, NumBytes = (short)(header->AnimationType1Offset * 4), DataPtr = (byte *)(keyframe + 1) }; stack[0] = result; return(stack.Slice(0, 1)); } case KeyframeType.SizeFromSameStructSimpleHeader: // 2 { var headersPtr = (Type2DataHeader *)(keyframe + 1); var valuesOffset = ((keyframe->NumberOfBytesDivBy4 - keyframe->NumberOfChangedProperties) * 4); var valuesPtr = (int *)((byte *)keyframe + valuesOffset); for (int x = 0; x < keyframe->NumberOfChangedProperties; x++) { stack[x] = new DataHeaderWrapper() { DataType = headersPtr->DataType, NumBytes = sizeof(int), DataPtr = (byte *)valuesPtr, }; valuesPtr++; headersPtr++; } return(stack.Slice(0, keyframe->NumberOfChangedProperties)); } case KeyframeType.SizeFromSameStructComplexHeader: // 3 { var headersPtr = (Type3DataHeader *)(keyframe + 1); var valuesOffset = (keyframe->NumberOfChangedProperties * sizeof(Type3DataHeader)); var valuesPtr = (byte *)headersPtr + valuesOffset; for (int x = 0; x < keyframe->NumberOfChangedProperties; x++) { stack[x] = new DataHeaderWrapper() { DataType = headersPtr->DataType, NumBytes = headersPtr->NumBytes, DataPtr = valuesPtr, }; valuesPtr += headersPtr->NumBytes; headersPtr++; } return(stack.Slice(0, keyframe->NumberOfChangedProperties)); } } }