|
|
@ -15,7 +15,10 @@ using static gaemstone.Components.TransformComponents; |
|
|
|
namespace gaemstone.Client.Systems; |
|
|
|
namespace gaemstone.Client.Systems; |
|
|
|
|
|
|
|
|
|
|
|
[Module] |
|
|
|
[Module] |
|
|
|
[DependsOn(typeof(Windowing))] |
|
|
|
[DependsOn(typeof(gaemstone.Components.TransformComponents))] |
|
|
|
|
|
|
|
[DependsOn(typeof(gaemstone.Client.Components.CameraComponents))] |
|
|
|
|
|
|
|
[DependsOn(typeof(gaemstone.Client.Components.RenderingComponents))] |
|
|
|
|
|
|
|
[DependsOn(typeof(gaemstone.Client.Systems.Windowing))] |
|
|
|
public class Renderer |
|
|
|
public class Renderer |
|
|
|
: IModuleInitializer |
|
|
|
: IModuleInitializer |
|
|
|
{ |
|
|
|
{ |
|
|
@ -51,77 +54,81 @@ public class Renderer |
|
|
|
_modelMatrixUniform = GL.GetUniformLocation(_program, "modelMatrix"); |
|
|
|
_modelMatrixUniform = GL.GetUniformLocation(_program, "modelMatrix"); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
[System(typeof(SystemPhase.OnStore))] |
|
|
|
[System(typeof(SystemPhase.PreStore))] |
|
|
|
public void Render(Universe universe, GameWindow window, Canvas canvas) |
|
|
|
public void Clear(Canvas canvas) |
|
|
|
{ |
|
|
|
{ |
|
|
|
var GL = canvas.GL; |
|
|
|
var GL = canvas.GL; |
|
|
|
GL.UseProgram(_program); |
|
|
|
GL.UseProgram(_program); |
|
|
|
GL.Viewport(default, canvas.Size); |
|
|
|
GL.Viewport(default, canvas.Size); |
|
|
|
GL.ClearColor(new Vector4D<float>(0, 0, 0, 255)); |
|
|
|
GL.ClearColor(new Vector4D<float>(0, 0, 0, 255)); |
|
|
|
GL.Clear(ClearBufferMask.ColorBufferBit | ClearBufferMask.DepthBufferBit); |
|
|
|
GL.Clear(ClearBufferMask.ColorBufferBit | ClearBufferMask.DepthBufferBit); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
Filter.RunOnce(universe, (in GlobalTransform cameraTransform, |
|
|
|
[System(typeof(SystemPhase.OnStore))] |
|
|
|
in Camera camera, CameraViewport? viewport) => { |
|
|
|
public void Render(Universe universe, [Game] Canvas canvas, |
|
|
|
var color = viewport?.ClearColor ?? new(0x4B, 0x00, 0x82, 255); |
|
|
|
in GlobalTransform cameraTransform, in Camera camera, CameraViewport? viewport) |
|
|
|
var bounds = viewport?.Viewport ?? new(default, canvas.Size); |
|
|
|
{ |
|
|
|
|
|
|
|
var color = viewport?.ClearColor ?? new(0x4B, 0x00, 0x82, 255); |
|
|
|
GL.Enable(EnableCap.ScissorTest); |
|
|
|
var bounds = viewport?.Viewport ?? new(default, canvas.Size); |
|
|
|
GL.Viewport(bounds); GL.Scissor(bounds.Origin.X, bounds.Origin.Y, (uint)bounds.Size.X, (uint)bounds.Size.Y); |
|
|
|
|
|
|
|
GL.ClearColor(color); GL.Clear(ClearBufferMask.ColorBufferBit | ClearBufferMask.DepthBufferBit); |
|
|
|
|
|
|
|
GL.Disable(EnableCap.ScissorTest); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Get the camera's transform matrix and invert it. |
|
|
|
|
|
|
|
Matrix4X4.Invert<float>(cameraTransform, out var invertedTransform); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Create the camera's projection matrix. |
|
|
|
|
|
|
|
var cameraProjection = camera.IsOrthographic |
|
|
|
|
|
|
|
? Matrix4X4.CreateOrthographic( |
|
|
|
|
|
|
|
bounds.Size.X, -bounds.Size.Y, |
|
|
|
|
|
|
|
camera.NearPlane, camera.FarPlane) |
|
|
|
|
|
|
|
: Matrix4X4.CreatePerspectiveFieldOfView( |
|
|
|
|
|
|
|
camera.FieldOfView * MathF.PI / 180, // Degrees => Radians |
|
|
|
|
|
|
|
(float)bounds.Size.X / bounds.Size.Y, // Aspect Ratio |
|
|
|
|
|
|
|
camera.NearPlane, camera.FarPlane); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Set the uniform to the combined transform and projection. |
|
|
|
|
|
|
|
var cameraMatrix = invertedTransform * cameraProjection; |
|
|
|
|
|
|
|
GL.UniformMatrix4(_cameraMatrixUniform, 1, false, in cameraMatrix.Row1.X); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
_renderEntityRule ??= new(universe, new(@"
|
|
|
|
|
|
|
|
GlobalTransform, |
|
|
|
|
|
|
|
(Mesh, $mesh), MeshHandle($mesh), |
|
|
|
|
|
|
|
?(Texture, $tex), ?TextureHandle($tex) |
|
|
|
|
|
|
|
"));
|
|
|
|
|
|
|
|
foreach (var iter in _renderEntityRule) { |
|
|
|
|
|
|
|
var transforms = iter.Field<GlobalTransform>(1); |
|
|
|
|
|
|
|
var meshes = iter.Field<MeshHandle>(3); |
|
|
|
|
|
|
|
// var texPairs = iter.MaybeField<Identifier>(4); |
|
|
|
|
|
|
|
var textures = iter.MaybeField<TextureHandle>(5); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
for (var i = 0; i < iter.Count; i++) { |
|
|
|
|
|
|
|
var rTransform = transforms[i]; |
|
|
|
|
|
|
|
var mesh = meshes[i]; |
|
|
|
|
|
|
|
// var hasTexture = (texPairs.Length > 0); |
|
|
|
|
|
|
|
var texture = textures.MaybeGet(i); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// If entity has Texture, bind it now. |
|
|
|
|
|
|
|
if (texture.HasValue) GL.BindTexture(texture.Value.Target, texture.Value.Handle); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Draw the mesh. |
|
|
|
|
|
|
|
GL.UniformMatrix4(_modelMatrixUniform, 1, false, in rTransform.Value.Row1.X); |
|
|
|
|
|
|
|
GL.BindVertexArray(mesh.Handle); |
|
|
|
|
|
|
|
if (!mesh.IsIndexed) GL.DrawArrays(PrimitiveType.Triangles, 0, (uint)mesh.Count); |
|
|
|
|
|
|
|
else unsafe { GL.DrawElements(PrimitiveType.Triangles, (uint)mesh.Count, DrawElementsType.UnsignedShort, null); } |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// If entity has Texture, unbind it after it has been rendered. |
|
|
|
|
|
|
|
if (texture.HasValue) GL.BindTexture(texture.Value.Target, 0); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
}); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
window.Handle.SwapBuffers(); |
|
|
|
var GL = canvas.GL; |
|
|
|
|
|
|
|
GL.Enable(EnableCap.ScissorTest); |
|
|
|
|
|
|
|
GL.Viewport(bounds); GL.Scissor(bounds.Origin.X, bounds.Origin.Y, (uint)bounds.Size.X, (uint)bounds.Size.Y); |
|
|
|
|
|
|
|
GL.ClearColor(color); GL.Clear(ClearBufferMask.ColorBufferBit | ClearBufferMask.DepthBufferBit); |
|
|
|
|
|
|
|
GL.Disable(EnableCap.ScissorTest); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Create the camera's projection matrix. |
|
|
|
|
|
|
|
var cameraProjection = camera.IsOrthographic |
|
|
|
|
|
|
|
? Matrix4X4.CreateOrthographic( |
|
|
|
|
|
|
|
bounds.Size.X, -bounds.Size.Y, |
|
|
|
|
|
|
|
camera.NearPlane, camera.FarPlane) |
|
|
|
|
|
|
|
: Matrix4X4.CreatePerspectiveFieldOfView( |
|
|
|
|
|
|
|
camera.FieldOfView * MathF.PI / 180, // Degrees => Radians |
|
|
|
|
|
|
|
(float)bounds.Size.X / bounds.Size.Y, // Aspect Ratio |
|
|
|
|
|
|
|
camera.NearPlane, camera.FarPlane); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Get the camera's transform matrix and invert it. |
|
|
|
|
|
|
|
Matrix4X4.Invert<float>(cameraTransform, out var invertedTransform); |
|
|
|
|
|
|
|
// Set the uniform to the combined transform and projection. |
|
|
|
|
|
|
|
var cameraMatrix = invertedTransform * cameraProjection; |
|
|
|
|
|
|
|
GL.UniformMatrix4(_cameraMatrixUniform, 1, false, in cameraMatrix.Row1.X); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
_renderEntityRule ??= new(universe, new(@"
|
|
|
|
|
|
|
|
GlobalTransform, |
|
|
|
|
|
|
|
(Mesh, $mesh), MeshHandle($mesh), |
|
|
|
|
|
|
|
?(Texture, $tex), ?TextureHandle($tex) |
|
|
|
|
|
|
|
"));
|
|
|
|
|
|
|
|
foreach (var iter in _renderEntityRule) { |
|
|
|
|
|
|
|
var transforms = iter.Field<GlobalTransform>(1); |
|
|
|
|
|
|
|
var meshes = iter.Field<MeshHandle>(3); |
|
|
|
|
|
|
|
// var texPairs = iter.MaybeField<Identifier>(4); |
|
|
|
|
|
|
|
var textures = iter.MaybeField<TextureHandle>(5); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
for (var i = 0; i < iter.Count; i++) { |
|
|
|
|
|
|
|
var rTransform = transforms[i]; |
|
|
|
|
|
|
|
var mesh = meshes[i]; |
|
|
|
|
|
|
|
// var hasTexture = (texPairs.Length > 0); |
|
|
|
|
|
|
|
var texture = textures.MaybeGet(i); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// If entity has Texture, bind it now. |
|
|
|
|
|
|
|
if (texture.HasValue) GL.BindTexture(texture.Value.Target, texture.Value.Handle); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Draw the mesh. |
|
|
|
|
|
|
|
GL.UniformMatrix4(_modelMatrixUniform, 1, false, in rTransform.Value.Row1.X); |
|
|
|
|
|
|
|
GL.BindVertexArray(mesh.Handle); |
|
|
|
|
|
|
|
if (!mesh.IsIndexed) GL.DrawArrays(PrimitiveType.Triangles, 0, (uint)mesh.Count); |
|
|
|
|
|
|
|
else unsafe { GL.DrawElements(PrimitiveType.Triangles, (uint)mesh.Count, DrawElementsType.UnsignedShort, null); } |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// If entity has Texture, unbind it after it has been rendered. |
|
|
|
|
|
|
|
if (texture.HasValue) GL.BindTexture(texture.Value.Target, 0); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
[System(typeof(SystemPhase.PostFrame))] |
|
|
|
|
|
|
|
public static void SwapBuffers(GameWindow window) |
|
|
|
|
|
|
|
=> window.Handle.SwapBuffers(); |
|
|
|
|
|
|
|
|
|
|
|
[DebuggerStepThrough] |
|
|
|
[DebuggerStepThrough] |
|
|
|
private static void DebugCallback(GLEnum source, GLEnum _type, int id, GLEnum _severity, |
|
|
|
private static void DebugCallback(GLEnum source, GLEnum _type, int id, GLEnum _severity, |
|
|
|
int length, nint _message, nint userParam) |
|
|
|
int length, nint _message, nint userParam) |
|
|
|