#region usings using System; using System.Drawing; using System.Linq; using OpenTK; using OpenTK.Graphics; using OpenTK.Graphics.OpenGL4; using OpenTK.Input; using SM.Base.Contexts; using SM.Base.Objects.Static; using SM.Base.PostProcess; using SM.Base.Scene; using SM.Base.ShaderExtension; using SM.Base.Time; using SM.OGL; using SM.OGL.Framebuffer; using SM.Utility; #endregion namespace SM.Base { /// /// The base window. /// public abstract class GenericWindow : GameWindow { private bool _loading; /// /// This tells you the current world scale. /// protected Vector2 _worldScale = Vector2.Zero; /// /// This tells you the current aspect ratio of this window. /// public float Aspect { get; private set; } public bool ReactWhileUnfocused = false; /// protected GenericWindow() : this(1280, 720, "Generic OGL Title", GameWindowFlags.Default) { } protected GenericWindow(int width, int height, string title, GameWindowFlags flags, bool vSync = true) : base(width, height, GraphicsMode.Default, title, flags, DisplayDevice.Default, GLSettings.ForcedVersion.MajorVersion, GLSettings.ForcedVersion.MinorVersion, GraphicsContextFlags.Default) { VSync = vSync ? VSyncMode.On : VSyncMode.Off; } /// protected override void OnLoad(EventArgs e) { GLSystem.INIT_SYSTEM(); GLSettings.ShaderPreProcessing = true; var args = Environment.GetCommandLineArgs(); if (args.Contains("--advDebugging")) { SMRenderer.AdvancedDebugging = true; GLSettings.InfoEveryUniform = true; } Log.Init(); Log.Write("#", ConsoleColor.Cyan, "----------------------", "--- OpenGL Loading ---", "----------------------------------", $"--- {"DeviceVersion",14}: {GLSystem.DeviceVersion,-10} ---", $"--- {"ForcedVersion",14}: {GLSettings.ForcedVersion,-10} ---", $"--- {"ShadingVersion",14}: {GLSystem.ShadingVersion,-10} ---", $"--- {"Debugging",14}: {GLSystem.Debugging,-10} ---", $"--- {"AdvDebugging",14}: {SMRenderer.AdvancedDebugging,-10} ---", "----------------------------------"); if (SMRenderer.AdvancedDebugging) Log.Write("Extension", ConsoleColor.DarkCyan, GLSystem.Extensions); ExtensionManager.InitExtensions(); base.OnLoad(e); _loading = true; } /// protected override void OnResize(EventArgs e) { base.OnResize(e); Aspect = (float) Width / Height; _worldScale = new Vector2(Width, Height); SetWorldScale(); GL.Viewport(ClientRectangle); if (_loading) { _loading = false; OnLoaded(); } } /// /// This is triggered after all the window-loading has been done. /// protected virtual void OnLoaded() { } /// /// Sets the world scale. /// protected virtual void SetWorldScale() { } /// protected override void OnUpdateFrame(FrameEventArgs e) { if (!ReactWhileUnfocused && !Focused) return; base.OnUpdateFrame(e); Deltatime.UpdateDelta = (float) e.Time; var context = new UpdateContext { KeyboardState = Keyboard.GetState(), MouseState = Mouse.GetState() }; Update(e, ref context); } /// /// Updates the system. /// /// /// protected virtual void Update(FrameEventArgs e, ref UpdateContext context) { Stopwatch.PerformTicks(context); } /// /// Grabs the cursor and make sure it doesn't leave the window. /// /// If true, it makes the cursor invisible. public void GrabCursor(bool makeItInvisible = true) { CursorGrabbed = true; CursorVisible = !makeItInvisible; } /// /// Ungrabs the cursor. /// public void UngrabCursor() { CursorGrabbed = false; if (!CursorVisible) CursorVisible = true; } public Bitmap TakeScreenshot(Framebuffer framebuffer, ReadBufferMode readBuffer, int x, int y, int width, int height) { GL.GetInteger(GetPName.FramebufferBinding, out int prevFBId); GL.GetInteger(GetPName.DrawFramebufferBinding, out int prevFBDrawId); GL.GetInteger(GetPName.ReadFramebufferBinding, out int prevFBReadId); Bitmap b = new Bitmap(width, height); System.Drawing.Imaging.BitmapData bits = b.LockBits(new Rectangle(0, 0, width, height), System.Drawing.Imaging.ImageLockMode.WriteOnly, System.Drawing.Imaging.PixelFormat.Format32bppArgb); GL.BindFramebuffer(FramebufferTarget.ReadFramebuffer, framebuffer); GL.ReadBuffer(readBuffer); GL.ReadPixels(x, y, width, height, OpenTK.Graphics.OpenGL4.PixelFormat.Bgra, PixelType.UnsignedByte, bits.Scan0); b.UnlockBits(bits); b.RotateFlip(RotateFlipType.RotateNoneFlipY); GL.BindFramebuffer(FramebufferTarget.Framebuffer, prevFBId); GL.BindFramebuffer(FramebufferTarget.DrawFramebuffer, prevFBDrawId); GL.BindFramebuffer(FramebufferTarget.ReadFramebuffer, prevFBReadId); return b; } } /// /// The base window. /// /// The scene type /// The camera type public abstract class GenericWindow : GenericWindow where TScene : GenericScene, new() where TCamera : GenericCamera, new() { /// protected GenericWindow() { ViewportCamera = new TCamera(); } /// /// The viewport camera. /// public TCamera ViewportCamera { get; } /// /// This forces the render to use the viewport camera. /// public bool ForceViewportCamera { get; set; } = false; /// /// The current scene. /// public TScene CurrentScene { get; private set; } /// /// Controls how a scene is rendered. /// public RenderPipeline RenderPipeline { get; private set; } /// protected override void Update(FrameEventArgs e, ref UpdateContext context) { base.Update(e, ref context); CurrentScene?.Update(context); } /// protected override void OnRenderFrame(FrameEventArgs e) { if (!ReactWhileUnfocused && !Focused) return; SMRenderer.CurrentFrame++; Deltatime.RenderDelta = (float) e.Time; var drawContext = new DrawContext { World = ViewportCamera.World, View = ViewportCamera.CalculateViewMatrix(), ModelMaster = Matrix4.Identity, Instances = new[] { new Instance {ModelMatrix = Matrix4.Identity, TexturePosition = Vector2.Zero, TextureScale = Vector2.One} }, Mesh = Plate.Object, ForceViewport = ForceViewportCamera, WorldScale = _worldScale }; base.OnRenderFrame(e); RenderPipeline.Render(ref drawContext, CurrentScene); SwapBuffers(); GLDebugging.CheckGLErrors(); } /// protected override void OnResize(EventArgs e) { base.OnResize(e); ViewportCamera.RecalculateWorld(_worldScale, Aspect); RenderPipeline.Resize(); PostProcessEffect.Mvp = Matrix4.CreateScale(_worldScale.X, -_worldScale.Y, 1) * Matrix4.LookAt(0, 0, 1, 0, 0, 0, 0, 1, 0) * GenericCamera.OrthographicWorld; } /// /// Sets the scene. /// /// public virtual void SetScene(TScene scene) { CurrentScene = scene; scene.Activate(); } /// /// Defines the render pipeline. /// /// public void SetRenderPipeline(RenderPipeline pipeline) { RenderPipeline = pipeline; pipeline.Activate(this); } } }