using System; using System.Windows; using System.Windows.Media; using System.Windows.Media.Media3D; namespace HelixToolkit { /// /// The is a base class that contains a and /// front/back s. /// Derived classes should override the Tesselate() method to generate the geometry. /// public abstract class MeshElement3D : ModelVisual3D { public static readonly DependencyProperty FillProperty = DependencyProperty.Register("Fill", typeof(Brush), typeof(MeshElement3D), new UIPropertyMetadata(null, FillChanged)); public static readonly DependencyProperty MaterialProperty = DependencyProperty.Register("Material", typeof(Material), typeof(MeshElement3D), new UIPropertyMetadata(MaterialHelper.CreateMaterial(Brushes.Blue), MaterialChanged)); public static readonly DependencyProperty BackMaterialProperty = DependencyProperty.Register("BackMaterial", typeof(Material), typeof(MeshElement3D), new UIPropertyMetadata(MaterialHelper.CreateMaterial(Brushes.Green), MaterialChanged)); private readonly object _invalidateLock = ""; private bool doUpdates = true; private bool isInvalidated; public MeshElement3D() { Content = new GeometryModel3D(); CompositionTarget.Rendering += CompositionTarget_Rendering; InvalidateModel(); } public Brush Fill { get { return (Brush)GetValue(FillProperty); } set { SetValue(FillProperty, value); } } public Material Material { get { return (Material)GetValue(MaterialProperty); } set { SetValue(MaterialProperty, value); } } public Material BackMaterial { get { return (Material)GetValue(BackMaterialProperty); } set { SetValue(BackMaterialProperty, value); } } public GeometryModel3D Model { get { return Content as GeometryModel3D; } } private static void FillChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) { var el = (MeshElement3D)d; el.Material = MaterialHelper.CreateMaterial(el.Fill); el.BackMaterial = el.Material; } protected static void GeometryChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) { ((MeshElement3D)d).GeometryChanged(); } protected static void MaterialChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) { ((MeshElement3D)d).MaterialChanged(); } private void CompositionTarget_Rendering(object sender, EventArgs e) { lock (_invalidateLock) { if (isInvalidated) { isInvalidated = false; GeometryChanged(); MaterialChanged(); } } } private void InvalidateModel() { lock (_invalidateLock) { isInvalidated = true; } } /// /// Forces an update to the geometry model and materials /// public void UpdateModel() { GeometryChanged(); MaterialChanged(); } protected void MaterialChanged() { if (!doUpdates) return; GeometryModel3D model = Model; if (model == null) return; model.Material = Material; model.BackMaterial = BackMaterial; } protected void GeometryChanged() { if (!doUpdates) return; Model.Geometry = Tessellate(); } public void DisableUpdates() { doUpdates = false; } public void EnableUpdates() { doUpdates = true; } /// /// Do the tesselation and return the . /// /// protected abstract MeshGeometry3D Tessellate(); // alternative: /* private MeshGeometry3D Tessellate() { var mesh = new MeshGeometry3D(); var positions = mesh.Positions; var normals = mesh.Normals; var textureCoordinates = mesh.TextureCoordinates; var triangleIndices = mesh.TriangleIndices; mesh.Positions = null; mesh.Normals = null; mesh.TextureCoordinates = null; mesh.TriangleIndices = null; Tessellate(positions, normals, textureCoordinates, triangleIndices); mesh.Positions = positions; mesh.Normals = normals; mesh.TextureCoordinates = textureCoordinates; mesh.TriangleIndices = triangleIndices; } protected abstract void Tessellate(Point3DCollection points, Vector3DCollection normals, PointCollection textureCoordinates, Int32Collection triangleIndices); */ } }