102 lines
3.1 KiB
C#
102 lines
3.1 KiB
C#
using Engine.Graphics.Shader;
|
|
using Engine.Graphics.Texture;
|
|
using OpenTK.Graphics.OpenGL;
|
|
using OpenTK.Mathematics;
|
|
|
|
namespace Engine.Graphics.Render.Mesh;
|
|
|
|
/// <summary>
|
|
/// A renderer class for rendering meshes using instancing.
|
|
/// Handles the instancing process for meshes, including texture binding and model transformations.
|
|
/// </summary>
|
|
public class MeshRenderer : InstancedRenderer<Asset.Mesh.Mesh.Vertex, MeshInstanceVertex>
|
|
{
|
|
/// <summary>
|
|
/// Maps textures to texture units with a limit of 16 texture units.
|
|
/// </summary>
|
|
private readonly TextureUnitMap _textureUnitMap = new(16);
|
|
|
|
/// <summary>
|
|
/// Stores the texture unit indices used for binding textures.
|
|
/// </summary>
|
|
private readonly int[] _textureUnitIndices = new int[16];
|
|
|
|
/// <summary>
|
|
/// Stores the hash of the current frame, used for detecting changes in instance data.
|
|
/// </summary>
|
|
private int _frameHash;
|
|
|
|
/// <summary>
|
|
/// Stores the hash of the previous frame.
|
|
/// </summary>
|
|
private int _previousHash;
|
|
|
|
/// <summary>
|
|
/// Initializes a new instance of the <see cref="MeshRenderer"/> class.
|
|
/// </summary>
|
|
/// <param name="parMesh">The mesh to render.</param>
|
|
/// <param name="parInstanceCount">The number of instances to render.</param>
|
|
/// <param name="parProgram">The shader program to use for rendering the mesh.</param>
|
|
public MeshRenderer(Asset.Mesh.Mesh parMesh, int parInstanceCount, Program parProgram)
|
|
: base(
|
|
PrimitiveType.Triangles, parInstanceCount,
|
|
parMesh.Indices.ToArray(),
|
|
parMesh.Vertices.ToArray(),
|
|
parProgram
|
|
)
|
|
{
|
|
}
|
|
|
|
/// <summary>
|
|
/// Commits an instance to the renderer, adding it to the queue with the specified model matrix and optional texture.
|
|
/// </summary>
|
|
/// <param name="parModelMatrix">The model transformation matrix for this instance.</param>
|
|
/// <param name="parTexture">An optional texture to apply to the mesh. If null, no texture is applied.</param>
|
|
public void Commit(Matrix4 parModelMatrix, Texture.Texture? parTexture = null)
|
|
{
|
|
if (_queuedInstanceCount >= _instanceCount)
|
|
{
|
|
throw new InvalidOperationException("Instance count exceeded");
|
|
}
|
|
|
|
var textureId = -1;
|
|
if (parTexture != null)
|
|
{
|
|
textureId = _textureUnitMap.GetUnit(parTexture);
|
|
}
|
|
|
|
_instanceVertices[_queuedInstanceCount]._textureId = textureId;
|
|
_instanceVertices[_queuedInstanceCount]._modelMatrix = parModelMatrix;
|
|
|
|
_frameHash = HashCode.Combine(_frameHash, _instanceVertices[_queuedInstanceCount]);
|
|
|
|
_queuedInstanceCount++;
|
|
}
|
|
|
|
/// <inheritdoc/>
|
|
public override void Reset()
|
|
{
|
|
base.Reset();
|
|
_textureUnitMap.Reset();
|
|
_previousHash = _frameHash;
|
|
_frameHash = 0;
|
|
}
|
|
|
|
/// <inheritdoc/>
|
|
protected override void SetAdditionalUniforms(Program parProgram)
|
|
{
|
|
foreach (var (texture, unit) in _textureUnitMap.Textures)
|
|
{
|
|
texture.BindUnit(unit);
|
|
_textureUnitIndices[unit] = unit;
|
|
}
|
|
|
|
parProgram.SetUniform("uTexture", _textureUnitIndices);
|
|
}
|
|
|
|
/// <inheritdoc/>
|
|
protected override bool DataChanged()
|
|
{
|
|
return _frameHash != _previousHash;
|
|
}
|
|
} |