예제 #1
0
파일: INF1.cs 프로젝트: CryZe/WindEditor2
        private static SceneNode LoadINF1FromFile(SceneNode rootNode, EndianBinaryReader reader, long chunkStart)
        {
            ushort unknown1 = reader.ReadUInt16(); // A lot of Link's models have it but no idea what it means. Alt. doc says: "0 for BDL, 01 for BMD"
            ushort padding = reader.ReadUInt16();
            uint packetCount = reader.ReadUInt32(); // Total number of Packets across all Batches in file.
            uint vertexCount = reader.ReadUInt32(); // Total number of vertexes across all batches within the file.
            uint hierarchyDataOffset = reader.ReadUInt32();

            // The Hierarchy defines how Joints, Materials and Shapes are laid out. This allows them to bind a material
            // and draw multiple shapes (batches) with the material. It also complicates drawing things, but whatever.
            reader.BaseStream.Position = chunkStart + hierarchyDataOffset;

            List<InfoNode> infoNodes = new List<InfoNode>();
            InfoNode curNode = null;

            do
            {
                curNode = new InfoNode();
                curNode.Type = (HierarchyDataTypes)reader.ReadUInt16();
                curNode.Value = reader.ReadUInt16(); // "Index into Joint, Material, or Shape table.

                infoNodes.Add(curNode);
            }
            while (curNode.Type != HierarchyDataTypes.Finish);

            ConvertInfoHiearchyToSceneGraph(ref rootNode, infoNodes, 0);
            return rootNode;
        }
예제 #2
0
파일: EVP1.cs 프로젝트: CryZe/WindEditor2
        private static Envelopes LoadEVP1FromStream(EndianBinaryReader reader, long chunkStart)
        {
            Envelopes envelopes = new Envelopes();
            ushort numEnvelopes = reader.ReadUInt16();
            reader.ReadUInt16(); // Padding

            // numEnvelope many uint8 - each one describes how many bones belong to this index.
            uint boneCountOffset = reader.ReadUInt32();
            // "sum over all bytes in boneCountOffset many shorts (index into some joint stuff? into matrix table?)"
            uint indexDataOffset = reader.ReadUInt32();
            // Bone Weights (as many floats here as there are ushorts at indexDataOffset)
            uint weightOffset = reader.ReadUInt32();
            // Matrix Table (3x4 float array) - Inverse Bind Pose
            uint boneMatrixOffset = reader.ReadUInt32();

            // - Is this the number of bones which influence the vert?
            reader.BaseStream.Position = chunkStart + boneCountOffset;
            for (int b = 0; b < numEnvelopes; b++)
                envelopes.numBonesAffecting.Add(reader.ReadByte());

            // ???
            reader.BaseStream.Position = chunkStart + indexDataOffset;
            for (int m = 0; m < envelopes.numBonesAffecting.Count; m++)
            {
                for (int j = 0; j < envelopes.numBonesAffecting[m]; j++)
                {
                    envelopes.indexRemap.Add(reader.ReadUInt16());
                }
            }

            // Bone Weights
            reader.BaseStream.Position = chunkStart + weightOffset;
            for (int w = 0; w < envelopes.numBonesAffecting.Count; w++)
            {
                for (int j = 0; j < envelopes.numBonesAffecting[w]; j++)
                {
                    envelopes.weights.Add(reader.ReadSingle());
                }
            }

            // Inverse Bind Pose Matrices
            reader.BaseStream.Position = chunkStart + boneMatrixOffset;
            for (int w = 0; w < numEnvelopes; w++)
            {
                Matrix3x4 matrix = new Matrix3x4();
                for (int j = 0; j < 3; j++)
                {
                    for (int k = 0; k < 4; k++)
                        matrix[j, k] = reader.ReadSingle();
                }

                envelopes.inverseBindPose.Add(matrix);
            }

            return envelopes;
        }
예제 #3
0
파일: DRW1.cs 프로젝트: CryZe/WindEditor2
        private static DrawInfo LoadDRW1FromStream(EndianBinaryReader reader, long chunkStart)
        {
            DrawInfo drawInfo = new DrawInfo();

            ushort sectionCount = reader.ReadUInt16();
            Trace.Assert(reader.ReadUInt16() == 0xFFFF); // Padding - 0xFFFF
            uint isWeightedOffset = reader.ReadUInt32();
            uint indexOffset = reader.ReadUInt32();

            reader.BaseStream.Position = chunkStart + isWeightedOffset;
            for (int k = 0; k < sectionCount; k++)
                drawInfo.IsWeighted.Add(reader.ReadBoolean());

            reader.BaseStream.Position = chunkStart + indexOffset;
            for (int k = 0; k < sectionCount; k++)
                drawInfo.Indexes.Add(reader.ReadUInt16());
            return drawInfo;
        }
예제 #4
0
        private static void LoadSHP1SectionFromFile(MeshVertexAttributeHolder vertexData, Mesh j3dMesh, EndianBinaryReader reader, long chunkStart)
        {
            short batchCount = reader.ReadInt16();
            short padding = reader.ReadInt16();
            int batchOffset = reader.ReadInt32();
            int unknownTableOffset = reader.ReadInt32(); // Another one of those 0->(n-1) counters. I think all sections have it? Might be part of the way they used inheritance to write files.
            int alwaysZero = reader.ReadInt32(); Trace.Assert(alwaysZero == 0);
            int attributeOffset = reader.ReadInt32();
            int matrixTableOffset = reader.ReadInt32();
            int primitiveDataOffset = reader.ReadInt32();
            int matrixDataOffset = reader.ReadInt32();
            int packetLocationOffset = reader.ReadInt32();

            // Batches can have different attributes (ie: some have pos, some have normal, some have texcoords, etc.) they're split by batches,
            // where everything in the batch uses the same set of vertex attributes. Each batch then has several packets, which are a collection
            // of primitives.
            for (int b = 0; b < batchCount; b++)
            {
                MeshBatch meshBatch = new MeshBatch();
                j3dMesh.SubMeshes.Add(meshBatch);
                int overallVertexCount = 0;
                meshBatch.PrimitveType = OpenTK.Graphics.OpenGL.PrimitiveType.TriangleStrip; // HackHack, this varies per primitive.
                // We need to look on each primitive and convert them to trianglestrips, most are TS some are TF's.

                // We re-use the list struct here to dynamically add paired pos/col/tex as we load them
                // then we convert them into arrays for the MeshBatch afterwards.
                MeshVertexAttributeHolder meshVertexData = new MeshVertexAttributeHolder();

                // chunkStart + batchOffset gets you the position where the batches are listed
                // 0x28 * b gives you the right batch - a batch is 0x28 in length
                reader.BaseStream.Position = chunkStart + batchOffset + (0x28 * b);
                long batchStart = reader.BaseStream.Position;

                byte matrixType = reader.ReadByte();
                Trace.Assert(reader.ReadByte() == 0xFF); // Padding
                ushort packetCount = reader.ReadUInt16();
                ushort batchAttributeOffset = reader.ReadUInt16();
                ushort firstMatrixIndex = reader.ReadUInt16();
                ushort firstPacketIndex = reader.ReadUInt16();
                ushort unknownpadding = reader.ReadUInt16(); Trace.Assert(unknownpadding == 0xFFFF);

                float boundingSphereDiameter = reader.ReadSingle();
                Vector3 boundingBoxMin = new Vector3();
                boundingBoxMin.X = reader.ReadSingle();
                boundingBoxMin.Y = reader.ReadSingle();
                boundingBoxMin.Z = reader.ReadSingle();

                Vector3 boundingBoxMax = new Vector3();
                boundingBoxMax.X = reader.ReadSingle();
                boundingBoxMax.Y = reader.ReadSingle();
                boundingBoxMax.Z = reader.ReadSingle();

                // We need to figure out how many primitive attributes there are in the SHP1 section. This can differ from the number of
                // attributes in the VTX1 section, as the SHP1 can also include things like PositionMatrixIndex, so the count can be different.
                // This also varies *per batch* as not all batches will have the things like PositionMatrixIndex.
                reader.BaseStream.Position = chunkStart + attributeOffset + batchAttributeOffset;
                var batchAttributes = new List<ShapeAttribute>();
                do
                {
                    ShapeAttribute attribute = new ShapeAttribute();
                    attribute.ArrayType = (VertexArrayType)reader.ReadInt32();
                    attribute.DataType = (VertexDataType)reader.ReadInt32();

                    if (attribute.ArrayType == VertexArrayType.NullAttr)
                        break;

                    batchAttributes.Add(attribute);

                } while (true);

                for (ushort p = 0; p < packetCount; p++)
                {
                    // Packet Location
                    reader.BaseStream.Position = chunkStart + packetLocationOffset;
                    reader.BaseStream.Position += (firstPacketIndex + p) * 0x8; // A Packet Location is 0x8 long, so we skip ahead to the right one.

                    int packetSize = reader.ReadInt32();
                    int packetOffset = reader.ReadInt32();

                    // Read the matrix data for this packet
                    reader.BaseStream.Position = chunkStart + matrixDataOffset + (firstMatrixIndex + p) * 0x08;
                    ushort matrixUnknown0 = reader.ReadUInt16();
                    ushort matrixCount = reader.ReadUInt16();
                    uint matrixFirstIndex = reader.ReadUInt32();

                    // Skip ahead to the actual data.
                    reader.BaseStream.Position = chunkStart + matrixTableOffset + (matrixFirstIndex * 0x2);
                    List<ushort> matrixTable = new List<ushort>();
                    for (int m = 0; m < matrixCount; m++)
                    {
                        matrixTable.Add(reader.ReadUInt16());
                    }

                    // Jump the read head to the location of the primitives for this packet.
                    reader.BaseStream.Position = chunkStart + primitiveDataOffset + packetOffset;
                    int numVertexesAtPacketStart = meshVertexData.PositionMatrixIndexes.Count;

                    uint numPrimitiveBytesRead = 0;
                    while (numPrimitiveBytesRead < packetSize)
                    {
                        // Jump to the primitives
                        // Primitives
                        GXPrimitiveType type = (GXPrimitiveType)reader.ReadByte();
                        // Game pads the chunks out with zeros, so this is the signal for an early break;
                        if (type == 0 || numPrimitiveBytesRead >= packetSize)
                            break;

                        ushort vertexCount = reader.ReadUInt16();

                        meshBatch.PrimitveType = type == GXPrimitiveType.TriangleStrip ? OpenTK.Graphics.OpenGL.PrimitiveType.TriangleStrip : OpenTK.Graphics.OpenGL.PrimitiveType.TriangleFan;
                        //if (type != GXPrimitiveType.TriangleStrip)
                        //{
                        //    WLog.Warning(LogCategory.ModelLoading, null, "Unsupported GXPrimitiveType {0}", type);
                        //}

                        numPrimitiveBytesRead += 0x3; // Advance us by 3 for the Primitive header.

                        for (int v = 0; v < vertexCount; v++)
                        {
                            meshVertexData.Indexes.Add(overallVertexCount);
                            overallVertexCount++;

                            // Iterate through the attribute types. I think the actual vertices are stored in interleaved format,
                            // ie: there's say 13 vertexes but those 13 vertexes will have a pos/color/tex index listed after it
                            // depending on the overall attributes of the file.
                            for (int attrib = 0; attrib < batchAttributes.Count; attrib++)
                            {
                                // Jump to primitive location
                                //reader.BaseStream.Position = chunkStart + primitiveDataOffset + numPrimitiveBytesRead + packetOffset;

                                // Now that we know how big the vertex type is stored in (either a Signed8 or a Signed16) we can read that much data
                                // and then we can use that index and index into
                                int val = 0;
                                uint numBytesRead = 0;
                                switch (batchAttributes[attrib].DataType)
                                {
                                    case VertexDataType.Signed8:
                                        val = reader.ReadByte();
                                        numBytesRead = 1;
                                        break;
                                    case VertexDataType.Signed16:
                                        val = reader.ReadInt16();
                                        numBytesRead = 2;
                                        break;
                                    default:
                                        WLog.Warning(LogCategory.ModelLoading, null, "Unknown Batch Index Type: {0}", batchAttributes[attrib].DataType);
                                        break;
                                }

                                // Now that we know what the index is, we can retrieve it from the appropriate array
                                // and stick it into our vertex. The J3D format removes all duplicate vertex attributes
                                // so we need to re-duplicate them here so that we can feed them to a PC GPU in a normal fashion.
                                switch (batchAttributes[attrib].ArrayType)
                                {
                                    case VertexArrayType.Position:
                                        meshVertexData.Position.Add(vertexData.Position[val]);
                                        break;
                                    case VertexArrayType.PositionMatrixIndex:
                                        meshVertexData.PositionMatrixIndexes.Add(val);
                                        break;
                                    case VertexArrayType.Normal:
                                        meshVertexData.Normal.Add(vertexData.Normal[val]);
                                        break;
                                    case VertexArrayType.Color0:
                                        meshVertexData.Color0.Add(vertexData.Color0[val]);
                                        break;
                                    case VertexArrayType.Color1:
                                        meshVertexData.Color1.Add(vertexData.Color1[val]);
                                        break;
                                    case VertexArrayType.Tex0:
                                        meshVertexData.Tex0.Add(vertexData.Tex0[val]);
                                        break;
                                    case VertexArrayType.Tex1:
                                        meshVertexData.Tex1.Add(vertexData.Tex1[val]);
                                        break;
                                    case VertexArrayType.Tex2:
                                        meshVertexData.Tex2.Add(vertexData.Tex2[val]);
                                        break;
                                    case VertexArrayType.Tex3:
                                        meshVertexData.Tex3.Add(vertexData.Tex3[val]);
                                        break;
                                    case VertexArrayType.Tex4:
                                        meshVertexData.Tex4.Add(vertexData.Tex4[val]);
                                        break;
                                    case VertexArrayType.Tex5:
                                        meshVertexData.Tex5.Add(vertexData.Tex5[val]);
                                        break;
                                    case VertexArrayType.Tex6:
                                        meshVertexData.Tex6.Add(vertexData.Tex6[val]);
                                        break;
                                    case VertexArrayType.Tex7:
                                        meshVertexData.Tex7.Add(vertexData.Tex7[val]);
                                        break;
                                    default:
                                        WLog.Warning(LogCategory.ModelLoading, null, "Unsupported attribType {0}", batchAttributes[attrib].ArrayType);
                                        break;
                                }

                                numPrimitiveBytesRead += numBytesRead;
                            }

                            // Gonna try a weird hack, where if the mesh doesn't have PMI values, we're going to use just use the packet index into the matrixtable
                            // so that all meshes always have PMI values, to abstract out the ones that don't seem to (but still have matrixtable) junk. It's a guess
                            // here.
                            if (batchAttributes.Find(x => x.ArrayType == VertexArrayType.PositionMatrixIndex) == null)
                            {
                                meshVertexData.PositionMatrixIndexes.Add(p);
                            }
                        }

                        // After we write a primitive, write a special null-terminator which signifies the GPU to do a primitive restart for the next tri-strip.
                        meshVertexData.Indexes.Add(0xFFFF);
                    }

                    // The Matrix Table is per-packet, so we need to reach into the the matrix table after processing each packet
                    // and transform the indexes. Yuck. Yay.
                    for (int j = numVertexesAtPacketStart; j < meshVertexData.PositionMatrixIndexes.Count; j++)
                    {
                        // Yes you divide this by 3. No, no one knows why. $20 to the person who figures out why.
                        meshBatch.drawIndexes.Add(matrixTable[meshVertexData.PositionMatrixIndexes[j] / 3]);
                    }
                }

                meshBatch.Vertices = meshVertexData.Position.ToArray();
                meshBatch.Color0 = meshVertexData.Color0.ToArray();
                meshBatch.Color1 = meshVertexData.Color1.ToArray();
                meshBatch.TexCoord0 = meshVertexData.Tex0.ToArray();
                meshBatch.TexCoord1 = meshVertexData.Tex0.ToArray();
                meshBatch.TexCoord2 = meshVertexData.Tex0.ToArray();
                meshBatch.TexCoord3 = meshVertexData.Tex0.ToArray();
                meshBatch.TexCoord4 = meshVertexData.Tex0.ToArray();
                meshBatch.TexCoord5 = meshVertexData.Tex0.ToArray();
                meshBatch.TexCoord6 = meshVertexData.Tex0.ToArray();
                meshBatch.TexCoord7 = meshVertexData.Tex0.ToArray();
                meshBatch.Indexes = meshVertexData.Indexes.ToArray();
                meshBatch.PositionMatrixIndexs = meshVertexData.PositionMatrixIndexes; // This should be obsolete as they should be transformed already.
            }
        }
예제 #5
0
파일: JNT1.cs 프로젝트: CryZe/WindEditor2
        private static List<SkeletonBone> LoadJNT1SectionFromStream(EndianBinaryReader reader, long chunkStart)
        {
            List<SkeletonBone> skeletonBones = new List<SkeletonBone>();

            ushort numJoints = reader.ReadUInt16();
            ushort padding = reader.ReadUInt16();
            uint jointDataOffset = reader.ReadUInt32(); // Relative to JNT1 Header Start
            uint jointRemapOffset = reader.ReadUInt32();
            uint stringTableOffset = reader.ReadUInt32();

            // Grab the joint names from file
            reader.BaseStream.Position = chunkStart + stringTableOffset;
            StringTable jointNames = StringTable.FromStream(reader);

            // This is always 0 to (numJoints-1) - unsure if it's a joint
            // remap (likely) or a string-table remap (less likely). It's unknown
            // if any models don't follow this 0 to (n-1) pattern.
            ushort[] jointRemaps = new ushort[numJoints];
            reader.BaseStream.Position = chunkStart + jointRemapOffset;
            for (int j = 0; j < numJoints; j++)
                jointRemaps[j] = reader.ReadUInt16();

            // Grab the actual joints
            reader.BaseStream.Position = chunkStart + jointDataOffset;
            for (int j = 0; j < numJoints; j++)
            {
                SkeletonBone bone = new SkeletonBone();

                bone.Name = jointNames[j];
                ushort unknown1 = reader.ReadUInt16();  // Values of 0, 2 or 1. yaz0r calls it Matrix Type (referring to 'MatrixTable' which is an index into DRW1 - Draw type?
                                                        // If value is 1 or 2 then Bounding Box / Radius is Vector3.Zero / 0f
                                                        // And seems to be 0 if a joint has direct non-joint children (Maybe 0 is a 'bone with children' and the BBMin/Max contain
                                                        // the bounds of children?
                ushort unknown2 = reader.ReadUInt16();  // No one seems to know what it is, often 0xFF or 0 or 1. May be two individual bytes with a pad afterwards.

                for (int f = 0; f < 3; f++)
                    bone.Scale[f] = reader.ReadSingle();

                Vector3 eulerAngles = new Vector3();
                for (int f = 0; f < 3; f++)
                    eulerAngles[f] = (reader.ReadInt16() * (180 / 32786f));

                Quaternion xAxis = Quaternion.FromAxisAngle(new Vector3(1, 0, 0), eulerAngles.X * MathE.Deg2Rad);
                Quaternion yAxis = Quaternion.FromAxisAngle(new Vector3(0, 1, 0), eulerAngles.Y * MathE.Deg2Rad);
                Quaternion zAxis = Quaternion.FromAxisAngle(new Vector3(0, 0, 1), eulerAngles.Z * MathE.Deg2Rad);

                // Swizzling to the ZYX order seems to be the right one.
                Quaternion finalRot = zAxis * yAxis * xAxis;

                bone.Rotation = finalRot;
                Trace.Assert(reader.ReadUInt16() == 0xFFFF); // Padding
                for (int f = 0; f < 3; f++)
                    bone.Translation[f] = reader.ReadSingle();
                bone.BoundingSphereDiameter = reader.ReadSingle();
                for (int f = 0; f < 3; f++)
                    bone.BoundingBoxMin[f] = reader.ReadSingle();
                for (int f = 0; f < 3; f++)
                    bone.BoundingBoxMax[f] = reader.ReadSingle();

                skeletonBones.Add(bone);
            }
            return skeletonBones;
        }
예제 #6
0
        public static ZUD FromStream(EndianBinaryReader reader)
        {
            /*=====================================================================
                ZUD HEADER
            =====================================================================*/
            byte IDCharacter = reader.ReadByte();
            byte IDWeapon = reader.ReadByte();
            byte IDWeaponCategory = reader.ReadByte();
            byte IDWeaponMaterial = reader.ReadByte();
            byte IDShield = reader.ReadByte();
            byte IDShieldMaterial = reader.ReadByte();
            byte unknown = reader.ReadByte();
            reader.SkipByte();
            UInt32 ptrCharacterSHP = reader.ReadUInt32();
            UInt32 lenCharacterSHP = reader.ReadUInt32();
            UInt32 ptrWeaponWEP = reader.ReadUInt32();
            UInt32 lenWeaponWEP= reader.ReadUInt32();
            UInt32 ptrShieldWEP = reader.ReadUInt32();
            UInt32 lenShieldWEP = reader.ReadUInt32();
            UInt32 ptrCommonSEQ = reader.ReadUInt32();
            UInt32 lenCommonSEQ = reader.ReadUInt32();
            UInt32 ptrBattleSEQ = reader.ReadUInt32();
            UInt32 lenBattleSEQ = reader.ReadUInt32();

            /*=====================================================================
                STREAM READER
            =====================================================================*/
            ZUD zud = new ZUD();

            if (lenCharacterSHP != 0)
            {
                zud.Character = SHPLoader.FromStream(reader);
            }

            if (lenWeaponWEP != 0)
            {
                zud.HasWeapon = true;
                reader.BaseStream.Seek(ptrWeaponWEP, System.IO.SeekOrigin.Begin);
                zud.Weapon = WEPLoader.FromStream(reader);
            }

            if (lenShieldWEP != 0)
            {
                zud.HasShield = true;
                reader.BaseStream.Seek(ptrShieldWEP, System.IO.SeekOrigin.Begin);
                zud.Shield = WEPLoader.FromStream(reader);
            }

            if (lenCommonSEQ != 0)
            {
                zud.HasCommon = true;
                reader.BaseStream.Seek(ptrCommonSEQ, System.IO.SeekOrigin.Begin);
                zud.Common = SEQLoader.FromStream(reader, zud.Character);
            }

            if (lenBattleSEQ != 0)
            {
                zud.HasBattle = true;
                reader.BaseStream.Seek(ptrBattleSEQ, System.IO.SeekOrigin.Begin);
                zud.Battle = SEQLoader.FromStream(reader, zud.Character);
            }

            return zud;
        }