using System; using System.Collections.Generic; using System.Linq; using System.Text; using Aiwaz.Contracts; using SlimDX; namespace Aiwaz.Resources { public class PickHull : IPickHull { private VertexElement positionElement; private int strideToPosition; private DataStream vertexData; private int vertexCount; private VertexElement[] vertexElements; private int vertexElementSize; private DataStream indexData; private int indexCount; private Vector3 boxMaxVector; private Vector3 boxMinVector; public PickHull(DataStream vertexData, int vertexCount, VertexElement[] vertexElements, DataStream indexData, int indexCount) { this.vertexData = vertexData; this.vertexCount = vertexCount; this.vertexElements = vertexElements; this.indexData = indexData; this.indexCount = indexCount; this.vertexElementSize = (int)vertexData.Length / vertexCount; this.positionElement = vertexElements.First(e => e.WellKnownFormat == VertexElement.Format.Position); foreach (var element in vertexElements) { if (!element.Equals(positionElement)) strideToPosition += element.Size; else break; } this.Precalculate(); } public bool TryPick(Ray pickRay, Matrix worldMatrix, out float distance) { distance = float.MaxValue; var boundingSphere = CalcBoundingSphere(worldMatrix); if (!Ray.Intersects(pickRay, boundingSphere, out distance)) return false; distance = float.MaxValue; indexData.Position = 0; for (var i = 0; i < indexCount / 3; ++i) { var triangle = new Vector3[3]; triangle[0] = Vector3.TransformCoordinate(this.GetPositionFromData(indexData.Read()), worldMatrix); triangle[1] = Vector3.TransformCoordinate(this.GetPositionFromData(indexData.Read()), worldMatrix); triangle[2] = Vector3.TransformCoordinate(this.GetPositionFromData(indexData.Read()), worldMatrix); float newDistance; if (!Ray.Intersects(pickRay, triangle[0], triangle[1], triangle[2], out newDistance) || newDistance > distance) continue; distance = newDistance; } return distance != float.MaxValue; } private Vector3 GetPositionFromData(uint index) { vertexData.Position = index * vertexElementSize + strideToPosition; return vertexData.Read(); } protected void Precalculate() { boxMinVector = Vector3.Zero; boxMaxVector = Vector3.Zero; for (uint i = 0; i < vertexCount; ++i) { boxMinVector = i == 0 ? this.GetPositionFromData(i) : Vector3.Maximize(boxMinVector, this.GetPositionFromData(i)); boxMaxVector = i == 0 ? this.GetPositionFromData(i) : Vector3.Minimize(boxMaxVector, this.GetPositionFromData(i)); } } public BoundingSphere CalcBoundingSphere(Matrix worldMatrix) { var centerPosition = Vector3.TransformCoordinate(Vector3.Zero, worldMatrix); var maxVec = Vector3.TransformCoordinate(boxMaxVector, worldMatrix); return new BoundingSphere(centerPosition, maxVec.Length()); } public BoundingBox CalcBoundingBox(Matrix worldMatrix) { var minVec = Vector3.TransformCoordinate(boxMinVector, worldMatrix); var maxVec = Vector3.TransformCoordinate(boxMaxVector, worldMatrix); return new BoundingBox(minVec, maxVec); } } }