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);
*/
}
}