Files
bluflame/aiwaz/Backup/Aiwaz.Resources/PickHull.cs
2026-04-18 22:31:51 +02:00

107 lines
3.8 KiB
C#

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<uint>()), worldMatrix);
triangle[1] = Vector3.TransformCoordinate(this.GetPositionFromData(indexData.Read<uint>()), worldMatrix);
triangle[2] = Vector3.TransformCoordinate(this.GetPositionFromData(indexData.Read<uint>()), 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<Vector3>();
}
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);
}
}
}