示例#1
0
        public override bool Execute(List <string> args)
        {
            var initialStringIDCount = Info.StringIDs.Strings.Count;

            bool isNew = false;

            if (args.Count == 3)
            {
                if (args[0] != "new")
                {
                    return(false);
                }
                isNew = true;
                args.Remove("new");
            }

            if (args.Count != 2)
            {
                return(false);
            }

            //
            // Verify the Blam render_model tag
            //

            var renderModelName = args[0];

            CacheBase.IndexItem item = null;

            Console.WriteLine("Verifying Blam tag...");

            foreach (var tag in BlamCache.IndexItems)
            {
                if ((tag.ClassCode == "mode" || tag.ClassCode == "sbsp") && tag.Filename == renderModelName)
                {
                    item = tag;
                    break;
                }
            }

            if (item == null)
            {
                Console.WriteLine("Blam tag does not exist: " + args[0]);
                return(false);
            }

            //
            // Verify the ED render_model tag
            //

            Console.WriteLine("Verifying ED tag index...");

            int edRenderModelIndex;

            if (!int.TryParse(args[1], NumberStyles.HexNumber, null, out edRenderModelIndex) ||
                (edRenderModelIndex >= Info.Cache.Tags.Count))
            {
                Console.WriteLine("Invalid tag index: " + args[1]);
                return(false);
            }

            var edTag = Info.Cache.Tags[edRenderModelIndex];

            if (edTag.Group.Name != Info.StringIDs.GetStringID("render_model"))
            {
                Console.WriteLine("Specified tag index is not a render_model: " + args[1]);
                return(false);
            }

            //
            // Deserialize the selected render_model
            //

            Console.WriteLine("Loading ED render_model tag...");

            TagDefinitions.RenderModel renderModel;

            using (var cacheStream = Info.CacheFile.Open(FileMode.Open, FileAccess.ReadWrite))
            {
                try
                {
                    var context = new Serialization.TagSerializationContext(cacheStream, Info.Cache, Info.StringIDs, Info.Cache.Tags[(int)edRenderModelIndex]);
                    renderModel = Info.Deserializer.Deserialize <TagDefinitions.RenderModel>(context);
                }
                catch
                {
                    Console.WriteLine("Failed to deserialize selected render_model tag: " + edRenderModelIndex);
                    return(true);
                }
            }

            //
            // Load the Blam render_model tag raw
            //

            var isBSP = item.ClassCode == "sbsp";

            scenario_structure_bsp sbsp = null;
            render_model           mode = null;

            if (isBSP)
            {
                sbsp = DefinitionsManager.sbsp(BlamCache, item);
                sbsp.LoadRaw();
            }
            else
            {
                mode = DefinitionsManager.mode(BlamCache, item);
                mode.LoadRaw();
            }

            //
            // Duplicate the render_model tag we're injecting over
            //

            TagInstance newTag;

            if (isNew)
            {
                Console.WriteLine("Duplicating selected render_model tag...");

                if (!new DuplicateTagCommand(Info).Execute(new List <string> {
                    edRenderModelIndex.ToString("X8")
                }))
                {
                    Console.WriteLine("Failed to duplicate render_model tag: " + edRenderModelIndex);
                    return(false);
                }

                newTag = Info.Cache.Tags[Info.Cache.Tags.Count - 1];
            }
            else
            {
                newTag = edTag;
            }

            //
            // Start porting the model
            //

            RenderModelBuilder builder = new RenderModelBuilder(DefinitionSet.HaloOnline106708);

            var blamNodes = isBSP ?
                            new List <render_model.Node>
            {
                new render_model.Node
                {
                    Name             = "default",
                    ParentIndex      = -1,
                    FirstChildIndex  = -1,
                    NextSiblingIndex = -1,
                    Position         = new Vector(),
                    Rotation         = new Vector(0, 0, 0, -1),
                    TransformScale   = 1,
                    TransformMatrix  = new Matrix4x3(
                        1, 0, 0,
                        0, 1, 0,
                        0, 0, 1,
                        0, 0, 0),
                    DistanceFromParent = 0
                }
            } : mode.Nodes;

            foreach (var node in blamNodes)
            {
                var nodeNameId = Info.StringIDs.GetStringID(node.Name);

                builder.AddNode(
                    new TagDefinitions.RenderModel.Node
                {
                    Name               = nodeNameId.Index == 0 && node.Name != "" ? nodeNameId = Info.StringIDs.Add(node.Name) : nodeNameId,
                    ParentNode         = (short)node.ParentIndex,
                    FirstChildNode     = (short)node.FirstChildIndex,
                    NextSiblingNode    = (short)node.NextSiblingIndex,
                    ImportNode         = 0,
                    DefaultTranslation = new Common.Vector3(node.Position.X, node.Position.Y, node.Position.Z),
                    DefaultRotation    = new Common.Vector4(node.Rotation.X, node.Rotation.Y, node.Rotation.Z, node.Rotation.W),
                    DefaultScale       = node.TransformScale,
                    InverseForward     = new Common.Vector3(node.TransformMatrix.m11, node.TransformMatrix.m12, node.TransformMatrix.m13),
                    InverseLeft        = new Common.Vector3(node.TransformMatrix.m21, node.TransformMatrix.m22, node.TransformMatrix.m23),
                    InverseUp          = new Common.Vector3(node.TransformMatrix.m31, node.TransformMatrix.m32, node.TransformMatrix.m33),
                    InversePosition    = new Common.Vector3(node.TransformMatrix.m41, node.TransformMatrix.m42, node.TransformMatrix.m43),
                    DistanceFromParent = node.DistanceFromParent
                });
            }

            //
            // Create empty materials for now...
            //

            var blamShaders = isBSP ? sbsp.Shaders : mode.Shaders;

            foreach (var shader in blamShaders)
            {
                builder.AddMaterial(
                    new RenderMaterial
                {
                    RenderMethod = Info.Cache.Tags[0x101F]
                });
            }

            //
            // Build the model regions
            //

            if (isBSP)
            {
                builder.BeginRegion(Info.StringIDs.GetStringID("default"));
                builder.BeginPermutation(Info.StringIDs.GetStringID("default"));

                foreach (var section in sbsp.ModelSections)
                {
                    if (section.Submeshes.Count == 0)
                    {
                        continue;
                    }

                    var rigidVertices = new List <RigidVertex>();

                    VertexValue v;
                    if (section.Vertices != null)
                    {
                        foreach (var vertex in section.Vertices)
                        {
                            vertex.TryGetValue("position", 0, out v);
                            var position = new Common.Vector4(v.Data.X, v.Data.Y, v.Data.Z, 1);

                            vertex.TryGetValue("normal", 0, out v);
                            var normal = new Common.Vector3(v.Data.I, v.Data.J, v.Data.K);

                            vertex.TryGetValue("texcoords", 0, out v);
                            var texcoord = new Common.Vector2(v.Data.X, v.Data.Y);

                            vertex.TryGetValue("tangent", 0, out v);
                            var tangent = new Common.Vector4(v.Data.X, v.Data.Y, v.Data.Z, 1);

                            vertex.TryGetValue("binormal", 0, out v);
                            var binormal = new Common.Vector3(v.Data.X, v.Data.Y, v.Data.Z);

                            rigidVertices.Add(
                                new RigidVertex
                            {
                                Position = position,
                                Normal   = normal,
                                Texcoord = texcoord,
                                Tangent  = tangent,
                                Binormal = binormal
                            });
                        }
                    }

                    // Build the section's subparts

                    builder.BeginMesh();

                    var indices = new List <ushort>();

                    foreach (var submesh in section.Submeshes)
                    {
                        builder.BeginPart((short)submesh.ShaderIndex, (ushort)submesh.FaceIndex, (ushort)submesh.FaceCount, (ushort)submesh.VertexCount);
                        for (var j = 0; j < submesh.SubsetCount; j++)
                        {
                            var subpart = section.Subsets[submesh.SubsetIndex + j];
                            builder.DefineSubPart((ushort)subpart.FaceIndex, (ushort)subpart.FaceCount, (ushort)subpart.VertexCount);
                        }
                        builder.EndPart();
                    }

                    builder.BindRigidVertexBuffer(rigidVertices, 0);
                    builder.BindIndexBuffer(section.Indices.Select(index => (ushort)index), PrimitiveType.TriangleList);

                    builder.EndMesh();
                }

                builder.EndPermutation();
                builder.EndRegion();

                foreach (var instance in sbsp.GeomInstances)
                {
                    var mesh = builder.Meshes[instance.SectionIndex];

                    if (mesh.VertexFormat == VertexBufferFormat.Rigid)
                    {
                        foreach (var i in mesh.RigidVertices)
                        {
                            i.Position = new Common.Vector4(
                                i.Position.X + instance.TransformMatrix.m41,
                                i.Position.Y + instance.TransformMatrix.m42,
                                i.Position.Z + instance.TransformMatrix.m43,
                                i.Position.W);
                        }
                    }

                    else if (mesh.VertexFormat == VertexBufferFormat.World)
                    {
                        foreach (var i in mesh.WorldVertices)
                        {
                            i.Position = new Common.Vector4(
                                i.Position.X + instance.TransformMatrix.m41,
                                i.Position.Y + instance.TransformMatrix.m42,
                                i.Position.Z + instance.TransformMatrix.m43,
                                i.Position.W);
                        }
                    }

                    else if (mesh.VertexFormat == VertexBufferFormat.Skinned)
                    {
                        foreach (var i in mesh.SkinnedVertices)
                        {
                            i.Position = new Common.Vector4(
                                i.Position.X + instance.TransformMatrix.m41,
                                i.Position.Y + instance.TransformMatrix.m42,
                                i.Position.Z + instance.TransformMatrix.m43,
                                i.Position.W);
                        }
                    }
                }
            }

            else
            {
                foreach (var region in mode.Regions)
                {
                    var regionNameId = Info.StringIDs.GetStringID(region.Name);

                    builder.BeginRegion(regionNameId.Index == 0 && region.Name != "" ? regionNameId = Info.StringIDs.Add(region.Name) : regionNameId);

                    foreach (var permutation in region.Permutations)
                    {
                        if (permutation.PieceCount <= 0 || permutation.PieceIndex == -1)
                        {
                            continue;
                        }

                        var permutationNameId = Info.StringIDs.GetStringID(permutation.Name);

                        builder.BeginPermutation(permutationNameId.Index == 0 && permutation.Name != "" ? permutationNameId = Info.StringIDs.Add(permutation.Name) : permutationNameId);

                        for (var i = permutation.PieceIndex; i < permutation.PieceIndex + permutation.PieceCount; i++)
                        {
                            var section = mode.ModelSections[i];

                            if (section.Submeshes.Count == 0 || section.Vertices == null)
                            {
                                continue;
                            }

                            //
                            // Collect the section's vertices
                            //

                            var skinnedVertices = new List <SkinnedVertex>();
                            var rigidVertices   = new List <RigidVertex>();

                            VertexValue v;
                            bool        isSkinned = section.Vertices[0].TryGetValue("blendindices", 0, out v) && section.NodeIndex == 255;
                            bool        isBoned   = section.Vertices[0].FormatName.Contains("rigid_boned");

                            foreach (var vertex in section.Vertices)
                            {
                                vertex.TryGetValue("position", 0, out v);
                                var position = new Common.Vector4(v.Data.X, v.Data.Y, v.Data.Z, 1);

                                vertex.TryGetValue("normal", 0, out v);
                                var normal = new Common.Vector3(v.Data.I, v.Data.J, v.Data.K);

                                vertex.TryGetValue("texcoords", 0, out v);
                                var texcoord = new Common.Vector2(v.Data.X, v.Data.Y);

                                vertex.TryGetValue("tangent", 0, out v);
                                var tangent = new Common.Vector4(v.Data.X, v.Data.Y, v.Data.Z, 1);

                                vertex.TryGetValue("binormal", 0, out v);
                                var binormal = new Common.Vector3(v.Data.X, v.Data.Y, v.Data.Z);

                                rigidVertices.Add(
                                    new RigidVertex
                                {
                                    Position = position,
                                    Normal   = normal,
                                    Texcoord = texcoord,
                                    Tangent  = tangent,
                                    Binormal = binormal
                                });

                                if (isBoned)
                                {
                                    var blendIndices = new List <byte>();

                                    vertex.TryGetValue("blendindices", 0, out v);

                                    blendIndices.Add((byte)v.Data.A);
                                    blendIndices.Add((byte)v.Data.B);
                                    blendIndices.Add((byte)v.Data.C);
                                    blendIndices.Add((byte)v.Data.D);

                                    skinnedVertices.Add(new SkinnedVertex
                                    {
                                        Position     = position,
                                        Normal       = normal,
                                        Texcoord     = texcoord,
                                        Tangent      = tangent,
                                        Binormal     = binormal,
                                        BlendIndices = blendIndices.ToArray(),
                                        BlendWeights = new[] { 1.0f, 0.0f, 0.0f, 0.0f }
                                    });
                                }
                                else if (isSkinned)
                                {
                                    var blendIndices = new List <byte>();
                                    var blendWeights = new List <float>();

                                    vertex.TryGetValue("blendindices", 0, out v);

                                    blendIndices.Add((byte)v.Data.A);
                                    blendIndices.Add((byte)v.Data.B);
                                    blendIndices.Add((byte)v.Data.C);
                                    blendIndices.Add((byte)v.Data.D);

                                    vertex.TryGetValue("blendweight", 0, out v);

                                    blendWeights.Add(v.Data.A);
                                    blendWeights.Add(v.Data.B);
                                    blendWeights.Add(v.Data.C);
                                    blendWeights.Add(v.Data.D);

                                    skinnedVertices.Add(new SkinnedVertex
                                    {
                                        Position     = position,
                                        Normal       = normal,
                                        Texcoord     = texcoord,
                                        Tangent      = tangent,
                                        Binormal     = binormal,
                                        BlendIndices = blendIndices.ToArray(),
                                        BlendWeights = blendWeights.ToArray()
                                    });
                                }
                            }

                            bool isRigid = false;

                            if (skinnedVertices.Count == 0)
                            {
                                isRigid = rigidVertices.Count != 0;
                            }

                            //
                            // Build the section's submeshes
                            //

                            builder.BeginMesh();

                            var indices = new List <ushort>();

                            foreach (var submesh in section.Submeshes)
                            {
                                builder.BeginPart((short)submesh.ShaderIndex, (ushort)submesh.FaceIndex, (ushort)submesh.FaceCount, (ushort)submesh.VertexCount);
                                for (var j = 0; j < submesh.SubsetCount; j++)
                                {
                                    var subpart = section.Subsets[submesh.SubsetIndex + j];
                                    builder.DefineSubPart((ushort)subpart.FaceIndex, (ushort)subpart.FaceCount, (ushort)subpart.VertexCount);
                                }
                                builder.EndPart();
                            }

                            if (isRigid)
                            {
                                builder.BindRigidVertexBuffer(rigidVertices, (sbyte)section.NodeIndex);
                            }
                            else if (isSkinned || isBoned)
                            {
                                builder.BindSkinnedVertexBuffer(skinnedVertices);
                            }
                            builder.BindIndexBuffer(section.Indices.Select(index => (ushort)index), PrimitiveType.TriangleStrip);

                            builder.EndMesh();
                        }

                        builder.EndPermutation();
                    }

                    builder.EndRegion();
                }
            }

            //
            // Finalize the new render_model tag
            //

            var resourceStream = new MemoryStream();
            var newRenderModel = builder.Build(Info.Serializer, resourceStream);

            var renderModelNameStringID = Info.StringIDs.GetStringID(isBSP ? "default" : mode.Name);

            newRenderModel.Name = renderModelNameStringID.Index == -1 ?
                                  renderModelNameStringID = Info.StringIDs.Add(isBSP ? "default" : mode.Name) :
                                                            renderModelNameStringID;

            //
            // Add the markers to the new render_model
            //

            newRenderModel.MarkerGroups = new List <TagDefinitions.RenderModel.MarkerGroup>();

            var blamMarkerGroups = isBSP ? new List <render_model.MarkerGroup>() : mode.MarkerGroups;

            foreach (var markerGroup in blamMarkerGroups)
            {
                var markerGroupNameId = Info.StringIDs.GetStringID(markerGroup.Name);

                if (markerGroupNameId.Index == -1)
                {
                    markerGroupNameId = Info.StringIDs.Add(markerGroup.Name);
                }

                newRenderModel.MarkerGroups.Add(
                    new TagDefinitions.RenderModel.MarkerGroup
                {
                    Name    = markerGroupNameId,
                    Markers = markerGroup.Markers.Select(marker =>
                                                         new TagDefinitions.RenderModel.MarkerGroup.Marker
                    {
                        RegionIndex      = (sbyte)marker.RegionIndex,
                        PermutationIndex = (sbyte)marker.PermutationIndex,
                        NodeIndex        = (sbyte)marker.NodeIndex,
                        Unknown3         = 0,
                        Translation      = new Common.Vector3(marker.Position.X, marker.Position.Y, marker.Position.Z),
                        Rotation         = new Common.Vector4(marker.Rotation.X, marker.Rotation.Y, marker.Rotation.Z, marker.Rotation.W),
                        Scale            = marker.Scale
                    }).ToList()
                });
            }

            //
            // Disable rigid nodes on skinned meshes
            //

            foreach (var mesh in newRenderModel.Geometry.Meshes)
            {
                if (mesh.Type == VertexType.Skinned)
                {
                    mesh.RigidNodeIndex = -1;
                }
            }

            //
            // Add a new resource for the model data
            //

            Console.WriteLine("Writing resource data...");

            var resources = new ResourceDataManager();

            resources.LoadCachesFromDirectory(Info.CacheFile.DirectoryName);
            resourceStream.Position = 0;
            resources.Add(newRenderModel.Geometry.Resource, ResourceLocation.Resources, resourceStream);

            using (var cacheStream = Info.CacheFile.Open(FileMode.Open, FileAccess.ReadWrite))
            {
                Console.WriteLine("Writing tag data...");

                newRenderModel.Geometry.Resource.Owner = newTag;

                var context = new Serialization.TagSerializationContext(cacheStream, Info.Cache, Info.StringIDs, newTag);
                Info.Serializer.Serialize(context, newRenderModel);
            }

            resourceStream.Close();

            //
            // Save new string_ids
            //

            if (Info.StringIDs.Strings.Count != initialStringIDCount)
            {
                Console.WriteLine("Saving string_ids...");

                using (var stringIdStream = Info.StringIDsFile.Open(FileMode.Open, FileAccess.ReadWrite))
                    Info.StringIDs.Save(stringIdStream);
            }

            //
            // Done!
            //

            Console.WriteLine("Ported render_model \"" + renderModelName + "\" successfully!");

            return(true);
        }
示例#2
0
        public override bool Execute(List <string> args)
        {
            if (args.Count < 1 || args.Count > 2)
            {
                return(false);
            }

            TagInstance destination = _cache.Tags[0x3317];

            if (args.Count == 2)
            {
                destination = ArgumentParser.ParseTagIndex(_cache, args[0]);

                if (!destination.IsInGroup("mode"))
                {
                    Console.WriteLine("Specified tag is not a render_model: " + args[0]);
                    return(false);
                }

                args = args.Skip(1).ToList();
            }

            var builder = new RenderModelBuilder(_info.Version);

            // Add a root node
            var node = builder.AddNode(new RenderModel.Node
            {
                Name            = _stringIds.GetStringId("street_cone"),
                ParentNode      = -1,
                FirstChildNode  = -1,
                NextSiblingNode = -1,
                DefaultRotation = new Vector4(0, 0, 0, -1),
                DefaultScale    = 1,
                InverseForward  = new Vector3(1, 0, 0),
                InverseLeft     = new Vector3(0, 1, 0),
                InverseUp       = new Vector3(0, 0, 1),
            });

            // Begin building the default region and permutation
            builder.BeginRegion(_stringIds.GetStringId("default"));
            builder.BeginPermutation(_stringIds.GetStringId("default"));

            using (var importer = new AssimpContext())
            {
                Scene model;
                using (var logStream = new LogStream((msg, userData) => Console.WriteLine(msg)))
                {
                    logStream.Attach();
                    model = importer.ImportFile(args[0],
                                                PostProcessSteps.CalculateTangentSpace |
                                                PostProcessSteps.GenerateNormals |
                                                PostProcessSteps.JoinIdenticalVertices |
                                                PostProcessSteps.SortByPrimitiveType |
                                                PostProcessSteps.PreTransformVertices |
                                                PostProcessSteps.Triangulate);
                    logStream.Detach();
                }

                Console.WriteLine("Assembling vertices...");

                // Build a multipart mesh from the model data,
                // with each model mesh mapping to a part of one large mesh and having its own material
                builder.BeginMesh();
                ushort partStartVertex = 0;
                ushort partStartIndex  = 0;
                var    vertices        = new List <RigidVertex>();
                var    indices         = new List <ushort>();
                foreach (var mesh in model.Meshes)
                {
                    for (var i = 0; i < mesh.VertexCount; i++)
                    {
                        var position  = mesh.Vertices[i];
                        var normal    = mesh.Normals[i];
                        var uv        = mesh.TextureCoordinateChannels[0][i];
                        var tangent   = mesh.Tangents[i];
                        var bitangent = mesh.BiTangents[i];
                        vertices.Add(new RigidVertex
                        {
                            Position = new Vector4(position.X, position.Y, position.Z, 1),
                            Normal   = new Vector3(normal.X, normal.Y, normal.Z),
                            Texcoord = new Vector2(uv.X, uv.Y),
                            Tangent  = new Vector4(tangent.X, tangent.Y, tangent.Z, 1),
                            Binormal = new Vector3(bitangent.X, bitangent.Y, bitangent.Z),
                        });
                    }

                    // Build the index buffer
                    var meshIndices = mesh.GetIndices();
                    indices.AddRange(meshIndices.Select(i => (ushort)(i + partStartVertex)));

                    // Define a material and part for this mesh
                    var material = builder.AddMaterial(new RenderMaterial
                    {
                        RenderMethod = _cache.Tags[0x101F],
                    });
                    builder.DefinePart(material, partStartIndex, (ushort)meshIndices.Length, (ushort)mesh.VertexCount);

                    // Move to the next part
                    partStartVertex += (ushort)mesh.VertexCount;
                    partStartIndex  += (ushort)meshIndices.Length;
                }

                // Bind the vertex and index buffers
                builder.BindRigidVertexBuffer(vertices, node);
                builder.BindIndexBuffer(indices, PrimitiveType.TriangleList);
                builder.EndMesh();
            }

            builder.EndPermutation();
            builder.EndRegion();

            Console.WriteLine("Building Blam mesh data...");

            var resourceStream = new MemoryStream();
            var renderModel    = builder.Build(_info.Serializer, resourceStream);

            Console.WriteLine("Writing resource data...");

            // Add a new resource for the model data
            var resources = new ResourceDataManager();

            resources.LoadCachesFromDirectory(_fileInfo.DirectoryName);
            resourceStream.Position = 0;
            resources.Add(renderModel.Geometry.Resource, ResourceLocation.Resources, resourceStream);

            Console.WriteLine("Writing tag data...");

            using (var cacheStream = _fileInfo.Open(FileMode.Open, FileAccess.ReadWrite))
            {
                var tag     = destination;
                var context = new TagSerializationContext(cacheStream, _cache, _stringIds, tag);
                _info.Serializer.Serialize(context, renderModel);
            }
            Console.WriteLine("Model imported successfully!");
            return(true);
        }
示例#3
0
        public override bool Execute(List<string> args)
        {
            if (args.Count < 1 || args.Count > 3)
                return false;

            ResourceLocation location = ResourceLocation.Resources;
            TagInstance destination = Info.Cache.Tags[0x3317];

            if (args.Count == 3)
            {
                var value = args[0];

                switch (value)
                {
                    case "resources":
                        location = ResourceLocation.Resources;
                        break;

                    case "textures":
                        location = ResourceLocation.Textures;
                        break;

                    case "textures_b":
                        location = ResourceLocation.TexturesB;
                        break;

                    case "audio":
                        location = ResourceLocation.Audio;
                        break;

                    case "video":
                        location = ResourceLocation.Video;
                        break;

                    case "render_models":
                        location = ResourceLocation.RenderModels;
                        break;

                    case "lightmaps":
                        location = ResourceLocation.Lightmaps;
                        break;

                    default:
                        Console.WriteLine("Invalid resource location: " + value);
                        return false;
                }

                args.RemoveAt(0);
            }

            if (args.Count == 2)
            {
                destination = ArgumentParser.ParseTagIndex(Info, args[0]);

                if (!destination.IsInGroup("mode"))
                {
                    Console.WriteLine("Specified tag is not a render_model: " + args[0]);
                    return false;
                }

                args.RemoveAt(0);
            }

            var builder = new RenderModelBuilder(Info.Version);

            // Add a root node
            var node = builder.AddNode(new RenderModel.Node
            {
                Name = Info.StringIDs.GetStringID("street_cone"),
                ParentNode = -1,
                FirstChildNode = -1,
                NextSiblingNode = -1,
                DefaultRotation = new Vector4(0, 0, 0, -1),
                DefaultScale = 1,
                InverseForward = new Vector3(1, 0, 0),
                InverseLeft = new Vector3(0, 1, 0),
                InverseUp = new Vector3(0, 0, 1),
            });

            // Begin building the default region and permutation
            builder.BeginRegion(Info.StringIDs.GetStringID("default"));
            builder.BeginPermutation(Info.StringIDs.GetStringID("default"));

            using (var importer = new AssimpContext())
            {
                Scene model;
                using (var logStream = new LogStream((msg, userData) => Console.WriteLine(msg)))
                {
                    logStream.Attach();
                    model = importer.ImportFile(args[0],
                        PostProcessSteps.CalculateTangentSpace |
                        PostProcessSteps.GenerateNormals |
                        PostProcessSteps.JoinIdenticalVertices |
                        PostProcessSteps.SortByPrimitiveType |
                        PostProcessSteps.PreTransformVertices |
                        PostProcessSteps.Triangulate);
                    logStream.Detach();
                }

                Console.WriteLine("Assembling vertices...");

                // Build a multipart mesh from the model data,
                // with each model mesh mapping to a part of one large mesh and having its own material
                builder.BeginMesh();
                ushort partStartVertex = 0;
                ushort partStartIndex = 0;
                var vertices = new List<RigidVertex>();
                var indices = new List<ushort>();
                foreach (var mesh in model.Meshes)
                {
                    for (var i = 0; i < mesh.VertexCount; i++)
                    {
                        var position = mesh.Vertices[i];
                        var normal = mesh.Normals[i];
                        var uv = mesh.TextureCoordinateChannels[0][i];
                        var tangent = mesh.Tangents[i];
                        var bitangent = mesh.BiTangents[i];
                        vertices.Add(new RigidVertex
                        {
                            Position = new Vector4(position.X, position.Y, position.Z, 1),
                            Normal = new Vector3(normal.X, normal.Y, normal.Z),
                            Texcoord = new Vector2(uv.X, uv.Y),
                            Tangent = new Vector4(tangent.X, tangent.Y, tangent.Z, 1),
                            Binormal = new Vector3(bitangent.X, bitangent.Y, bitangent.Z),
                        });
                    }

                    // Build the index buffer
                    var meshIndices = mesh.GetIndices();
                    indices.AddRange(meshIndices.Select(i => (ushort)(i + partStartVertex)));

                    // Define a material and part for this mesh
                    var material = builder.AddMaterial(new RenderMaterial
                    {
                        RenderMethod = Info.Cache.Tags[0x101F],
                    });

                    builder.BeginPart(material, partStartIndex, (ushort)meshIndices.Length, (ushort)mesh.VertexCount);
                    builder.DefineSubPart(partStartIndex, (ushort)meshIndices.Length, (ushort)mesh.VertexCount);
                    builder.EndPart();

                    // Move to the next part
                    partStartVertex += (ushort)mesh.VertexCount;
                    partStartIndex += (ushort)meshIndices.Length;
                }

                // Bind the vertex and index buffers
                builder.BindRigidVertexBuffer(vertices, node);
                builder.BindIndexBuffer(indices, PrimitiveType.TriangleList);
                builder.EndMesh();
            }

            builder.EndPermutation();
            builder.EndRegion();

            Console.WriteLine("Building Blam mesh data...");

            var resourceStream = new MemoryStream();
            var renderModel = builder.Build(Info.Serializer, resourceStream);

            Console.WriteLine("Writing resource data...");

            // Add a new resource for the model data
            var resources = new ResourceDataManager();
            resources.LoadCachesFromDirectory(Info.CacheFile.DirectoryName);
            resourceStream.Position = 0;
            resources.Add(renderModel.Geometry.Resource, location, resourceStream);

            Console.WriteLine("Writing tag data...");

            using (var cacheStream = Info.OpenCacheReadWrite())
            {
                var tag = destination;
                var context = new TagSerializationContext(cacheStream, Info.Cache, Info.StringIDs, tag);
                Info.Serializer.Serialize(context, renderModel);
            }

            Console.WriteLine("Model imported successfully!");

            return true;
        }
        public override object Execute(List <string> args)
        {
            if (args.Count != 1)
            {
                return(false);
            }

            if (!CacheContext.TryGetTag <Shader>(@"shaders\invalid", out var defaultShaderTag))
            {
                Console.WriteLine("WARNING: 'shaders\\invalid.shader' not found!");
                Console.WriteLine("You will have to assign material shaders manually.");
            }

            var stringIdCount = CacheContext.StringIdCache.Strings.Count;

            var sceneFile = new FileInfo(args[0]);

            if (!sceneFile.Exists)
            {
                throw new FileNotFoundException(sceneFile.FullName);
            }

            if (sceneFile.Extension.ToLower() != ".dae")
            {
                throw new FormatException($"Input file is not COLLADA format: {sceneFile.FullName}");
            }

            Scene scene;

            using (var importer = new AssimpContext())
            {
                scene = importer.ImportFile(sceneFile.FullName,
                                            PostProcessSteps.CalculateTangentSpace |
                                            PostProcessSteps.GenerateNormals |
                                            PostProcessSteps.SortByPrimitiveType |
                                            PostProcessSteps.Triangulate);
            }

            var builder         = new RenderModelBuilder(CacheContext);
            var nodes           = new Dictionary <string, sbyte>();
            var materialIndices = new Dictionary <string, short>();

            foreach (var oldNode in Definition.Nodes)
            {
                var name = CacheContext.GetString(oldNode.Name);

                nodes[name] = builder.AddNode(oldNode);
            }

            foreach (var region in Definition.Regions)
            {
                builder.BeginRegion(region.Name);

                var regionName = CacheContext.GetString(region.Name);

                foreach (var permutation in region.Permutations)
                {
                    if (permutation.MeshCount > 1)
                    {
                        throw new NotSupportedException("multiple permutation meshes");
                    }

                    if (permutation.MeshIndex == -1)
                    {
                        continue;
                    }

                    var permName = CacheContext.GetString(permutation.Name);
                    var meshName = $"{regionName}FBXASC058{permName}Mesh";

                    var permMeshes = scene.Meshes.Where(i => i.Name == meshName).ToList();

                    if (permMeshes.Count == 0)
                    {
                        throw new Exception($"No mesh(es) found for region '{regionName}' permutation '{permName}'!");
                    }

                    permMeshes.Sort((a, b) => a.MaterialIndex.CompareTo(b.MaterialIndex));

                    // Build a multipart mesh from the model data,
                    // with each model mesh mapping to a part of one large mesh and having its own material
                    ushort partStartVertex = 0;
                    ushort partStartIndex  = 0;

                    var rigidVertices   = new List <RigidVertex>();
                    var skinnedVertices = new List <SkinnedVertex>();

                    var indices = new List <ushort>();

                    var vertexType = Definition.Geometry.Meshes[permutation.MeshIndex].Type;
                    var rigidNode  = Definition.Geometry.Meshes[permutation.MeshIndex].RigidNodeIndex;

                    builder.BeginPermutation(permutation.Name);
                    builder.BeginMesh();

                    foreach (var mesh in permMeshes)
                    {
                        for (var i = 0; i < mesh.VertexCount; i++)
                        {
                            var position = mesh.Vertices[i];
                            var normal   = mesh.Normals[i];

                            Vector3D uv;

                            try
                            {
                                uv = mesh.TextureCoordinateChannels[0][i];
                            }
                            catch
                            {
                                Console.WriteLine($"WARNING: Missing texture coordinate for vertex {i} in '{regionName}:{permName}'");
                                uv = new Vector3D();
                            }

                            var tangent   = mesh.Tangents.Count != 0 ? mesh.Tangents[i] : new Vector3D();
                            var bitangent = mesh.BiTangents.Count != 0 ? mesh.BiTangents[i] : new Vector3D();

                            if (vertexType == VertexType.Skinned)
                            {
                                var blendIndicesList = new List <byte>();
                                var blendWeightsList = new List <float>();

                                foreach (var bone in mesh.Bones)
                                {
                                    foreach (var vertexInfo in bone.VertexWeights)
                                    {
                                        if (vertexInfo.VertexID == i)
                                        {
                                            // HAX BELOW
                                            //if (bone.Name.StartsWith("_"))
                                            //bone.Name = bone.Name.Substring(4);
                                            //if (bone.Name.EndsWith("2"))
                                            //bone.Name = bone.Name.Replace("2", "_tip");
                                            //else if (bone.Name != "spine1" && bone.Name.EndsWith("1"))
                                            //bone.Name = bone.Name.Replace("1", "_low");
                                            blendIndicesList.Add((byte)nodes[bone.Name]);
                                            blendWeightsList.Add(vertexInfo.Weight);
                                        }
                                    }
                                }

                                var blendIndices = new byte[4];
                                var blendWeights = new float[4];

                                for (int j = 0; j < blendIndicesList.Count; j++)
                                {
                                    if (j < 4)
                                    {
                                        blendIndices[j] = blendIndicesList[j];
                                    }
                                }

                                for (int j = 0; j < blendWeightsList.Count; j++)
                                {
                                    if (j < 4)
                                    {
                                        blendWeights[j] = blendWeightsList[j];
                                    }
                                }

                                skinnedVertices.Add(new SkinnedVertex
                                {
                                    Position     = new RealQuaternion(position.X * 0.01f, position.Y * 0.01f, position.Z * 0.01f, 1),
                                    Texcoord     = new RealVector2d(uv.X, -uv.Y),
                                    Normal       = new RealVector3d(normal.X, normal.Y, normal.Z),
                                    Tangent      = new RealQuaternion(tangent.X, tangent.Y, tangent.Z, 1),
                                    Binormal     = new RealVector3d(bitangent.X, bitangent.Y, bitangent.Z),
                                    BlendIndices = blendIndices,
                                    BlendWeights = blendWeights
                                });
                            }
                            else
                            {
                                rigidVertices.Add(new RigidVertex
                                {
                                    Position = new RealQuaternion(position.X * 0.01f, position.Y * 0.01f, position.Z * 0.01f, 1),
                                    Texcoord = new RealVector2d(uv.X, -uv.Y),
                                    Normal   = new RealVector3d(normal.X, normal.Y, normal.Z),
                                    Tangent  = new RealQuaternion(tangent.X, tangent.Y, tangent.Z, 1),
                                    Binormal = new RealVector3d(bitangent.X, bitangent.Y, bitangent.Z),
                                });
                            }
                        }

                        // Build the index buffer
                        var meshIndices = mesh.GetIndices();
                        indices.AddRange(meshIndices.Select(i => (ushort)(i + partStartVertex)));

                        // Define a material and part for this mesh
                        var meshMaterial = scene.Materials[mesh.MaterialIndex];

                        short materialIndex = 0;

                        if (materialIndices.ContainsKey(meshMaterial.Name))
                        {
                            materialIndex = materialIndices[meshMaterial.Name];
                        }
                        else
                        {
                            materialIndex = materialIndices[meshMaterial.Name] = builder.AddMaterial(new RenderMaterial
                            {
                                RenderMethod = defaultShaderTag,
                            });
                        }

                        builder.BeginPart(materialIndex, partStartIndex, (ushort)meshIndices.Length, (ushort)mesh.VertexCount);
                        builder.DefineSubPart(partStartIndex, (ushort)meshIndices.Length, (ushort)mesh.VertexCount);
                        builder.EndPart();

                        // Move to the next part
                        partStartVertex += (ushort)mesh.VertexCount;
                        partStartIndex  += (ushort)meshIndices.Length;
                    }

                    // Bind the vertex and index buffers
                    if (vertexType == VertexType.Skinned)
                    {
                        builder.BindSkinnedVertexBuffer(skinnedVertices);
                    }
                    else
                    {
                        builder.BindRigidVertexBuffer(rigidVertices, rigidNode);
                    }

                    builder.BindIndexBuffer(indices, IndexBufferFormat.TriangleList);

                    builder.EndMesh();
                    builder.EndPermutation();
                }

                builder.EndRegion();
            }

            using (var resourceStream = new MemoryStream())
            {
                Console.Write("Building render_geometry...");

                var newDefinition = builder.Build(CacheContext.Serializer, resourceStream);
                Definition.Regions   = newDefinition.Regions;
                Definition.Geometry  = newDefinition.Geometry;
                Definition.Nodes     = newDefinition.Nodes;
                Definition.Materials = newDefinition.Materials;

                resourceStream.Position = 0;

                Definition.Geometry.Resource.ChangeLocation(ResourceLocation.ResourcesB);
                CacheContext.AddResource(Definition.Geometry.Resource, resourceStream);

                Console.WriteLine("done.");
            }

            //
            // TODO: Build the new render_model and update the original render_model here...
            //

            Console.Write("Writing render_model tag data...");

            using (var cacheStream = CacheContext.OpenTagCacheReadWrite())
                CacheContext.Serialize(cacheStream, Tag, Definition);

            Console.WriteLine("done.");

            if (stringIdCount != CacheContext.StringIdCache.Strings.Count)
            {
                Console.Write("Saving string ids...");

                using (var stream = CacheContext.OpenStringIdCacheReadWrite())
                    CacheContext.StringIdCache.Save(stream);

                Console.WriteLine("done");
            }

            Console.WriteLine("Replaced render_geometry successfully.");

            return(true);
        }
示例#5
0
        public override object Execute(List <string> args)
        {
            if (args.Count < 1 || args.Count > 2)
            {
                return(false);
            }

            var stringIdCount  = Cache.StringTable.Count;
            var destinationTag = Cache.TagCache.GetTag(@"objects\gear\human\industrial\street_cone\street_cone", "mode");

            string vertexType = "rigid";

            if (args[0] == "skinned" || args[0] == "rigid")
            {
                vertexType = args[0];
                args.RemoveAt(0);
            }

            if (args.Count == 2)
            {
                if (!Cache.TryGetTag(args[0], out destinationTag) || !destinationTag.IsInGroup("mode"))
                {
                    Console.WriteLine("Specified tag is not a render_model: " + args[0]);
                    return(false);
                }

                args.RemoveAt(0);
            }

            RenderModel edMode = null;

            using (var cacheStream = Cache.OpenCacheReadWrite())
                edMode = Cache.Deserialize <RenderModel>(cacheStream, destinationTag);

            // Get a list of the original nodes
            var nodeIndices = new Dictionary <string, int>();

            foreach (var a in edMode.Nodes)
            {
                nodeIndices.Add(Cache.StringTable.GetString(a.Name), edMode.Nodes.IndexOf(a));
            }

            // Read the custom model file
            if (!File.Exists(args[0]))
            {
                return(false);
            }

            Console.WriteLine($"File date: {File.GetLastWriteTime(args[0])}");

            var builder = new RenderModelBuilder(Cache);

            using (var importer = new AssimpContext())
            {
                Scene model;

                if (vertexType == "skinned")
                {
                    using (var logStream = new LogStream((msg, userData) => Console.WriteLine(msg)))
                    {
                        logStream.Attach();
                        model = importer.ImportFile(args[0],
                                                    PostProcessSteps.CalculateTangentSpace |
                                                    PostProcessSteps.GenerateNormals |
                                                    PostProcessSteps.SortByPrimitiveType |
                                                    PostProcessSteps.Triangulate);
                        logStream.Detach();
                    }

                    for (var i = 0; i < model.Meshes.Count; i++)
                    {
                        if (!model.Meshes[i].HasBones)
                        {
                            throw new Exception($"Mesh \"{model.Meshes[i].Name}\" has no bones!");
                        }
                    }
                }
                else
                {
                    using (var logStream = new LogStream((msg, userData) => Console.WriteLine(msg)))
                    {
                        logStream.Attach();
                        model = importer.ImportFile(args[0],
                                                    PostProcessSteps.CalculateTangentSpace |
                                                    PostProcessSteps.GenerateNormals |
                                                    PostProcessSteps.JoinIdenticalVertices |
                                                    PostProcessSteps.SortByPrimitiveType |
                                                    PostProcessSteps.PreTransformVertices |
                                                    PostProcessSteps.Triangulate);
                        logStream.Detach();
                    }
                }

                Console.WriteLine("Assembling vertices...");

                // Add nodes
                var rigidNode = builder.AddNode(new RenderModel.Node
                {
                    Name            = Cache.StringTable.GetStringId("street_cone"),
                    ParentNode      = -1,
                    FirstChildNode  = -1,
                    NextSiblingNode = -1,
                    DefaultRotation = new RealQuaternion(0, 0, 0, -1),
                    DefaultScale    = 1,
                    InverseForward  = new RealVector3d(1, 0, 0),
                    InverseLeft     = new RealVector3d(0, 1, 0),
                    InverseUp       = new RealVector3d(0, 0, 1),
                });

                // Build a multipart mesh from the model data,
                // with each model mesh mapping to a part of one large mesh and having its own material
                ushort partStartVertex = 0;
                ushort partStartIndex  = 0;

                var rigidVertices   = new List <RigidVertex>();
                var skinnedVertices = new List <SkinnedVertex>();

                var indices = new List <ushort>();

                Dictionary <string, int> newNodes = new Dictionary <string, int>();
                foreach (var mesh in model.Meshes)
                {
                    var meshIndex = model.Meshes.IndexOf(mesh);

                    Console.Write($"Enter a region name for '{mesh.Name}' (mesh index {meshIndex}): ");
                    var regionName     = Console.ReadLine();
                    var regionStringId = Cache.StringTable.GetStringId(regionName);

                    if (regionStringId == StringId.Invalid)
                    {
                        regionStringId = Cache.StringTable.AddString(regionName);
                    }

                    // Begin building the default region and permutation
                    builder.BeginRegion(regionStringId);
                    builder.BeginPermutation(Cache.StringTable.GetStringId("default"));
                    builder.BeginMesh();

                    for (var i = 0; i < mesh.VertexCount; i++)
                    {
                        var position = mesh.Vertices[i];
                        var normal   = mesh.Normals[i];
                        var uv       = mesh.TextureCoordinateChannels[0][i];

                        var tangent   = mesh.Tangents.Count != 0 ? mesh.Tangents[i] : new Vector3D();
                        var bitangent = mesh.BiTangents.Count != 0 ? mesh.BiTangents[i] : new Vector3D();

                        if (vertexType == "skinned")
                        {
                            var blendIndicesList = new List <byte>();
                            var blendWeightsList = new List <float>();
                            var bonesList        = new List <string>();

                            foreach (var bone in mesh.Bones)
                            {
                                foreach (var vertexInfo in bone.VertexWeights)
                                {
                                    if (vertexInfo.VertexID == i)
                                    {
                                        bonesList.Add(bone.Name);
                                        blendIndicesList.Add((byte)nodeIndices[bone.Name]);
                                        blendWeightsList.Add(vertexInfo.Weight);
                                    }
                                }
                            }

                            var blendIndices = new byte[4];
                            var blendWeights = new float[4];

                            for (int j = 0; j < blendIndicesList.Count; j++)
                            {
                                if (j < 4)
                                {
                                    blendIndices[j] = blendIndicesList[j];
                                }
                            }

                            for (int j = 0; j < blendWeightsList.Count; j++)
                            {
                                if (j < 4)
                                {
                                    blendWeights[j] = blendWeightsList[j];
                                }
                            }

                            skinnedVertices.Add(new SkinnedVertex
                            {
                                Position     = new RealQuaternion(position.X, position.Y, position.Z, 1),
                                Texcoord     = new RealVector2d(uv.X, -uv.Y),
                                Normal       = new RealVector3d(normal.X, normal.Y, normal.Z),
                                Tangent      = new RealQuaternion(tangent.X, tangent.Y, tangent.Z, 1),
                                Binormal     = new RealVector3d(bitangent.X, bitangent.Y, bitangent.Z),
                                BlendIndices = blendIndices,
                                BlendWeights = blendWeights
                            });
                        }
                        else
                        {
                            rigidVertices.Add(new RigidVertex
                            {
                                Position = new RealQuaternion(position.X, position.Y, position.Z, 1),
                                Texcoord = new RealVector2d(uv.X, -uv.Y),
                                Normal   = new RealVector3d(normal.X, normal.Y, normal.Z),
                                Tangent  = new RealQuaternion(tangent.X, tangent.Y, tangent.Z, 1),
                                Binormal = new RealVector3d(bitangent.X, bitangent.Y, bitangent.Z),
                            });
                        }
                    }

                    // Build the index buffer
                    var meshIndices = mesh.GetIndices();
                    indices.AddRange(meshIndices.Select(i => (ushort)(i + partStartVertex)));

                    // Define a material and part for this mesh
                    var material = builder.AddMaterial(new RenderMaterial
                    {
                        RenderMethod = Cache.TagCache.GetTag(@"shaders\invalid", "rmsh"),
                    });

                    builder.BeginPart(material, partStartIndex, (ushort)meshIndices.Length, (ushort)mesh.VertexCount);
                    builder.DefineSubPart(partStartIndex, (ushort)meshIndices.Length, (ushort)mesh.VertexCount);
                    builder.EndPart();

                    // Move to the next part
                    partStartVertex += (ushort)mesh.VertexCount;
                    partStartIndex  += (ushort)meshIndices.Length;

                    // Bind the vertex and index buffers
                    if (vertexType == "skinned")
                    {
                        builder.BindSkinnedVertexBuffer(skinnedVertices);
                    }
                    else
                    {
                        builder.BindRigidVertexBuffer(rigidVertices, rigidNode);
                    }

                    builder.BindIndexBuffer(indices, IndexBufferFormat.TriangleList);
                    builder.EndMesh();
                    builder.EndPermutation();
                    builder.EndRegion();
                }
            }

            Console.Write("Building render_geometry...");

            var resourceStream = new MemoryStream();
            var renderModel    = builder.Build(Cache.Serializer, resourceStream);

            if (vertexType == "skinned")
            {
                // Copy required data from the original render_model tag
                renderModel.Nodes                   = edMode.Nodes;
                renderModel.MarkerGroups            = edMode.MarkerGroups;
                renderModel.RuntimeNodeOrientations = edMode.RuntimeNodeOrientations;
            }

            Console.WriteLine("done.");


            //
            // Serialize the new render_model tag
            //

            Console.Write("Writing render_model tag data...");

            using (var cacheStream = Cache.OpenCacheReadWrite())
                Cache.Serialize(cacheStream, destinationTag, renderModel);

            Console.WriteLine("done.");

            //
            // Save any new string ids
            //

            if (stringIdCount != Cache.StringTable.Count)
            {
                Console.Write("Saving string ids...");


                Cache.SaveStrings();

                Console.WriteLine("done");
            }

            Console.WriteLine("Model imported successfully!");

            return(true);
        }