using Engine.Graphics.Shader; using Engine.Graphics.Texture; using OpenTK.Graphics.OpenGL; using OpenTK.Mathematics; namespace Engine.Graphics.Render.Quad; public class QuadRenderer : InstancedRenderer { private readonly TextureUnitMap _textureUnitMap = new(16); private readonly int[] _textureUnitIndices = new int[16]; private int _frameHash; private int _previousHash; public QuadRenderer(Engine parEngine, int parInstanceCount) : base(PrimitiveType.Triangles, parInstanceCount, [0, 2, 1, 2, 3, 1], [ new QuadCommonVertex { _position = new Vector3(-0.5f, -0.5f, 0), _uv = new Vector2(0, 0) }, new QuadCommonVertex { _position = new Vector3(-0.5f, 0.5f, 0), _uv = new Vector2(0, 1) }, new QuadCommonVertex { _position = new Vector3(0.5f, -0.5f, 0), _uv = new Vector2(1, 0) }, new QuadCommonVertex { _position = new Vector3(0.5f, 0.5f, 0), _uv = new Vector2(1, 1) }, ], parEngine.EngineResourceManager.Load("shader/quad")) { } public void Commit(in Matrix4 parModelMatrix, in Vector4 parColor, 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]._modelMatrix = parModelMatrix; _instanceVertices[_queuedInstanceCount]._color = parColor; _instanceVertices[_queuedInstanceCount]._textureId = textureId; _frameHash = HashCode.Combine(_frameHash, _instanceVertices[_queuedInstanceCount]); _queuedInstanceCount++; } protected override void SetAdditionalUniforms(Program parProgram) { foreach (var (texture, unit) in _textureUnitMap.Textures) { texture.BindUnit(unit); _textureUnitIndices[unit] = unit; } parProgram.SetUniform("uTexture", _textureUnitIndices); } protected override bool DataChanged() { return _frameHash != _previousHash; } public override void Reset() { base.Reset(); _textureUnitMap.Reset(); _previousHash = _frameHash; _frameHash = 0; } }