Пример #1
0
        internal void DrawInternal(RenderSettings settings, IEnumerable <IDecorator> decorators)
        {
            _device.SetRenderState(RenderState.ZEnable, true);
            _device.SetRenderState(RenderState.ZWriteEnable, true);

            // Draw opaque objects first.
            foreach (ModelMesh modelMesh in Meshes.Where(m => m.Opaque))
            {
                modelMesh.Draw(_vertexDeclaration, settings, decorators);
            }

            _device.SetRenderState(RenderState.ZWriteEnable, false);

            // Draw transparent objects. TODO: Sort by distance from camera and draw from back to front.
            _device.SetRenderState(RenderState.AlphaBlendEnable, true);
            _device.SetRenderState(RenderState.SourceBlend, Blend.SourceAlpha);
            _device.SetRenderState(RenderState.DestinationBlend, Blend.InverseSourceAlpha);
            foreach (ModelMesh modelMesh in Meshes.Where(m => !m.Opaque))
            {
                modelMesh.Draw(_vertexDeclaration, settings, decorators);
            }
            _device.SetRenderState(RenderState.AlphaBlendEnable, false);

            _device.SetRenderState(RenderState.ZWriteEnable, true);
        }
Пример #2
0
        private void _setParents()
        {
            // Bandaid, as we really want only 1 root mesh
            if (MainMeshNames.Count > 1)
            {
                foreach (var mesh in Meshes)
                {
                    mesh.ParentName = "__ROOT";
                }

                Mesh root = new Mesh {
                    Name = "__ROOT"
                };
                MainMesh = root;
                Meshes.Add(root);
            }

            // Fix : 2015-04-23
            // Sets the parents in each mesh by using their references.
            foreach (var mesh in Meshes)
            {
                // No parent, they are ignored
                if (String.IsNullOrEmpty(mesh.ParentName) || mesh == MainMesh)
                {
                    continue;
                }

                List <Mesh> parents = Meshes.Where(p => p.Name == mesh.ParentName && mesh != p).ToList();

                if (parents.Count == 0)
                {
                    continue;
                }
                mesh.Parent = parents[0];
                parents[0].Children.Add(mesh);
            }
        }
Пример #3
0
 public Mesh[] GetMeshesByType(Mesh.MeshType mp)
 {
     return(Meshes.Where(m => m.Types.Contains(mp)).ToArray());
 }
Пример #4
0
        public void Save(Stream destination, ObjectDatabase objectDatabase, TextureDatabase textureDatabase,
                         BoneDatabase boneDatabase, bool leaveOpen = false)
        {
            if (objectDatabase != null)
            {
                foreach (var mesh in Meshes)
                {
                    mesh.Id = objectDatabase.GetMesh(mesh.Name)?.Id ?? mesh.Id;
                }
            }

            if (boneDatabase != null)
            {
                string fileName = destination is FileStream fileStream
                    ? Path.GetFileName(fileStream.Name)
                    : string.Empty;

                var skeletonEntry =
                    boneDatabase.Skeletons.FirstOrDefault(x =>
                                                          fileName.StartsWith(x.Name, StringComparison.OrdinalIgnoreCase)) ??
                    boneDatabase.Skeletons.FirstOrDefault(x =>
                                                          x.Name.Equals("CMN", StringComparison.OrdinalIgnoreCase)) ??
                    boneDatabase.Skeletons[0];

                if (skeletonEntry != null)
                {
                    foreach (var skin in Meshes.Where(x => x.Skin != null).Select(x => x.Skin))
                    {
                        foreach (var bone in skin.Bones)
                        {
                            int index = skin.ExData?.BoneNames?.FindIndex(x =>
                                                                          x.Equals(bone.Name, StringComparison.OrdinalIgnoreCase)) ?? -1;

                            if (index == -1)
                            {
                                index = skeletonEntry.BoneNames1.FindIndex(x =>
                                                                           x.Equals(bone.Name, StringComparison.OrdinalIgnoreCase));
                            }
                            else
                            {
                                index = 0x8000 | index;
                            }

                            if (index == -1)
                            {
                                continue;
                            }

                            foreach (var childBone in skin.Bones.Where(x => x.ParentId == bone.Id))
                            {
                                childBone.ParentId = index;
                            }

                            bone.Id = index;
                        }
                    }
                }
            }

            if (textureDatabase != null && TextureSet != null)
            {
                int id           = textureDatabase.Textures.Max(x => x.Id) + 1;
                var idDictionary = new Dictionary <int, int>(TextureSet.Textures.Count);

                foreach (var texture in TextureSet.Textures)
                {
                    var textureEntry = !string.IsNullOrEmpty(texture.Name)
                        ? textureDatabase.GetTexture(texture.Name)
                        : textureDatabase.GetTexture(texture.Id);

                    if (textureEntry == null)
                    {
                        textureDatabase.Textures.Add(
                            textureEntry = new TextureEntry
                        {
                            Name = texture.Name,
                            Id   = id++
                        });

                        if (string.IsNullOrEmpty(textureEntry.Name))
                        {
                            textureEntry.Name = $"Unnamed {textureEntry.Id}";
                        }
                    }
                    idDictionary[texture.Id] = textureEntry.Id;

                    texture.Name = textureEntry.Name;
                    texture.Id   = textureEntry.Id;
                }

                foreach (var materialTexture in Meshes.SelectMany(x => x.Materials)
                         .SelectMany(x => x.MaterialTextures))
                {
                    if (idDictionary.TryGetValue(materialTexture.TextureId, out id))
                    {
                        materialTexture.TextureId = id;
                    }
                }

                TextureIds.Clear();
                TextureIds.AddRange(TextureSet.Textures.Select(x => x.Id));
            }

            Save(destination, leaveOpen);
        }
Пример #5
0
        internal void Save(EndianBinaryWriter output, GcGame game)
        {
            int headerSize = SizeOfHeader();

            // In the GCMF file, the triangle meshes are classified in two layers:
            // The "opaque" layer and the "translucid" layer.
            // We store both kinds of layers in the same vector for easier manipulation
            // (setting the layer property on the triangle mesh itself), which the user
            // may order freely, but now that we're writting the GCMF again, we need to
            // reclassify the meshes in both layers.
            GcmfMesh[] layer1Meshes        = Meshes.Where(mesh => mesh.Layer == GcmfMesh.MeshLayer.Layer1).ToArray();
            GcmfMesh[] layer2Meshes        = Meshes.Where(mesh => mesh.Layer == GcmfMesh.MeshLayer.Layer2).ToArray();
            GcmfMesh[] meshesSortedByLayer = layer1Meshes.Union(layer2Meshes).ToArray();

            // Write GCMF header
            output.Write(GcmfMagic);
            output.Write(SectionFlags);
            output.Write(BoundingSphereCenter.X);
            output.Write(BoundingSphereCenter.Y);
            output.Write(BoundingSphereCenter.Z);
            output.Write(BoundingSphereRadius);
            output.Write(Convert.ToUInt16(Materials.Count));
            output.Write(Convert.ToUInt16(layer1Meshes.Length));
            output.Write(Convert.ToUInt16(layer2Meshes.Length));
            output.Write(Convert.ToByte(TransformMatrices.Count));
            output.Write((byte)0);
            output.Write(headerSize);
            output.Write((uint)0);
            output.Write(TransformMatrixDefaultIdxs);
            output.Write((uint)0);
            output.Write((uint)0);
            output.Write((uint)0);
            output.Write((uint)0);

            for (int i = 0; i < Materials.Count; i++)
            {
                Materials[i].Save(output, i);
            }

            foreach (GcmfTransformMatrix tmtx in TransformMatrices)
            {
                tmtx.Save(output);
            }

            output.Align(0x20);

            if ((SectionFlags & (uint)GcmfSectionFlags.SkinModel) != 0 || (SectionFlags & (uint)GcmfSectionFlags.EffectiveModel) != 0)
            {
                int offsetPartVertexPool    = SizeOf2Header() + SizeOf2MeshHeaders();
                int offsetPartType8Unknown1 = offsetPartVertexPool + SizeOf2VertexPool(game);
                int offsetPartType8Unknown2 = offsetPartType8Unknown1 + (((SectionFlags & (uint)GcmfSectionFlags.SkinModel) != 0) ? SizeOf2Type8Unknown1() : 0);
                int offsetPartMeshData      = offsetPartType8Unknown2 + (((SectionFlags & (uint)GcmfSectionFlags.SkinModel) != 0) ? SizeOf2Type8Unknown2() : 0);
                if (!GcmfVersionDetails.IsGcmfSkinModelSupported(game))
                {
                    // Those are zero on SMB1
                    offsetPartType8Unknown1 = 0;
                    offsetPartType8Unknown2 = 0;
                }

                output.Write(VertexPool.Count);
                output.Write(offsetPartType8Unknown1);
                output.Write(offsetPartVertexPool);
                output.Write(offsetPartMeshData);
                output.Write(offsetPartType8Unknown2);
                output.Write((uint)0);
                output.Write((uint)0);
                output.Write((uint)0);

                // Write the mesh headers
                foreach (GcmfMesh mesh in meshesSortedByLayer)
                {
                    mesh.SaveHeader(output, true, false);
                }

                // Write the vertex pool
                bool isVtx16Bit = (SectionFlags & (uint)GcmfSectionFlags._16Bit) != 0 &&
                                  !GcmfVersionDetails.Is16BitEffectiveModelIgnored(game);

                foreach (GcmfVertex vtx in VertexPool)
                {
                    vtx.SaveIndexed(output, isVtx16Bit);
                }

                if ((SectionFlags & (uint)GcmfSectionFlags.SkinModel) != 0)
                {
                    foreach (GcmfType8Unknown1 unk1 in Type8Unknown1)
                    {
                        unk1.Save(output);
                    }

                    foreach (ushort unk2 in Type8Unknown2)
                    {
                        output.Write(unk2);
                    }

                    output.Align(0x20);
                }

                // Write the section data itself (the indexed triangle strips)
                Dictionary <GcmfVertex, int> vertexPoolIndexes = new Dictionary <GcmfVertex, int>();
                for (int i = 0; i < VertexPool.Count; i++)
                {
                    vertexPoolIndexes.Add(VertexPool[i], i);
                }

                foreach (GcmfMesh mesh in meshesSortedByLayer)
                {
                    mesh.SaveIndexedData(output, isVtx16Bit, vertexPoolIndexes);
                }

                output.Align(0x20);
            }
            else
            {
                bool is16Bit = ((SectionFlags & (uint)GcmfSectionFlags._16Bit) != 0);
                foreach (GcmfMesh mesh in meshesSortedByLayer)
                {
                    mesh.SaveHeader(output, false, is16Bit);
                    mesh.SaveNonIndexedData(output, is16Bit);
                }
            }
        }
Пример #6
0
        public void Save(Stream destination, ObjectDatabase objectDatabase, TextureDatabase textureDatabase, BoneDatabase boneDatabase, bool leaveOpen = false)
        {
            if (objectDatabase != null)
            {
                foreach (var mesh in Meshes)
                {
                    mesh.ID = objectDatabase.GetMesh(mesh.Name)?.ID ?? mesh.ID;
                }
            }

            if (boneDatabase != null)
            {
                string fileName = (destination is FileStream fileStream) ? Path.GetFileName(fileStream.Name) : string.Empty;

                // Assume we are exporting in game's style
                var skeleton = boneDatabase.Skeletons.FirstOrDefault(x => fileName.StartsWith(x.Name, StringComparison.OrdinalIgnoreCase));

                // If we couldn't find it, default to CMN skeleton
                if (skeleton == null)
                {
                    skeleton = boneDatabase.Skeletons.FirstOrDefault(x => x.Name.Equals("CMN", StringComparison.OrdinalIgnoreCase));
                }

                // Still?? Then default to the first skeleton (this is unlikely to happen though)
                if (skeleton == null)
                {
                    skeleton = boneDatabase.Skeletons[0];
                }

                // Pretty much impossible to miss
                if (skeleton != null)
                {
                    foreach (var skin in Meshes.Where(x => x.Skin != null).Select(x => x.Skin))
                    {
                        foreach (var bone in skin.Bones)
                        {
                            int index = skin.ExData?.BoneNames?.FindIndex(x => x.Equals(bone.Name, StringComparison.OrdinalIgnoreCase)) ?? -1;
                            if (index == -1)
                            {
                                index = skeleton.BoneNames1.FindIndex(x => x.Equals(bone.Name, StringComparison.OrdinalIgnoreCase));
                            }
                            else
                            {
                                index = 0x8000 | index;
                            }

                            if (index != -1)
                            {
                                // Before we do this, fix the child bones
                                foreach (var childBone in skin.Bones.Where(x => x.ParentID.Equals(bone.ID)))
                                {
                                    childBone.ParentID = index;
                                }

                                // Now replace the ID
                                bone.ID = index;
                            }
                            else
                            {
                                Debug.WriteLine($"Model.Save: Bone wasn't found in bone database or ex-data: {bone.Name}");
                            }
                        }
                    }
                }
            }

            if (textureDatabase != null && TextureSet != null)
            {
                var newIDs    = new List <int>(TextureSet.Textures.Count);
                int currentID = textureDatabase.Textures.Max(x => x.ID) + 1;
                foreach (var texture in TextureSet.Textures)
                {
                    var textureEntry = !string.IsNullOrEmpty(texture.Name) ?
                                       textureDatabase.GetTexture(texture.Name) : textureDatabase.GetTexture(texture.ID);

                    if (textureEntry == null)
                    {
                        textureDatabase.Textures.Add(textureEntry = new TextureEntry
                        {
                            ID   = currentID++,
                            Name = texture.Name ?? $"Texture{currentID}",
                        });
                    }

                    newIDs.Add(textureEntry.ID);
                }

                if (!newIDs.SequenceEqual(TextureIDs))
                {
                    TextureUtilities.ReAssignTextureIDs(this, newIDs);
                }
            }

            Save(destination, leaveOpen);
        }