using System.Drawing; using System.Numerics; using ProjectUnknown.Engine.Components; using ProjectUnknown.Engine.Physics.Components; using ProjectUnknown.Engine.Rendering; using ProjectUnknown.Engine.Resources; using Serilog; using Silk.NET.OpenGL; using Shader = ProjectUnknown.Engine.Resources.Shader; using static ProjectUnknown.Engine.MathHelper; namespace ProjectUnknown.Engine.Physics.Systems; public class PhysicsDebugRenderSystem : ISystem, IDisposable { private readonly IEntityManager _entityManager; private readonly IEntityQuery _aabbQuery; private readonly IEntityQuery _rectangleColliders; private readonly IEntityQuery _cameraQuery; private readonly IResourceManager _resources; private readonly GL _gl; private readonly BufferObject _vbo; private readonly BufferObject _ebo; private readonly VertexArrayObject _vao; private readonly int _uViewLocation; private readonly int _uProjectionLocation; private readonly int _uModelLocation; private readonly int _uColorLocation; private readonly Shader _shader; private const float Min = -.5f; private const float Max = .5f; private static readonly float[] Vertices = { //X Y Min, Min, Max, Min, Min, Max, Max, Max }; //Index data, uploaded to the EBO. private static readonly uint[] Indices = { 0, 2, 1 }; public PhysicsDebugRenderSystem(IEntityManager entityManager, GL gl, IResourceManager resources) { _entityManager = entityManager; _gl = gl; _resources = resources; _aabbQuery = _entityManager.CreateQuery(_entityManager.HasComponent); _rectangleColliders = _entityManager.CreateQuery(_entityManager.HasComponent); _cameraQuery = _entityManager.CreateQuery(_entityManager.HasComponent); _ebo = new (_gl, Indices, BufferTargetARB.ElementArrayBuffer); _vbo = new (_gl, Vertices, BufferTargetARB.ArrayBuffer); _vao = new (_gl, _vbo, _ebo); _vao.VertexAttributePointer(0, 2, VertexAttribPointerType.Float, 0, 0); _shader = _resources.Load("ProjectUnknown.Engine.Resources.BuiltIn.Debug", "debug"); _uViewLocation = GetLocation("uView"); _uProjectionLocation = GetLocation("uProjection"); _uModelLocation = GetLocation("uModel"); _uColorLocation = GetLocation("uColor"); } private int GetLocation(string name) { var location = _gl.GetUniformLocation(_shader.Handle, name); if (location == -1) { throw new($"{name} uniform not found on shader."); } return location; } public unsafe void Execute(float deltaTime) { _gl.UseProgram(_shader.Handle); _vao.Bind(); _gl.Uniform4(_uColorLocation, Vector4.One); _cameraQuery.ForEach(cam => { var camMatrix = _entityManager.GetComponent(cam); _aabbQuery.ForEach(entity => { var aabb = _entityManager.GetComponent(entity); var position = new Vector2((aabb.Min.X + aabb.Max.X) / 2, (aabb.Min.Y + aabb.Max.Y) / 2); var size = new Vector2(aabb.Max.X - aabb.Min.X, aabb.Max.Y - aabb.Min.Y); RenderRectangle(position, size); }); _gl.Uniform4(_uColorLocation, new Vector4(0, 1.0f, 0, 1)); _rectangleColliders.ForEach(entity => { var (offset, size) = _entityManager.GetComponent(entity); var position = _entityManager.HasComponent(entity) ? (Vector2)_entityManager.GetComponent(entity) : Vector2.Zero; var rotation = _entityManager.HasComponent(entity) ? _entityManager.GetComponent(entity) : 0; var targetPosition = position + RotateVector(Vector2.UnitX, rotation) * offset; RenderRectangle(targetPosition, size, rotation); }); void RenderRectangle(Vector2 position, Vector2 size, float rotation = 0) { SetMatrix(_uViewLocation, camMatrix.View); SetMatrix(_uProjectionLocation, camMatrix.Projection); var model = Matrix4x4.Identity * Matrix4x4.CreateScale(size.X, size.Y, 1) * Matrix4x4.CreateRotationZ(DegreesToRadians(rotation)) * Matrix4x4.CreateTranslation(position.X, position.Y, 0); SetMatrix(_uModelLocation, model); _gl.DrawElements(PrimitiveType.LineLoop, (uint) Indices.Length, DrawElementsType.UnsignedInt, null); void SetMatrix(int location, Matrix4x4 value) => _gl.UniformMatrix4(location, 1, false, (float*)&value); } }); } public void Dispose() { _resources.Unload("debug"); } }