void WriteMeshes(BinaryWriter writer, TextTable text, ref Header header) { header.MeshOffset = (int)writer.BaseStream.Position; header.MeshCount = Mathf.Max(1, Submeshes.Count); if (Submeshes.Count > 0) { foreach (var mesh in Submeshes) { WriteMesh(mesh); } } else { WriteMesh(new Submesh { Name = "Model", Material = "Default", TriangleCount = Triangles.Count }); } void WriteMesh(Submesh mesh) { writer.Write(text.GetOrAddIndex(mesh.Name)); writer.Write(text.GetOrAddIndex(mesh.Material)); writer.Write(0); writer.Write(Vertices.Count); writer.Write(mesh.TriangleIndex); writer.Write(mesh.TriangleCount); } }
void WriteBones(BinaryWriter writer, TextTable text, ref Header header) { header.JointOffset = (int)writer.BaseStream.Position; header.JointCount = Bones.Count; foreach (var bone in Bones) { int parent = Bones.IndexOf(bone.Parent); if (parent == -1 && bone.Parent != null) { throw new Exception("Bone has invalid parent."); } writer.Write(text.GetOrAddIndex(bone.Name)); writer.Write(parent); writer.Write(CoordinateHelper.UnityToQuake(bone.Translate)); writer.Write(CoordinateHelper.UnityToQuake(bone.Rotate)); writer.Write(CoordinateHelper.UnityToQuake(bone.Scale, isScale: true)); } }
void WriteAnimations(BinaryWriter writer, TextTable text, ref Header header) { // todo: make this code nicer if (FrameCount <= 0) { return; } header.PoseCount = Bones.Count; header.FrameCount = FrameCount; var frameData = new List <ushort>(); var keyFrames = new KeyFrame[Bones.Count]; var channels = new PoseChannels[FrameCount, Bones.Count]; var poses = new Pose[Bones.Count]; for (int b = 0; b < Bones.Count; b++) { keyFrames[b] = new KeyFrame { Bone = Bones[b], Translate = Bones[b].Translate, Rotate = Bones[b].Rotate, Scale = Bones[b].Scale }; } for (int f = 0; f < FrameCount; f++) { if (frames.TryGetValue(f, out var keys)) { foreach (var key in keys) { var bone = Bones.IndexOf(key.Bone); if (bone == -1) { continue; } keyFrames[bone] = key; } } for (int b = 0; b < Bones.Count; b++) { var translate = CoordinateHelper.UnityToQuake(keyFrames[b].Translate); var rotate = CoordinateHelper.UnityToQuake(keyFrames[b].Rotate); var scale = CoordinateHelper.UnityToQuake(keyFrames[b].Scale, isScale: true); channels[f, b][0] = translate.x; channels[f, b][1] = translate.y; channels[f, b][2] = translate.z; channels[f, b][3] = rotate.x; channels[f, b][4] = rotate.y; channels[f, b][5] = rotate.z; channels[f, b][6] = rotate.w; channels[f, b][7] = scale.x; channels[f, b][8] = scale.y; channels[f, b][9] = scale.z; for (int c = 0; c < 10; c++) { if (f == 0) { poses[b].Min[c] = poses[b].Max[c] = channels[f, b][c]; } else { poses[b].Min[c] = Mathf.Min(poses[b].Min[c], channels[f, b][c]); poses[b].Max[c] = Mathf.Max(poses[b].Max[c], channels[f, b][c]); } } } } for (int b = 0; b < Bones.Count; b++) { poses[b].Parent = Bones.IndexOf(Bones[b].Parent); for (int c = 0; c < 10; c++) { poses[b].ChannelOffset[c] = poses[b].Min[c]; poses[b].ChannelScale [c] = 0; if (poses[b].Min[c] == poses[b].Max[c]) { continue; } poses[b].ChannelMask |= 1 << c; poses[b].ChannelScale[c] = (poses[b].Max[c] - poses[b].Min[c]) / 65535f; header.FrameChannelCount++; } } for (int f = 0; f < FrameCount; f++) { for (int b = 0; b < Bones.Count; b++) { for (int c = 0; c < 10; c++) { if ((poses[b].ChannelMask & (1 << c)) == 0) { continue; } float frame = (channels[f, b][c] - poses[b].Min[c]) / (poses[b].Max[c] - poses[b].Min[c]); frameData.Add((ushort)Mathf.Min(frame * 65535f, 65535f)); } } } header.PoseOffset = (int)writer.BaseStream.Position; foreach (var pose in poses) { pose.Write(writer); } header.FrameOffset = (int)writer.BaseStream.Position; foreach (var frame in frameData) { writer.Write(frame); } header.AnimCount = Mathf.Max(1, Animations.Count); header.AnimOffset = (int)writer.BaseStream.Position; if (Animations.Count > 0) { foreach (var range in Animations) { WriteAnimation(range); } } else { WriteAnimation(new AnimationRange { Name = "Sequence", FrameCount = FrameCount, FrameRate = 24 }); } void WriteAnimation(AnimationRange range) { writer.Write(text.GetOrAddIndex(range.Name)); writer.Write(range.FrameIndex); writer.Write(range.FrameCount); writer.Write(range.FrameRate); writer.Write((int)range.Flags); } }