Пример #1
0
        private bool PromptFileSave(IGeometryModel model, out string fileName, out string formatId)
        {
            var getExportFormats = Substrate.GetSharedFunction <GetExportFormats>("Reclaimer.Plugins.ModelViewerPlugin.GetExportFormats");

            var exportFormats = getExportFormats()
                                .Select(f => new
            {
                FormatId    = f,
                Extension   = ModelViewerPlugin.GetFormatExtension(f),
                Description = ModelViewerPlugin.GetFormatDescription(f)
            }).ToList();

            var filter = string.Join("|", exportFormats.Select(f => $"{f.Description}|*.{f.Extension}"));

            var sfd = new SaveFileDialog
            {
                OverwritePrompt = true,
                FileName        = model.Name,
                Filter          = filter,
                FilterIndex     = 1 + exportFormats.TakeWhile(f => f.FormatId != ArchitectSettingsPlugin.Settings.DefaultSaveFormat).Count(),
                AddExtension    = true
            };

            if (sfd.ShowDialog() != true)
            {
                fileName = formatId = null;
                return(false);
            }

            fileName = sfd.FileName;
            formatId = exportFormats[sfd.FilterIndex - 1].FormatId;
            ArchitectSettingsPlugin.Settings.DefaultSaveFormat = formatId;
            return(true);
        }
Пример #2
0
        public MaskedGeometryModel(IGeometryModel source, IList <IGeometryPermutation> permutations)
        {
            this.source = source;

            var regions = new List <GeometryRegion>();

            foreach (var reg in source.Regions)
            {
                var perms = reg.Permutations
                            .Where(p => permutations.Contains(p))
                            .ToList();

                if (!perms.Any())
                {
                    continue;
                }

                regions.Add(new GeometryRegion
                {
                    Name         = reg.Name,
                    Permutations = perms
                });
            }

            MarkerGroups = new List <IGeometryMarkerGroup>();
            Regions      = regions.OfType <IGeometryRegion>().ToList();
        }
        public ModelProperties(IGeometryModel source)
        {
            Name         = source.Name;
            Regions      = source.Regions.ToList();
            MarkerGroups = source.MarkerGroups.ToList();
            Nodes        = source.Nodes.ToList();
            Materials    = source.Materials.ToList();

            var standard  = new List <int>();
            var instances = new List <int>();

            for (int i = 0; i < source.Meshes.Count; i++)
            {
                if (source.Meshes[i].IsInstancing)
                {
                    instances.Add(i);
                }
                else
                {
                    standard.Add(i);
                }
            }

            MeshCount      = source.Meshes.Count;
            StandardMeshes = standard;
            InstanceMeshes = instances;
        }
Пример #4
0
        public MaskedGeometryModel(IGeometryModel source, IEnumerable <IGeometryPermutation> filter)
        {
            this.source = source;
            filter      = (filter as IList <IGeometryPermutation>) ?? filter.ToList();

            regions = source.Regions.Select((r, i) => new MaskedRegion(i, r)).ToList();
            foreach (var region in regions)
            {
                region.Permutations.RemoveAll(p => !filter.Contains(p.SourcePermutation));
            }
            regions.RemoveAll(r => r.Permutations.Count == 0);

            markerGroups = new List <GeometryMarkerGroup>();
            foreach (var group in source.MarkerGroups)
            {
                var markers = group.Markers
                              .Select(m => new MaskedMarker(m, regions))
                              .Where(m => m.IsValid)
                              .OfType <IGeometryMarker>()
                              .ToList();

                if (markers.Count == 0)
                {
                    continue;
                }

                markerGroups.Add(new GeometryMarkerGroup
                {
                    Name    = group.Name,
                    Markers = markers
                });
            }
        }
Пример #5
0
    private void InteractObject(IGeometryModel model)
    {
        var clicks     = model.AddClick();
        var selectData = clicksData.clicksData
                         .Where(x => x.objectType == model.Type && (clicks >= x.minClicksCount && clicks <= x.maxClicksCount));

        foreach (var data in selectData)
        {
            model.ChangeColor(data.color);
            break;
        }
    }
Пример #6
0
        public static MeshTemplate FromModel(IGeometryModel model, int meshIndex)
        {
            var mesh = model.Meshes[meshIndex];

            if (mesh.IsInstancing)
            {
                return(new InstancedMeshTemplate(model, mesh));
            }
            else
            {
                return(new MeshTemplate(model, mesh));
            }
        }
Пример #7
0
        private IEnumerable <Material> GetMaterials(IGeometryModel model)
        {
            var indexes = model.Meshes.SelectMany(m => m.Submeshes)
                          .Select(s => s.MaterialIndex).Distinct().ToArray();

            var bitmapLookup = new Dictionary <int, DiffuseMaterial>();

            for (short i = 0; i < model.Materials.Count; i++)
            {
                if (!indexes.Contains(i))
                {
                    yield return(null);

                    continue;
                }

                var             mat = model.Materials[i];
                DiffuseMaterial material;

                try
                {
                    var diffuse = mat.Submaterials.First(m => m.Usage == MaterialUsage.Diffuse);
                    if (!bitmapLookup.ContainsKey(diffuse.Bitmap.Id))
                    {
                        var dds = diffuse.Bitmap.ToDds(0);

                        var brush = new ImageBrush(dds.ToBitmapSource(new DdsOutputArgs(DecompressOptions.Bgr24)))
                        {
                            ViewportUnits = BrushMappingMode.Absolute,
                            TileMode      = TileMode.Tile,
                            Viewport      = new Rect(0, 0, 1f / Math.Abs(diffuse.Tiling.X), 1f / Math.Abs(diffuse.Tiling.Y))
                        };

                        brush.Freeze();
                        material = new DiffuseMaterial(brush);
                        material.Freeze();
                        bitmapLookup[diffuse.Bitmap.Id] = material;
                    }
                    else
                    {
                        material = bitmapLookup[diffuse.Bitmap.Id];
                    }
                }
                catch
                {
                    material = ErrorMaterial;
                }

                yield return(material);
            }
        }
Пример #8
0
        private IEnumerable <IGeometryPermutation> GetSelectedPermutations(IGeometryModel model)
        {
            foreach (var parent in TreeViewItems.Where(i => i.IsChecked != false))
            {
                var region = model.Regions.ElementAtOrDefault((parent.Tag as RenderModel3D.Region)?.SourceIndex ?? -1);
                if (region == null)
                {
                    continue;
                }

                foreach (var child in parent.Items.Where(i => i.IsChecked == true))
                {
                    var permutation = region.Permutations.ElementAtOrDefault((child.Tag as RenderModel3D.Permutation)?.SourceIndex ?? -1);
                    if (permutation != null)
                    {
                        yield return(permutation);
                    }
                }
            }
        }
Пример #9
0
            public MultiMesh(IGeometryModel model, int meshIndex, int meshCount)
            {
                if (model == null)
                {
                    throw new ArgumentNullException(nameof(model));
                }

                if (meshIndex < 0 || meshIndex >= model.Meshes.Count)
                {
                    throw new ArgumentOutOfRangeException(nameof(meshIndex));
                }

                if (meshCount < 1 || meshIndex + meshCount > model.Meshes.Count)
                {
                    throw new ArgumentOutOfRangeException(nameof(meshCount));
                }

                this.model     = model;
                this.meshIndex = meshIndex;
                this.meshCount = meshCount;
            }
Пример #10
0
        public static void WriteModelFile(IGeometryModel model, string fileName, string formatId)
        {
            if (model == null)
            {
                throw new ArgumentNullException(nameof(model));
            }

            if (string.IsNullOrWhiteSpace(fileName))
            {
                throw new ArgumentNullException(nameof(fileName));
            }

            formatId = (formatId ?? Settings.DefaultSaveFormat).ToLower();
            if (!ExportFormats.Any(f => f.FormatId == formatId))
            {
                throw new ArgumentException($"{formatId} is not a supported format.", nameof(formatId));
            }

            var ext = "." + GetFormatExtension(formatId);

            if (!fileName.EndsWith(ext, StringComparison.OrdinalIgnoreCase))
            {
                fileName += ext;
            }

            var format = ExportFormats.First(f => f.FormatId == formatId);

            if (format.ExportFunction != null)
            {
                format.ExportFunction(model, fileName);
            }
            else
            {
                using (var context = new Assimp.AssimpContext())
                {
                    var scene = model.CreateAssimpScene(context, formatId);
                    context.ExportFile(scene, fileName, formatId);
                }
            }
        }
Пример #11
0
        public static Assimp.Scene CreateAssimpScene(this IGeometryModel model, Assimp.AssimpContext context, string formatId)
        {
            var scale = ModelViewerPlugin.Settings.GeometryScale;

            //either Assimp or collada has issues when there is a name conflict
            const string bonePrefix = "~";
            const string geomPrefix = "-";
            const string scenPrefix = "$";

            var scene = new Assimp.Scene();

            scene.RootNode = new Assimp.Node($"{scenPrefix}{model.Name}");

            //Assimp is Y-up in inches by default - this forces it to export as Z-up in meters
            scene.RootNode.Transform = (CoordinateSystem.HaloCEX * ModelViewerPlugin.Settings.AssimpScale).ToAssimp4x4();

            #region Nodes
            var allNodes = new List <Assimp.Node>();
            foreach (var node in model.Nodes)
            {
                var result = new Assimp.Node($"{bonePrefix}{node.Name}");

                var q   = new System.Numerics.Quaternion(node.Rotation.X, node.Rotation.Y, node.Rotation.Z, node.Rotation.W);
                var mat = System.Numerics.Matrix4x4.CreateFromQuaternion(q);
                mat.Translation  = new System.Numerics.Vector3(node.Position.X * scale, node.Position.Y * scale, node.Position.Z * scale);
                result.Transform = mat.ToAssimp4x4();

                allNodes.Add(result);
            }

            for (int i = 0; i < model.Nodes.Count; i++)
            {
                var node = model.Nodes[i];
                if (node.ParentIndex >= 0)
                {
                    allNodes[node.ParentIndex].Children.Add(allNodes[i]);
                }
                else
                {
                    scene.RootNode.Children.Add(allNodes[i]);
                }
            }
            #endregion

            var meshLookup = new List <int>();

            #region Meshes
            for (int i = 0; i < model.Meshes.Count; i++)
            {
                var geom = model.Meshes[i];
                if (geom.Submeshes.Count == 0)
                {
                    meshLookup.Add(-1);
                    continue;
                }

                meshLookup.Add(scene.MeshCount);

                foreach (var sub in geom.Submeshes)
                {
                    var m = new Assimp.Mesh($"mesh{i:D3}");

                    var indices = geom.Indicies.Skip(sub.IndexStart).Take(sub.IndexLength);

                    var minIndex  = indices.Min();
                    var maxIndex  = indices.Max();
                    var vertCount = maxIndex - minIndex + 1;

                    if (geom.IndexFormat == IndexFormat.TriangleStrip)
                    {
                        indices = indices.Unstrip();
                    }

                    indices = indices.Select(x => x - minIndex);
                    var vertices = geom.Vertices.Skip(minIndex).Take(vertCount);

                    if (geom.BoundsIndex >= 0)
                    {
                        vertices = vertices.Select(v => (IVertex) new CompressedVertex(v, model.Bounds[geom.BoundsIndex.Value]));
                    }

                    int vIndex     = -1;
                    var boneLookup = new Dictionary <int, Assimp.Bone>();
                    foreach (var v in vertices)
                    {
                        vIndex++;

                        if (v.Position.Count > 0)
                        {
                            m.Vertices.Add(v.Position[0].ToAssimp3D(scale));

                            //some Halo shaders use position W as the colour alpha - add it to a colour channel to preserve it
                            //also assimp appears to have issues exporting obj when a colour channel exists so only do this for collada
                            if (formatId == "collada" && v.Color.Count == 0 && !float.IsNaN(v.Position[0].W))
                            {
                                m.VertexColorChannels[0].Add(new Assimp.Color4D {
                                    R = v.Position[0].W
                                });
                            }
                        }

                        if (v.Normal.Count > 0)
                        {
                            m.Normals.Add(v.Normal[0].ToAssimp3D());
                        }

                        if (v.TexCoords.Count > 0)
                        {
                            m.TextureCoordinateChannels[0].Add(v.TexCoords[0].ToAssimpUV());
                        }

                        if (geom.VertexWeights == VertexWeights.None && !geom.NodeIndex.HasValue)
                        {
                            continue;
                        }

                        #region Vertex Weights
                        var weights = new List <Tuple <int, float> >(4);

                        if (geom.NodeIndex.HasValue)
                        {
                            weights.Add(Tuple.Create <int, float>(geom.NodeIndex.Value, 1));
                        }
                        else if (geom.VertexWeights == VertexWeights.Skinned)
                        {
                            var ind = v.BlendIndices[0];
                            var wt  = v.BlendWeight[0];

                            if (wt.X > 0)
                            {
                                weights.Add(Tuple.Create((int)ind.X, wt.X));
                            }
                            if (wt.Y > 0)
                            {
                                weights.Add(Tuple.Create((int)ind.Y, wt.Y));
                            }
                            if (wt.Z > 0)
                            {
                                weights.Add(Tuple.Create((int)ind.Z, wt.Z));
                            }
                            if (wt.W > 0)
                            {
                                weights.Add(Tuple.Create((int)ind.W, wt.W));
                            }
                        }

                        foreach (var val in weights)
                        {
                            Assimp.Bone b;
                            if (boneLookup.ContainsKey(val.Item1))
                            {
                                b = boneLookup[val.Item1];
                            }
                            else
                            {
                                var t = model.Nodes[val.Item1].OffsetTransform;
                                t.M41 *= scale;
                                t.M42 *= scale;
                                t.M43 *= scale;

                                b = new Assimp.Bone
                                {
                                    Name         = bonePrefix + model.Nodes[val.Item1].Name,
                                    OffsetMatrix = t.ToAssimp4x4()
                                };

                                m.Bones.Add(b);
                                boneLookup.Add(val.Item1, b);
                            }

                            b.VertexWeights.Add(new Assimp.VertexWeight(vIndex, val.Item2));
                        }
                        #endregion
                    }

                    m.SetIndices(indices.ToArray(), 3);
                    m.MaterialIndex = sub.MaterialIndex;

                    scene.Meshes.Add(m);
                }
            }
            #endregion

            #region Regions
            foreach (var reg in model.Regions)
            {
                var regNode = new Assimp.Node($"{geomPrefix}{reg.Name}");
                foreach (var perm in reg.Permutations)
                {
                    var meshStart = meshLookup[perm.MeshIndex];
                    if (meshStart < 0)
                    {
                        continue;
                    }

                    var permNode = new Assimp.Node($"{geomPrefix}{perm.Name}");
                    if (perm.TransformScale != 1 || !perm.Transform.IsIdentity)
                    {
                        permNode.Transform = Assimp.Matrix4x4.FromScaling(new Assimp.Vector3D(perm.TransformScale)) * perm.Transform.ToAssimp4x4(scale);
                    }

                    var meshCount = Enumerable.Range(perm.MeshIndex, perm.MeshCount).Sum(i => model.Meshes[i].Submeshes.Count);
                    permNode.MeshIndices.AddRange(Enumerable.Range(meshStart, meshCount));

                    regNode.Children.Add(permNode);
                }

                if (regNode.ChildCount > 0)
                {
                    scene.RootNode.Children.Add(regNode);
                }
            }
            #endregion

            #region Materials
            foreach (var mat in model.Materials)
            {
                var m = new Assimp.Material {
                    Name = mat?.Name ?? "unused"
                };

                //prevent max from making every material super shiny
                m.ColorEmissive = m.ColorReflective = m.ColorSpecular = new Assimp.Color4D(0, 0, 0, 1);
                m.ColorDiffuse  = m.ColorTransparent = new Assimp.Color4D(1);

                //max only seems to care about diffuse
                var dif = mat?.Submaterials.FirstOrDefault(s => s.Usage == MaterialUsage.Diffuse);
                if (dif != null)
                {
                    var suffix   = dif.Bitmap.SubmapCount > 1 ? "[0]" : string.Empty;
                    var filePath = $"{dif.Bitmap.Name}{suffix}.{ModelViewerPlugin.Settings.MaterialExtension}";

                    //collada spec says it requires URI formatting, and Assimp doesn't do it for us
                    //for some reason "new Uri(filePath, UriKind.Relative)" doesnt change the slashes, have to use absolute uri
                    if (formatId == FormatId.Collada)
                    {
                        filePath = new Uri("X:\\", UriKind.Absolute).MakeRelativeUri(new Uri(System.IO.Path.Combine("X:\\", filePath))).ToString();
                    }

                    m.TextureDiffuse = new Assimp.TextureSlot
                    {
                        BlendFactor = 1,
                        FilePath    = filePath,
                        TextureType = Assimp.TextureType.Diffuse
                    };
                }

                scene.Materials.Add(m);
            }
            #endregion

            return(scene);
        }
Пример #12
0
        private IEnumerable <Model3DGroup> GetMeshes(IGeometryModel model)
        {
            var indexes = model.Regions.SelectMany(r => r.Permutations)
                          .SelectMany(p => Enumerable.Range(p.MeshIndex, p.MeshCount))
                          .Distinct().ToList();

            var materials = GetMaterials(model).ToList();

            for (int i = 0; i < model.Meshes.Count; i++)
            {
                var mesh = model.Meshes[i];

                if (mesh.Submeshes.Count == 0 || !indexes.Contains(i))
                {
                    yield return(null);

                    continue;
                }

                var mGroup = new Model3DGroup();
                var tGroup = new Transform3DGroup();

                var texMatrix = Matrix.Identity;
                if (mesh.BoundsIndex >= 0)
                {
                    var bounds = model.Bounds[mesh.BoundsIndex.Value];
                    texMatrix = new Matrix
                    {
                        M11     = bounds.UBounds.Length,
                        M22     = bounds.VBounds.Length,
                        OffsetX = bounds.UBounds.Min,
                        OffsetY = bounds.VBounds.Min
                    };

                    var transform = new Matrix3D
                    {
                        M11     = bounds.XBounds.Length,
                        M22     = bounds.YBounds.Length,
                        M33     = bounds.ZBounds.Length,
                        OffsetX = bounds.XBounds.Min,
                        OffsetY = bounds.YBounds.Min,
                        OffsetZ = bounds.ZBounds.Min
                    };

                    var tform = new MatrixTransform3D(transform);
                    tform.Freeze();
                    tGroup.Children.Add(tform);
                }

                foreach (var sub in mesh.Submeshes)
                {
                    try
                    {
                        var geom = new MeshGeometry3D();

                        var indices = mesh.Indicies.Skip(sub.IndexStart).Take(sub.IndexLength).ToList();
                        if (mesh.IndexFormat == IndexFormat.TriangleStrip)
                        {
                            indices = indices.Unstrip().ToList();
                        }

                        var vertStart  = indices.Min();
                        var vertLength = indices.Max() - vertStart + 1;

                        var verts     = mesh.Vertices.Skip(vertStart).Take(vertLength);
                        var positions = verts.Select(v => new Point3D(v.Position[0].X, v.Position[0].Y, v.Position[0].Z));

                        (geom.Positions = new Point3DCollection(positions)).Freeze();
                        (geom.TriangleIndices = new Int32Collection(indices.Select(j => j - vertStart))).Freeze();

                        if (mesh.Vertices[0].TexCoords.Count > 0)
                        {
                            var texcoords = verts.Select(v => new Point(v.TexCoords[0].X, v.TexCoords[0].Y)).ToArray();
                            if (!texMatrix.IsIdentity)
                            {
                                texMatrix.Transform(texcoords);
                            }
                            (geom.TextureCoordinates = new PointCollection(texcoords)).Freeze();
                        }

                        if (mesh.Vertices[0].Normal.Count > 0)
                        {
                            var normals = verts.Select(v => new Vector3D(v.Normal[0].X, v.Normal[0].Y, v.Normal[0].Z));
                            (geom.Normals = new Vector3DCollection(normals)).Freeze();
                        }

                        var mat      = materials.ElementAtOrDefault(sub.MaterialIndex) ?? ErrorMaterial;
                        var subGroup = new GeometryModel3D(geom, mat)
                        {
                            BackMaterial = mat
                        };
                        subGroup.Freeze();
                        mGroup.Children.Add(subGroup);
                    }
                    catch { }
                }

                (mGroup.Transform = tGroup).Freeze();
                mGroup.Freeze();

                yield return(mGroup);
            }
        }
Пример #13
0
        internal MeshTemplate(IGeometryModel model, IGeometryMesh mesh)
        {
            submeshCount = mesh.Submeshes.Count;
            matIndex     = new int[submeshCount];
            submeshes    = new Helix.MeshGeometry3D[submeshCount];

            var texMatrix    = SharpDX.Matrix.Identity;
            var boundsMatrix = SharpDX.Matrix.Identity;

            if (mesh.BoundsIndex >= 0)
            {
                var bounds = model.Bounds[mesh.BoundsIndex.Value];
                boundsMatrix = bounds.ToMatrix3();
                texMatrix    = bounds.ToMatrix2();
            }

            for (int i = 0; i < submeshCount; i++)
            {
                var sub = mesh.Submeshes[i];
                matIndex[i] = sub.MaterialIndex;

                var subIndices = mesh.Indicies.Skip(sub.IndexStart).Take(sub.IndexLength).ToList();
                if (mesh.IndexFormat == IndexFormat.TriangleStrip)
                {
                    subIndices = subIndices.Unstrip().ToList();
                }

                var vertStart  = subIndices.Min();
                var vertLength = subIndices.Max() - vertStart + 1;
                var subVerts   = mesh.Vertices.Skip(vertStart).Take(vertLength);

                IEnumerable <SharpDX.Vector3> subPositions;
                if (boundsMatrix.IsIdentity)
                {
                    subPositions = subVerts.Select(v => v.Position[0].ToVector3());
                }
                else
                {
                    subPositions = subVerts.Select(v => SharpDX.Vector3.TransformCoordinate(v.Position[0].ToVector3(), boundsMatrix));
                }

                IEnumerable <SharpDX.Vector2> subTexcoords;
                if (texMatrix.IsIdentity)
                {
                    subTexcoords = subVerts.Select(v => v.TexCoords[0].ToVector2());
                }
                else
                {
                    subTexcoords = subVerts.Select(v => SharpDX.Vector2.TransformCoordinate(v.TexCoords[0].ToVector2(), texMatrix));
                }

                submeshes[i] = new Helix.MeshGeometry3D
                {
                    Indices            = new Helix.IntCollection(subIndices.Select(j => j - vertStart)),
                    Positions          = new Helix.Vector3Collection(subPositions),
                    TextureCoordinates = new Helix.Vector2Collection(subTexcoords)
                };

                if (mesh.Vertices[0].Normal.Count > 0)
                {
                    var subNormals = subVerts.Select(v => new SharpDX.Vector3(v.Normal[0].X, v.Normal[0].Y, v.Normal[0].Z));
                    submeshes[i].Normals = new Helix.Vector3Collection(subNormals);
                }

                submeshes[i].UpdateOctree();
            }
        }
Пример #14
0
        public static void WriteAMF(this IGeometryModel model, string fileName, float scale)
        {
            if (!Directory.GetParent(fileName).Exists)
            {
                Directory.GetParent(fileName).Create();
            }
            if (!fileName.EndsWith(".amf", StringComparison.CurrentCultureIgnoreCase))
            {
                fileName += ".amf";
            }

            using (var fs = new FileStream(fileName, FileMode.Create, FileAccess.Write))
                using (var bw = new EndianWriter(fs, ByteOrder.LittleEndian))
                {
                    var dupeDic = new Dictionary <int, long>();

                    var validRegions = model.Regions
                                       .Select(r => new { r.Name, Permutations = r.Permutations.Where(p => model.Meshes[p.MeshIndex].Submeshes.Count > 0).ToList() })
                                       .Where(r => r.Permutations.Count > 0)
                                       .ToList();

                    var fauxMeshes = validRegions.SelectMany(r => r.Permutations)
                                     .Where(p => p.MeshCount > 1)
                                     .GroupBy(p => p.MeshIndex)
                                     .ToDictionary(g => g.Key, g => new MultiMesh(model, g.Key, g.First().MeshCount));

                    #region Address Lists
                    var headerAddressList = new List <long>();
                    var headerValueList   = new List <long>();

                    var markerAddressList = new List <long>();
                    var markerValueList   = new List <long>();

                    var permAddressList = new List <long>();
                    var permValueList   = new List <long>();

                    var vertAddressList = new List <long>();
                    var vertValueList   = new List <long>();

                    var indxAddressList = new List <long>();
                    var indxValueList   = new List <long>();

                    var meshAddressList = new List <long>();
                    var meshValueList   = new List <long>();
                    #endregion

                    #region Header
                    bw.Write("AMF!".ToCharArray());
                    bw.Write(2.0f);
                    bw.WriteStringNullTerminated(model.Name ?? string.Empty);

                    bw.Write(model.Nodes.Count);
                    headerAddressList.Add(bw.BaseStream.Position);
                    bw.Write(0);

                    bw.Write(model.MarkerGroups.Count);
                    headerAddressList.Add(bw.BaseStream.Position);
                    bw.Write(0);

                    bw.Write(validRegions.Count);
                    headerAddressList.Add(bw.BaseStream.Position);
                    bw.Write(0);

                    bw.Write(model.Materials.Count);
                    headerAddressList.Add(bw.BaseStream.Position);
                    bw.Write(0);
                    #endregion

                    #region Nodes
                    headerValueList.Add(bw.BaseStream.Position);
                    foreach (var node in model.Nodes)
                    {
                        bw.WriteStringNullTerminated(node.Name);
                        bw.Write(node.ParentIndex);
                        bw.Write(node.FirstChildIndex);
                        bw.Write(node.NextSiblingIndex);
                        bw.Write(node.Position.X * scale);
                        bw.Write(node.Position.Y * scale);
                        bw.Write(node.Position.Z * scale);
                        bw.Write(node.Rotation.X);
                        bw.Write(node.Rotation.Y);
                        bw.Write(node.Rotation.Z);
                        bw.Write(node.Rotation.W);
                    }
                    #endregion

                    #region Marker Groups
                    headerValueList.Add(bw.BaseStream.Position);
                    foreach (var group in model.MarkerGroups)
                    {
                        bw.WriteStringNullTerminated(group.Name);
                        bw.Write(group.Markers.Count);
                        markerAddressList.Add(bw.BaseStream.Position);
                        bw.Write(0);
                    }
                    #endregion

                    #region Markers
                    foreach (var group in model.MarkerGroups)
                    {
                        markerValueList.Add(bw.BaseStream.Position);
                        foreach (var marker in group.Markers)
                        {
                            bw.Write(marker.RegionIndex);
                            bw.Write(marker.PermutationIndex);
                            bw.Write((short)marker.NodeIndex);
                            bw.Write(marker.Position.X * scale);
                            bw.Write(marker.Position.Y * scale);
                            bw.Write(marker.Position.Z * scale);
                            bw.Write(marker.Rotation.X);
                            bw.Write(marker.Rotation.Y);
                            bw.Write(marker.Rotation.Z);
                            bw.Write(marker.Rotation.W);
                        }
                    }
                    #endregion

                    #region Regions
                    headerValueList.Add(bw.BaseStream.Position);
                    foreach (var region in validRegions)
                    {
                        bw.WriteStringNullTerminated(region.Name);
                        bw.Write(region.Permutations.Count);
                        permAddressList.Add(bw.BaseStream.Position);
                        bw.Write(0);
                    }
                    #endregion

                    #region Permutations
                    foreach (var region in validRegions)
                    {
                        permValueList.Add(bw.BaseStream.Position);
                        foreach (var perm in region.Permutations)
                        {
                            var part = fauxMeshes.ContainsKey(perm.MeshIndex)
                            ? fauxMeshes[perm.MeshIndex]
                            : model.Meshes[perm.MeshIndex];

                            bw.WriteStringNullTerminated(perm.Name);
                            bw.Write((byte)part.VertexWeights);
                            bw.Write(part.NodeIndex ?? byte.MaxValue);

                            bw.Write(part.Vertices.Count);
                            vertAddressList.Add(bw.BaseStream.Position);
                            bw.Write(0);

                            int count = 0;
                            foreach (var submesh in part.Submeshes)
                            {
                                var indices = part.Indicies.Skip(submesh.IndexStart).Take(submesh.IndexLength);
                                if (part.IndexFormat == IndexFormat.TriangleStrip)
                                {
                                    indices = Unstrip(indices);
                                }

                                count += indices.Count() / 3;
                            }

                            bw.Write(count);
                            indxAddressList.Add(bw.BaseStream.Position);
                            bw.Write(0);

                            bw.Write(part.Submeshes.Count);
                            meshAddressList.Add(bw.BaseStream.Position);
                            bw.Write(0);

                            if (perm.Transform.IsIdentity && perm.TransformScale == 1)
                            {
                                bw.Write(float.NaN);
                            }
                            else
                            {
                                bw.Write(perm.TransformScale);
                                bw.Write(perm.Transform.M11);
                                bw.Write(perm.Transform.M12);
                                bw.Write(perm.Transform.M13);
                                bw.Write(perm.Transform.M21);
                                bw.Write(perm.Transform.M22);
                                bw.Write(perm.Transform.M23);
                                bw.Write(perm.Transform.M31);
                                bw.Write(perm.Transform.M32);
                                bw.Write(perm.Transform.M33);
                                bw.Write(perm.Transform.M41);
                                bw.Write(perm.Transform.M42);
                                bw.Write(perm.Transform.M43);
                            }
                        }
                    }
                    #endregion

                    #region Vertices
                    var emptyVector = new RealVector3D();

                    foreach (var region in validRegions)
                    {
                        foreach (var perm in region.Permutations)
                        {
                            var part = fauxMeshes.ContainsKey(perm.MeshIndex)
                            ? fauxMeshes[perm.MeshIndex]
                            : model.Meshes[perm.MeshIndex];

                            var scale1 = perm.Transform.IsIdentity && perm.TransformScale == 1 ? scale : 1;

                            long address;
                            if (dupeDic.TryGetValue(perm.MeshIndex, out address))
                            {
                                vertValueList.Add(address);
                                continue;
                            }
                            else
                            {
                                dupeDic.Add(perm.MeshIndex, bw.BaseStream.Position);
                            }

                            vertValueList.Add(bw.BaseStream.Position);

                            IXMVector vector;
                            var       vertices = part.BoundsIndex >= 0 ? part.Vertices.Select(v => (IVertex) new CompressedVertex(v, model.Bounds[part.BoundsIndex.Value])) : part.Vertices;
                            foreach (var vert in vertices)
                            {
                                vector = vert.Position.Count > 0 ? vert.Position[0] : emptyVector;
                                bw.Write(vector.X * scale1);
                                bw.Write(vector.Y * scale1);
                                bw.Write(vector.Z * scale1);

                                vector = vert.Normal.Count > 0 ? vert.Normal[0] : emptyVector;
                                bw.Write(vector.X);
                                bw.Write(vector.Y);
                                bw.Write(vector.Z);

                                vector = vert.TexCoords.Count > 0 ? vert.TexCoords[0] : emptyVector;
                                bw.Write(vector.X);
                                bw.Write(1 - vector.Y);

                                if (part.VertexWeights == VertexWeights.Rigid)
                                {
                                    IXMVector i;
                                    var       indices = new List <int>();
                                    i = vert.BlendIndices.Count > 0 ? vert.BlendIndices[0] : emptyVector;

                                    if (!indices.Contains((int)i.X) && i.X != 0)
                                    {
                                        indices.Add((int)i.X);
                                    }
                                    if (!indices.Contains((int)i.Y) && i.X != 0)
                                    {
                                        indices.Add((int)i.Y);
                                    }
                                    if (!indices.Contains((int)i.Z) && i.X != 0)
                                    {
                                        indices.Add((int)i.Z);
                                    }
                                    if (!indices.Contains((int)i.W) && i.X != 0)
                                    {
                                        indices.Add((int)i.W);
                                    }

                                    if (indices.Count == 0)
                                    {
                                        indices.Add(0);
                                    }

                                    foreach (int index in indices)
                                    {
                                        bw.Write((byte)index);
                                    }

                                    if (indices.Count < 4)
                                    {
                                        bw.Write(byte.MaxValue);
                                    }
                                }
                                else if (part.VertexWeights == VertexWeights.Skinned)
                                {
                                    var indices = (vert.BlendIndices.Count > 0 ? vert.BlendIndices[0] : emptyVector).AsEnumerable().ToArray();
                                    var weights = (vert.BlendWeight.Count > 0 ? vert.BlendWeight[0] : emptyVector).AsEnumerable().ToArray();

                                    var count = weights.Count(w => w > 0);

                                    if (count == 0)
                                    {
                                        bw.Write((byte)0);
                                        bw.Write((byte)255);
                                        bw.Write(0);
                                        continue;
                                        //throw new Exception("no weights on a weighted node. report this.");
                                    }

                                    for (int i = 0; i < 4; i++)
                                    {
                                        if (weights[i] > 0)
                                        {
                                            bw.Write((byte)indices[i]);
                                        }
                                    }

                                    if (count != 4)
                                    {
                                        bw.Write(byte.MaxValue);
                                    }

                                    foreach (var w in weights.Where(w => w > 0))
                                    {
                                        bw.Write(w);
                                    }
                                }
                            }
                        }
                    }
                    #endregion

                    #region Indices
                    dupeDic.Clear();
                    foreach (var region in validRegions)
                    {
                        foreach (var perm in region.Permutations)
                        {
                            var part = fauxMeshes.ContainsKey(perm.MeshIndex)
                            ? fauxMeshes[perm.MeshIndex]
                            : model.Meshes[perm.MeshIndex];

                            long address;
                            if (dupeDic.TryGetValue(perm.MeshIndex, out address))
                            {
                                indxValueList.Add(address);
                                continue;
                            }
                            else
                            {
                                dupeDic.Add(perm.MeshIndex, bw.BaseStream.Position);
                            }

                            indxValueList.Add(bw.BaseStream.Position);

                            foreach (var submesh in part.Submeshes)
                            {
                                var indices = part.Indicies.Skip(submesh.IndexStart).Take(submesh.IndexLength);
                                if (part.IndexFormat == IndexFormat.TriangleStrip)
                                {
                                    indices = Unstrip(indices);
                                }

                                foreach (var index in indices)
                                {
                                    if (part.Vertices.Count > ushort.MaxValue)
                                    {
                                        bw.Write(index);
                                    }
                                    else
                                    {
                                        bw.Write((ushort)index);
                                    }
                                }
                            }
                        }
                    }
                    #endregion

                    #region Submeshes
                    foreach (var region in validRegions)
                    {
                        foreach (var perm in region.Permutations)
                        {
                            meshValueList.Add(bw.BaseStream.Position);

                            var part = fauxMeshes.ContainsKey(perm.MeshIndex)
                            ? fauxMeshes[perm.MeshIndex]
                            : model.Meshes[perm.MeshIndex];

                            int currentPosition = 0;
                            foreach (var mesh in part.Submeshes)
                            {
                                var indices = part.Indicies.Skip(mesh.IndexStart).Take(mesh.IndexLength);
                                if (part.IndexFormat == IndexFormat.TriangleStrip)
                                {
                                    indices = Unstrip(indices);
                                }

                                var faceCount = indices.Count() / 3;

                                bw.Write(mesh.MaterialIndex);
                                bw.Write(currentPosition);
                                bw.Write(faceCount);

                                currentPosition += faceCount;
                            }
                        }
                    }
                    #endregion

                    #region Shaders
                    headerValueList.Add(bw.BaseStream.Position);
                    foreach (var material in model.Materials)
                    {
                        const string nullPath = "null";

                        //skip null shaders
                        if (material == null)
                        {
                            bw.WriteStringNullTerminated(nullPath);
                            for (int i = 0; i < 8; i++)
                            {
                                bw.WriteStringNullTerminated(nullPath);
                            }

                            for (int i = 0; i < 4; i++)
                            {
                                bw.Write(0);
                            }

                            bw.Write(Convert.ToByte(false));
                            bw.Write(Convert.ToByte(false));

                            continue;
                        }

                        if (material.Flags.HasFlag(MaterialFlags.TerrainBlend))
                        {
                            bw.WriteStringNullTerminated("*" + material.Name);

                            var blendInfo  = material.Submaterials.FirstOrDefault(s => s.Usage == MaterialUsage.BlendMap);
                            var baseInfo   = material.Submaterials.Where(s => s.Usage == MaterialUsage.Diffuse).ToList();
                            var bumpInfo   = material.Submaterials.Where(s => s.Usage == MaterialUsage.Normal).ToList();
                            var detailInfo = material.Submaterials.Where(s => s.Usage == MaterialUsage.DiffuseDetail).ToList();

                            if (blendInfo == null)
                            {
                                bw.WriteStringNullTerminated(nullPath);
                            }
                            else
                            {
                                bw.WriteStringNullTerminated(blendInfo.Bitmap.Name);
                                bw.Write(blendInfo.Tiling.X);
                                bw.Write(blendInfo.Tiling.Y);
                            }

                            bw.Write((byte)baseInfo.Count);
                            bw.Write((byte)bumpInfo.Count);
                            bw.Write((byte)detailInfo.Count);

                            foreach (var info in baseInfo.Concat(bumpInfo).Concat(detailInfo))
                            {
                                bw.WriteStringNullTerminated(info.Bitmap.Name);
                                bw.Write(info.Tiling.X);
                                bw.Write(info.Tiling.Y);
                            }
                        }
                        else
                        {
                            bw.WriteStringNullTerminated(material.Name);
                            for (int i = 0; i < 8; i++)
                            {
                                var submat = material.Submaterials.FirstOrDefault(s => s.Usage == (MaterialUsage)i);
                                bw.WriteStringNullTerminated(submat?.Bitmap.Name ?? nullPath);
                                if (submat != null)
                                {
                                    bw.Write(submat.Tiling.X);
                                    bw.Write(submat.Tiling.Y);
                                }
                            }

                            for (int i = 0; i < 4; i++)
                            {
                                var tint = material.TintColours.FirstOrDefault(t => t.Usage == (TintUsage)i);
                                if (tint == null)
                                {
                                    bw.Write(0);
                                    continue;
                                }

                                bw.Write(tint.R);
                                bw.Write(tint.G);
                                bw.Write(tint.B);
                                bw.Write(tint.A);
                            }

                            bw.Write(Convert.ToByte(material.Flags.HasFlag(MaterialFlags.Transparent)));
                            bw.Write(Convert.ToByte(material.Flags.HasFlag(MaterialFlags.ColourChange)));
                        }
                    }
                    #endregion

                    #region Write Addresses
                    for (int i = 0; i < headerAddressList.Count; i++)
                    {
                        bw.BaseStream.Position = headerAddressList[i];
                        bw.Write((int)headerValueList[i]);
                    }

                    for (int i = 0; i < markerAddressList.Count; i++)
                    {
                        bw.BaseStream.Position = markerAddressList[i];
                        bw.Write((int)markerValueList[i]);
                    }

                    for (int i = 0; i < permAddressList.Count; i++)
                    {
                        bw.BaseStream.Position = permAddressList[i];
                        bw.Write((int)permValueList[i]);
                    }

                    for (int i = 0; i < vertAddressList.Count; i++)
                    {
                        bw.BaseStream.Position = vertAddressList[i];
                        bw.Write((int)vertValueList[i]);
                    }

                    for (int i = 0; i < indxAddressList.Count; i++)
                    {
                        bw.BaseStream.Position = indxAddressList[i];
                        bw.Write((int)indxValueList[i]);
                    }

                    for (int i = 0; i < meshAddressList.Count; i++)
                    {
                        bw.BaseStream.Position = meshAddressList[i];
                        bw.Write((int)meshValueList[i]);
                    }
                    #endregion
                }
        }
Пример #15
0
 internal InstancedMeshTemplate(IGeometryModel model, IGeometryMesh mesh)
     : base(model, mesh)
 {
     rootMeshes = new Helix.InstancingMeshGeometryModel3D[submeshCount];
 }
Пример #16
0
        public static void WriteJMS(this IGeometryModel model, string fileName, float scale)
        {
            const string float4 = "{0:F6}\t{1:F6}\t{2:F6}\t{3:F6}";
            const string float3 = "{0:F6}\t{1:F6}\t{2:F6}";
            const string float1 = "{0:F6}";

            var modelName = Path.GetFileNameWithoutExtension(fileName);
            var directory = Path.Combine(Directory.GetParent(fileName).FullName, "models");

            Directory.CreateDirectory(directory);

            var permNames = model.Regions.SelectMany(r => r.Permutations)
                            .Select(p => p.Name)
                            .Distinct();

            foreach (var permName in permNames)
            {
                var allRegions = model.Regions.Where(r => r.Permutations.Any(p => p.Name == permName)).ToList();
                var allPerms   = model.Regions.SelectMany(r => r.Permutations).Where(p => p.Name == permName).ToList();

                using (var sw = new StreamWriter(Path.Combine(directory, permName + ".jms")))
                {
                    sw.WriteLine("8200");
                    sw.WriteLine("14689795");

                    sw.WriteLine(model.Nodes.Count);
                    foreach (var node in model.Nodes)
                    {
                        sw.WriteLine(node.Name);
                        sw.WriteLine(node.FirstChildIndex);
                        sw.WriteLine(node.NextSiblingIndex);
                        sw.WriteLine("{0}\t{1}\t{2}\t{3}", -node.Rotation.X, -node.Rotation.Y, -node.Rotation.Z, node.Rotation.W);
                        sw.WriteLine(float3, node.Position.X * scale, node.Position.Y * scale, node.Position.Z * scale);
                    }

                    sw.WriteLine(model.Materials.Count);
                    foreach (var mat in model.Materials)
                    {
                        sw.WriteLine(mat?.Name ?? "unused");
                        sw.WriteLine("<none>"); //unknown
                    }

                    sw.WriteLine(model.MarkerGroups.Sum(g => g.Markers.Count));
                    foreach (var group in model.MarkerGroups)
                    {
                        foreach (var marker in group.Markers)
                        {
                            sw.WriteLine(group.Name);
                            sw.WriteLine(-1); //unknown
                            sw.WriteLine(marker.NodeIndex);
                            sw.WriteLine(float4, marker.Rotation.X, marker.Rotation.Y, marker.Rotation.Z, marker.Rotation.W);
                            sw.WriteLine(float3, marker.Position.X * scale, marker.Position.Y * scale, marker.Position.Z * scale);
                            sw.WriteLine(1); //radius
                        }
                    }

                    sw.WriteLine(allRegions.Count);
                    foreach (var region in allRegions)
                    {
                        sw.WriteLine(region.Name);
                    }

                    #region Vertices
                    var emptyVector = new RealVector3D();

                    sw.WriteLine(allPerms.SelectMany(p => model.Meshes.Skip(p.MeshIndex).Take(p.MeshCount)).Sum(m => m.Vertices.Count));
                    foreach (var perm in allPerms)
                    {
                        var mesh = model.Meshes[perm.MeshIndex];
                        foreach (var vert in mesh.Vertices)
                        {
                            var decompressed = vert;
                            if (mesh.BoundsIndex >= 0)
                            {
                                decompressed = new CompressedVertex(vert, model.Bounds[mesh.BoundsIndex.Value]);
                            }

                            var pos     = decompressed.Position.FirstOrDefault() ?? emptyVector;
                            var norm    = vert.Normal.FirstOrDefault() ?? emptyVector;
                            var tex     = decompressed.TexCoords.FirstOrDefault() ?? emptyVector;
                            var weights = decompressed.BlendWeight.FirstOrDefault() ?? emptyVector;
                            var nodes   = decompressed.BlendIndices.FirstOrDefault() ?? emptyVector;

                            var node1 = nodes.X;
                            if (mesh.NodeIndex < byte.MaxValue)
                            {
                                node1 = mesh.NodeIndex.Value;
                            }

                            sw.WriteLine("{0:F0}", node1);

                            sw.WriteLine(float3, pos.X * scale, pos.Y * scale, pos.Z * scale);
                            sw.WriteLine(float3, norm.X, norm.Y, norm.Z);

                            sw.WriteLine(nodes.Y);
                            sw.WriteLine(float1, weights.Y);

                            sw.WriteLine(float1, tex.X);
                            sw.WriteLine(float1, 1 - tex.Y);
                            sw.WriteLine(0);
                        }
                    }
                    #endregion

                    #region Triangles
                    var totalEdges = allPerms.SelectMany(p =>
                    {
                        var mesh = model.Meshes[p.MeshIndex];
                        if (mesh.IndexFormat == IndexFormat.TriangleList)
                        {
                            return(mesh.Indicies);
                        }
                        else
                        {
                            return(mesh.Submeshes.SelectMany(s => mesh.Indicies.Skip(s.IndexStart).Take(s.IndexLength).Unstrip()));
                        }
                    }).Count();

                    sw.WriteLine(totalEdges / 3);
                    int offset = 0;
                    foreach (var perm in allPerms)
                    {
                        var regIndex = allRegions.TakeWhile(r => !r.Permutations.Contains(perm)).Count();
                        var mesh     = model.Meshes[perm.MeshIndex];
                        foreach (var sub in mesh.Submeshes)
                        {
                            var temp = mesh.Indicies.Skip(sub.IndexStart).Take(sub.IndexLength);
                            if (mesh.IndexFormat == IndexFormat.TriangleStrip)
                            {
                                temp = temp.Unstrip();
                            }

                            var indices = temp.ToList();
                            for (int i = 0; i < indices.Count; i += 3)
                            {
                                sw.WriteLine(regIndex);
                                sw.WriteLine(sub.MaterialIndex);
                                sw.WriteLine("{0}\t{1}\t{2}", offset + indices[i], offset + indices[i + 1], offset + indices[i + 2]);
                            }
                        }
                        offset += mesh.Vertices.Count;
                    }
                    #endregion
                }
            }
        }
Пример #17
0
        private void SetLod(int index)
        {
            model = geometry.ReadGeometry(index);
            var meshes = GetMeshes(model).ToList();

            TreeViewItems.Clear();
            modelGroup.Children.Clear();
            foreach (var region in model.Regions)
            {
                var regNode = new TreeItemModel {
                    Header = region.Name, IsChecked = true
                };

                foreach (var perm in region.Permutations)
                {
                    var mesh = meshes.ElementAtOrDefault(perm.MeshIndex);
                    if (mesh == null || perm.MeshCount <= 0)
                    {
                        continue;
                    }

                    var permNode = new TreeItemModel {
                        Header = perm.Name, IsChecked = true
                    };
                    regNode.Items.Add(permNode);

                    var tGroup = new Transform3DGroup();

                    if (perm.TransformScale != 1)
                    {
                        var tform = new ScaleTransform3D(perm.TransformScale, perm.TransformScale, perm.TransformScale);

                        tform.Freeze();
                        tGroup.Children.Add(tform);
                    }

                    if (!perm.Transform.IsIdentity)
                    {
                        var tform = new MatrixTransform3D(new Matrix3D
                        {
                            M11 = perm.Transform.M11,
                            M12 = perm.Transform.M12,
                            M13 = perm.Transform.M13,

                            M21 = perm.Transform.M21,
                            M22 = perm.Transform.M22,
                            M23 = perm.Transform.M23,

                            M31 = perm.Transform.M31,
                            M32 = perm.Transform.M32,
                            M33 = perm.Transform.M33,

                            OffsetX = perm.Transform.M41,
                            OffsetY = perm.Transform.M42,
                            OffsetZ = perm.Transform.M43
                        });

                        tform.Freeze();
                        tGroup.Children.Add(tform);
                    }

                    Model3DGroup permGroup;
                    if (tGroup.Children.Count == 0 && perm.MeshCount == 1)
                    {
                        permGroup = meshes[perm.MeshIndex];
                    }
                    else
                    {
                        permGroup = new Model3DGroup();
                        for (int i = 0; i < perm.MeshCount; i++)
                        {
                            if (tGroup.Children.Count > 0)
                            {
                                (permGroup.Transform = tGroup).Freeze();

                                permGroup.Children.Add(meshes[perm.MeshIndex + i]);
                                permGroup.Freeze();
                            }
                            else
                            {
                                permGroup.Children.Add(meshes[perm.MeshIndex + i]);
                            }
                        }
                    }

                    permNode.Tag = new MeshTag(permGroup, perm);
                    modelGroup.Children.Add(permGroup);
                }

                if (regNode.HasItems)
                {
                    TreeViewItems.Add(regNode);
                }
            }

            renderer.ScaleToContent(new[] { modelGroup });
        }