override public void decode(EndianBinaryReader binReader) { actorId = binReader.ReadInt16(); m_byte = binReader.ReadSByte(); m_date = binReader.ReadDate(); m_float = binReader.ReadFloat(); testStruct = new sendLogin_testStructVO(); testStruct.decode(binReader); var len_playerList = binReader.ReadUInt16(); playerList = new sendLogin_playerListVO[len_playerList]; for (int i = 0; i < len_playerList; i++) { playerList[i] = new sendLogin_playerListVO(); playerList[i].decode(binReader); } }
public static List<Joint> GetJoints(EndianBinaryReader reader, int numJoints) { List<Joint> joints = new List<Joint>(); for (int i = 0; i < numJoints; i++) { Joint joint = new Joint(); joint.boneLength = -reader.ReadInt16(); reader.Skip(2); // no effect on length, just padding joint.parentID = reader.ReadSByte(); joint.x = reader.ReadSByte(); joint.y = reader.ReadSByte(); joint.z = reader.ReadSByte(); joint.mode = reader.ReadSByte(); // does this matter? reader.Skip(0x01); // unknown reader.Skip(0x06); // always 0? padding? joints.Add(joint); } return joints; }
private static NullableVector4 ReadOPCode(EndianBinaryReader reader) { byte op = reader.ReadByte(); if (op == 0) return null; // return abort vector // results float? x = null, y = null, z = null, f = null; if ((op & 0xe0) > 0) { // number of frames, byte case f = op & 0x1f; if (f == 0x1f) { f = 0x20 + reader.ReadByte(); } else { f = 1 + f; } } else { // number of frames, half word case f = op & 0x3; if (f == 0x3) { f = 4 + reader.ReadByte(); } else { f = 1 + f; } // half word values reader.CurrentEndian = Endian.Big; op = (byte)(op << 3); var h = reader.ReadInt16(); if ((h & 0x4) > 0) { x = h >> 3; op = (byte)(op & 0x60); if ((h & 0x2) > 0) { y = reader.ReadInt16(); op = (byte)(op & 0xa0); } if ((h & 0x1) > 0) { z = reader.ReadInt16(); op = (byte)(op & 0xc0); } } else if ((h & 0x2) > 0) { y = h >> 3; op = (byte)(op & 0xa0); if ((h & 0x1) > 0) { z = reader.ReadInt16(); op = (byte)(op & 0xc0); } } else if ((h & 0x1) > 0) { z = h >> 3; op = (byte)(op & 0xc0); } } // byte values (fallthrough) reader.CurrentEndian = Endian.Little; if ((op & 0x80) > 0) { x = reader.ReadSByte(); } if ((op & 0x40) > 0) { y = reader.ReadSByte(); } if ((op & 0x20) > 0) { z = reader.ReadSByte(); } return new NullableVector4(x, y, z, f); }
public static SEQ FromStream(EndianBinaryReader reader, ContentBase activeSHP) { SHP targetSHP = (SHP)activeSHP; /*===================================================================== TODO: add lenght =====================================================================*/ // base ptr needed because the SEQ could be embedded. uint ptrBase = (uint)reader.BaseStream.Position; byte numFrames = reader.ReadByte(); // total number of frames? var unknownPaddingValue1 = reader.ReadByte(); // padding //Trace.Assert(unknownPaddingValue1 == 0); byte numBones = reader.ReadByte(); var unknownPaddingValue2 = reader.ReadByte(); // padding //Trace.Assert(unknownPaddingValue2 == 0); uint size = reader.ReadUInt32(); var unknownPaddingValue3 = reader.ReadUInt32(); // unknown //Trace.Assert(unknownPaddingValue3 == 0); uint ptrFrames = (uint)reader.ReadUInt32() + 8; // pointer to the frames data section uint ptrSequence = ptrFrames + (uint)numFrames; // pointer to the sequence section // number of animations // length of all the headers / length of one animation header int numAnimations = (((int)ptrSequence - numFrames) - 16) / (numBones * 4 + 10); List<AnimationHeader> headers = new List<AnimationHeader>(); for (int i = 0; i < numAnimations; i++) { AnimationHeader animHeader = new AnimationHeader { length = reader.ReadUInt16(), idOtherAnimation = reader.ReadSByte(), // the intial source animation. Used to get initial frames. mode = reader.ReadByte(), ptrLooping = reader.ReadUInt16(), // seems to point to a data block that controls looping ptrTranslation = reader.ReadUInt16(), // points to a translation vector for the animated mesh (root motion?) ptrMove = reader.ReadUInt16(), // points to a data block that controls movement (root motion?) ptrBones = new ushort[numBones], }; // assign bone ptrs for (int p = 0; p < numBones; p++) { animHeader.ptrBones[p] = reader.ReadUInt16(); } for (int j = 0; j < numBones; j++) { var unknownBoneValues = reader.ReadUInt16(); //TODO: this is 0 for all SEQs? //Trace.Assert(unknownBoneValues == 0); // will show if value is ever NOT zero } headers.Add(animHeader); } // TODO: Never used!? sbyte[] frames = new sbyte[numFrames]; for (int i = 0; i < numFrames; i++) { frames[i] = reader.ReadSByte(); } // get source animation data from .SEQ List<Animation> animations = new List<Animation>(); for (int i = 0; i < numAnimations; i++) { Animation animation = new Animation(); // seek translation data long seekTranslationPtr = (long)(headers[i].ptrTranslation + ptrSequence + ptrBase); reader.BaseStream.Seek(seekTranslationPtr, SeekOrigin.Begin); reader.CurrentEndian = Endian.Big; // this is code used in the opcode portion (machine code uses Big) Int16 x = reader.ReadInt16(); Int16 y = reader.ReadInt16(); Int16 z = reader.ReadInt16(); reader.CurrentEndian = Endian.Little; // TODO: implement move // set base animation if (headers[i].idOtherAnimation != -1) { // TODO: FIX THIS // should store other animation inside as base // I assume it only references animations that // have been constructed first otherwise it will hold a dead copy. // animation.baseAnimation = animations[i]; } // read base pose and keyframes animation.poses = new Vector3[numBones]; animation.keyframes = new List<NullableVector4>[numBones]; for (int k = 0; k < numBones; k++) { animation.keyframes[k] = new List<NullableVector4>(); animation.keyframes[k].Add(NullableVector4.Zero()); // read pose long seekBonePtr = (long)(headers[i].ptrBones[k] + ptrSequence + ptrBase); reader.BaseStream.Seek(seekBonePtr, SeekOrigin.Begin); reader.CurrentEndian = Endian.Big; // machine code uses Big Int16 rx = reader.ReadInt16(); Int16 ry = reader.ReadInt16(); Int16 rz = reader.ReadInt16(); reader.CurrentEndian = Endian.Little; animation.poses[k] = new Vector3(rx, ry, rz); // read keyframe float? f = 0; while (true) { // this could be optimized using out values and an advanced way of recording and reading frames NullableVector4 op = ReadOPCode(reader); if (op == null) break; f += op.W; animation.keyframes[k].Add(op); if (f >= headers[i].length - 1) break; } } animations.Add(animation); } // build useable animation data for (int a = 0; a < numAnimations; a++) { // rotation bones for (int i = 0; i < numBones; i++) { List<NullableVector4> keyframes = animations[a].keyframes[i]; Vector3 pose = animations[a].poses[i]; // multiplication by two at 0xad25c, 0xad274, 0xad28c // value * (180f / uint16.max); float rx = pose.X * 2; float ry = pose.Y * 2; float rz = pose.Z * 2; List<Keyframe> keys = new List<Keyframe>(); float t = 0; for (var j = 0; j < keyframes.Count; j++) { NullableVector4 keyframe = keyframes[j]; float f = (float)keyframe.W; t += f; if (keyframe.X == null) keyframe.X = keyframes[j - 1].X; if (keyframe.Y == null) keyframe.Y = keyframes[j - 1].Y; if (keyframe.Z == null) keyframe.Z = keyframes[j - 1].Z; rx += (float)keyframe.X * f; ry += (float)keyframe.Y * f; rz += (float)keyframe.Z * f; Quaternion q = VSTools.Rot2Quat(rx * VSTools.Rot13ToRad, ry * VSTools.Rot13ToRad, rz * VSTools.Rot13ToRad); Keyframe key = new Keyframe(); key.Time = t * VSTools.TimeScale; key.Rotation = q; keys.Add(key); } animations[a].jointKeys.Add(keys); } // root's translation bone List<Keyframe> rootKey = new List<Keyframe>(); rootKey.Add(new Keyframe()); animations[a].jointKeys.Add(rootKey); // translation bones for (int t = 1; t < numBones; t++) { List<Keyframe> transBone = new List<Keyframe>(); Keyframe key = new Keyframe(); key.Position = new Vector3(targetSHP.joints[t].boneLength, 0, 0); transBone.Add(key); animations[a].jointKeys.Add(transBone); } if (headers[a].idOtherAnimation != -1) { animations[a].baseAnimation = animations[headers[a].idOtherAnimation]; } } return new SEQ(animations); }
public void Read(Stream inStream, MesgDefinition defnMesg) { inStream.Position = 1; EndianBinaryReader mesgReader = new EndianBinaryReader(inStream, defnMesg.IsBigEndian); LocalNum = defnMesg.LocalMesgNum; foreach (FieldDefinition fieldDef in defnMesg.GetFields()) { // It's possible the field type found in the field definition may // not agree with the type defined in the profile. The profile // type will be preferred for decode. Field field = GetField(fieldDef.Num); if (field == null) { // We normally won't have fields attached to our skeleton message, // as we add values we need to add the fields too based on the mesg,field // combo in the profile. Must derive from the profile so the scale etc // is correct field = new Field(Profile.GetMesg(this.Num).GetField(fieldDef.Num)); if (field.Num == Fit.FieldNumInvalid) { // If there was no info in the profile the FieldNum will get set to invalid // so preserve the unknown fields info while we know it field.Num = fieldDef.Num; field.Type = fieldDef.Type; } SetField(field); } object value; // strings may be an array and are of variable length if ((field.Type & Fit.BaseTypeNumMask) == Fit.String) { List<byte> utf8Bytes = new List<byte>(); byte b = new byte(); for (int i=0; i<fieldDef.Size; i++) { b = mesgReader.ReadByte(); if (b == 0x00) { field.AddValue(utf8Bytes.ToArray()); utf8Bytes.Clear(); } else { utf8Bytes.Add(b); } } if (utf8Bytes.Count != 0) { field.AddValue(utf8Bytes.ToArray()); utf8Bytes.Clear(); } } else { int numElements = (int)fieldDef.Size / Fit.BaseType[field.Type & Fit.BaseTypeNumMask].size; for (int i=0; i < numElements; i++) { switch (field.Type & Fit.BaseTypeNumMask) { case Fit.Enum: case Fit.Byte: case Fit.UInt8: case Fit.UInt8z: value = mesgReader.ReadByte(); break; case Fit.SInt8: value = mesgReader.ReadSByte(); break; case Fit.SInt16: value = mesgReader.ReadInt16(); break; case Fit.UInt16: case Fit.UInt16z: value = mesgReader.ReadUInt16(); break; case Fit.SInt32: value = mesgReader.ReadInt32(); break; case Fit.UInt32: case Fit.UInt32z: value = mesgReader.ReadUInt32(); break; case Fit.Float32: value = mesgReader.ReadSingle(); break; case Fit.Float64: value = mesgReader.ReadDouble(); break; default: value = mesgReader.ReadBytes(fieldDef.Size); break; } field.SetRawValue(i, value); } } } }