Ejemplo n.º 1
0
        protected unsafe Mesh ReadSubMesh(GensReader reader, float scale = 1)
        {
            uint offset; // Generic uint reused for different data

            // Offsets
            uint materialNameOffset, faceCount, faceOffset, vertexCount,
                 vertexSize, vertexOffset, vertexFormatOffset, boneCount,
                 boneOffset, textureUnitCount, textureUnitOffsetsOffset;

            if (Header.RootNodeType == PS3RootType)
            {
                uint unknownOffset1 = reader.ReadUInt32(); // VertexFormat?
                materialNameOffset       = reader.ReadUInt32();
                boneCount                = reader.ReadUInt32();
                boneOffset               = reader.ReadUInt32(); // ?
                textureUnitCount         = reader.ReadUInt32();
                textureUnitOffsetsOffset = reader.ReadUInt32();

                // Possibly vertex format?
                reader.JumpTo(unknownOffset1, false);
                int unknown1 = reader.ReadInt32();
                int unknown2 = reader.ReadInt32();
                int unknown3 = reader.ReadInt32();
                int unknown4 = reader.ReadInt32();

                uint unknownOffset2 = reader.ReadUInt32();
                uint unknownCount1  = reader.ReadUInt32();
                vertexOffset = reader.ReadUInt32();

                // TODO
                throw new NotImplementedException(
                          "ERROR: Cannot yet read PS3 terrain-models");
            }
            else
            {
                materialNameOffset       = reader.ReadUInt32();
                faceCount                = reader.ReadUInt32();
                faceOffset               = reader.ReadUInt32();
                vertexCount              = reader.ReadUInt32();
                vertexSize               = reader.ReadUInt32();
                vertexOffset             = reader.ReadUInt32();
                vertexFormatOffset       = reader.ReadUInt32();
                boneCount                = reader.ReadUInt32();
                boneOffset               = reader.ReadUInt32();
                textureUnitCount         = reader.ReadUInt32();
                textureUnitOffsetsOffset = reader.ReadUInt32();
            }

            // Faces
            var faces = new ushort[faceCount];

            reader.JumpTo(faceOffset, false);

            // Convert faces from triangle strips
            // Basically taken from LibGens because I honestly
            // don't think there's another way to do it lol
            int    newStrip = 3, newIndex = 0;
            ushort face1 = 0, face2 = 0, face3 = 0, t;
            uint   count = 0, faceIndex = 0;

            // HACK: We go through the whole loop twice, the first time just
            // to get the new faceCount, second time to actually get the faces.
            // This way we don't have to do any copying (yes, lists do it too)
            // which is a huge performance improvement.
            for (uint i = 0; i < faceCount; ++i)
            {
                t        = reader.ReadUInt16();
                faces[i] = t;

                if (t == 0xFFFF)
                {
                    newStrip = 3;
                    newIndex = 0;
                }
                else
                {
                    newStrip -= 1;
                    face3     = face2;
                    face2     = face1;
                    face1     = t;

                    if (newStrip == 0)
                    {
                        if ((face1 != face2) && (face2 != face3) && (face1 != face3))
                        {
                            count += 3;
                        }

                        newStrip = 1;
                        ++newIndex;
                    }
                }
            }

            // Alright, we've got the new count!
            // Time to actually get the faces.
            var newFaces = new uint[count];

            newStrip = 3; newIndex = 0;
            face1    = face2 = face3 = 0;

            for (uint i = 0; i < faceCount; ++i)
            {
                t = faces[i];
                if (t == 0xFFFF)
                {
                    newStrip = 3;
                    newIndex = 0;
                }
                else
                {
                    newStrip -= 1;
                    face3     = face2;
                    face2     = face1;
                    face1     = t;

                    if (newStrip == 0)
                    {
                        if ((face1 != face2) && (face2 != face3) && (face1 != face3))
                        {
                            if ((newIndex % 2) == 0)
                            {
                                newFaces[faceIndex]   = face1;
                                newFaces[++faceIndex] = face2;
                                newFaces[++faceIndex] = face3;
                            }
                            else
                            {
                                newFaces[faceIndex]   = face3;
                                newFaces[++faceIndex] = face2;
                                newFaces[++faceIndex] = face1;
                            }

                            ++faceIndex;
                        }

                        newStrip = 1;
                        ++newIndex;
                    }
                }
            }

            // Vertex Format
            var vertexFormat = new List <VertexFormatElement>();
            var fs           = reader.BaseStream;

            reader.JumpTo(vertexFormatOffset, false);

            for (byte i = 0; i < 0xFF; ++i)
            {
                offset = reader.ReadUInt32();
                if (offset > 1000)
                {
                    break;
                }

                var element = new VertexFormatElement()
                {
                    Offset = offset,
                    Type   = reader.ReadUInt32(),
                    ID     = reader.ReadUInt16(),
                    Index  = reader.ReadByte()
                };

                vertexFormat.Add(element);
                fs.ReadByte();
            }

            // Vertices
            var data = new float[vertexCount * Mesh.StructureLength];
            var idc  = new float[vertexCount * 4]; // TODO: Care

            // HACK: Read this stuff using pointers to avoid boundry checks.
            fixed(float *dataStart = data)
            fixed(float *idcp = idc)
            {
                float *dp; // Pointer to data
                uint   structStart;

                for (uint i = 0; i < vertexCount; ++i)
                {
                    // Set default vertex coloring
                    structStart = (i * Mesh.StructureLength);
                    dp          = dataStart + structStart + Mesh.ColorPos;

                    // RGBA = 1, 1, 1, 1
                    *dp = 1; *++dp = 1;
                    *++dp = 1; *++dp = 1;

                    // Just to be accurate
                    offset = (vertexOffset + (i * vertexSize));
                    foreach (var element in vertexFormat)
                    {
                        reader.JumpTo(offset + element.Offset, false);
                        switch (element.ID)
                        {
                        // Vertex Positions
                        case 0:
                            element.Read(reader, dataStart +
                                         structStart + Mesh.VertPos, scale);
                            break;

                        // Bone Weights
                        case 1:
                            // TODO
                            element.Read(reader, idcp);
                            break;

                        // Bone Indices
                        case 2:
                            // TODO
                            element.Read(reader, idcp);
                            break;

                        // Normals
                        case 3:
                            // TODO: Do I need to scale normals?
                            element.Read(reader, dataStart +
                                         structStart + Mesh.NormPos);
                            break;

                        // UV Coordinates
                        case 5:
                            if (element.Index < 1)
                            {
                                element.Read(reader, dataStart +
                                             structStart + Mesh.UVPos);
                            }
                            else
                            {
                                // TODO: Read multi-UV Channels
                                element.Read(reader, idcp);
                            }
                            break;

                        // Tangents
                        case 6:
                            // TODO
                            element.Read(reader, idcp);
                            break;

                        // Binormals
                        case 7:
                            // TODO
                            element.Read(reader, idcp);
                            break;

                        // Vertex Colors
                        case 10:
                            element.Read(reader, dataStart +
                                         structStart + Mesh.ColorPos);
                            break;
                        }
                    }

                    ++dp;
                }
            }

            // Bones
            reader.JumpTo(boneOffset, false);
            var bones = reader.ReadBytes((int)boneCount);

            // Texture Unit Offsets
            var textureUnitOffsets = new uint[textureUnitCount];

            reader.JumpTo(textureUnitOffsetsOffset, false);

            for (uint i = 0; i < textureUnitCount; ++i)
            {
                textureUnitOffsets[i] = reader.ReadUInt32();
            }

            // Texture Units
            for (uint i = 0; i < textureUnitCount; ++i)
            {
                // TODO: Actually use this data
                reader.JumpTo(textureUnitOffsets[i], false);
                uint textureUnitNameOffset = reader.ReadUInt32();
                uint textureUnitID         = reader.ReadUInt32();

                // Texture Unit Name
                reader.JumpTo(textureUnitNameOffset, false);
                string textureUnitName = reader.ReadNullTerminatedString();
            }

            // Material Name
            reader.JumpTo(materialNameOffset, false);
            string materialName = reader.ReadNullTerminatedString();

            // Generate a HedgeLib mesh and add it to the array
            var mesh = new Mesh()
            {
                VertexData   = data,
                Triangles    = newFaces,
                MaterialName = materialName
            };

            Meshes.Add(mesh);
            return(mesh);
        }
        public override void Load(Stream fileStream)
        {
            // Header
            var reader = new GensReader(fileStream);

            Header = reader.ReadHeader();

            // Root Node
            uint shaderOffset    = reader.ReadUInt32();
            uint subShaderOffset = reader.ReadUInt32();
            uint texsetOffset    = reader.ReadUInt32();
            uint texturesOffset  = reader.ReadUInt32();

            MaterialFlag      = reader.ReadByte(); // ?
            NoBackFaceCulling = reader.ReadBoolean();
            AdditiveBlending  = reader.ReadBoolean();
            UnknownFlag1      = reader.ReadByte();

            byte paramCount   = reader.ReadByte();
            byte padding1     = reader.ReadByte();
            byte unknownFlag2 = reader.ReadByte(); // Might be an enum, might just be a boolean?
            byte textureCount = reader.ReadByte();

            uint paramsOffset = reader.ReadUInt32();
            uint padding2     = reader.ReadUInt32();
            uint unknown1     = reader.ReadUInt32();

            // Padding/Unknown Value Checks
            if (padding1 != 0)
            {
                Console.WriteLine($"WARNING: Material Padding1 != 0 ({padding1})");
            }

            if (unknownFlag2 > 1)
            {
                Console.WriteLine($"WARNING: Material UnknownFlag2 > 1 ({unknownFlag2})");
            }

            if (padding2 != 0)
            {
                Console.WriteLine($"WARNING: Material Padding2 != 0 ({padding2})");
            }

            // Shader Name
            reader.JumpTo(shaderOffset, false);
            ShaderName = reader.ReadNullTerminatedString();

            // Sub-Shader Name
            reader.JumpTo(subShaderOffset, false);
            SubShaderName = reader.ReadNullTerminatedString();

            // Parameter Offsets
            var paramOffsets = new uint[paramCount];

            reader.JumpTo(paramsOffset, false);

            for (uint i = 0; i < paramCount; ++i)
            {
                paramOffsets[i] = reader.ReadUInt32();
            }

            // Parameters
            parameters.Clear();
            for (uint i = 0; i < paramCount; ++i)
            {
                reader.JumpTo(paramOffsets[i], false);
                var param = new Parameter()
                {
                    ParamFlag1 = reader.ReadUInt16(),
                    ParamFlag2 = reader.ReadUInt16()
                };

                uint paramNameOffset  = reader.ReadUInt32();
                uint paramValueOffset = reader.ReadUInt32();

                // Parameter Name
                reader.JumpTo(paramNameOffset, false);
                param.Name = reader.ReadNullTerminatedString();

                // Parameter Value
                reader.JumpTo(paramValueOffset, false);
                param.Value = reader.ReadVector4();

                parameters.Add(param);
            }

            // Texset
            reader.JumpTo(texsetOffset, false);
            if (Header.RootNodeType == 1) // TODO: Maybe check for textureCount < 1 instead?
            {
                TexsetName = reader.ReadNullTerminatedString();
            }
            else
            {
                Texset.Read(reader, textureCount);

                // Texture Offsets
                var texOffsets = new uint[textureCount];
                reader.JumpTo(texturesOffset, false);

                for (uint i = 0; i < textureCount; ++i)
                {
                    texOffsets[i] = reader.ReadUInt32();
                }

                // Textures
                for (int i = 0; i < textureCount; ++i)
                {
                    reader.JumpTo(texOffsets[i], false);
                    Texset.Textures[i].Read(reader);
                }
            }
        }