#region usings using System; using System.Collections.Generic; 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.Drawing; 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, IGenericWindow { protected GenericCamera _viewportCamera; internal bool _loading = true; internal List _actionsAfterLoading = new List(); public bool Loading => _loading; /// /// This tells you the current world scale. /// public Vector2 WorldScale { get; set; } = Vector2.Zero; /// /// This tells you the current aspect ratio of this window. /// public float Aspect { get; set; } /// /// If false, the window will not react on updates and will not render something. /// /// Default: false /// /// public bool ReactWhileUnfocused = false; public GenericCamera ViewportCamera => _viewportCamera; public bool ForceViewportCamera { get; set; } /// protected GenericWindow() : this(1280, 720, "Generic OGL Title", GameWindowFlags.Default) { } /// /// Creates a window... /// 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) { GenericWindowCode.Load(this); base.OnLoad(e); } /// protected override void OnResize(EventArgs e) { base.OnResize(e); GenericWindowCode.Resize(this); if (_loading) { _loading = false; OnLoaded(); _actionsAfterLoading.ForEach(a => a()); _actionsAfterLoading = null; } } /// /// This is triggered after all the window-loading has been done. /// protected virtual void OnLoaded() { } /// /// Sets the world scale. /// public 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() }; if (context.KeyboardState[Key.AltLeft] && context.KeyboardState[Key.F4]) Close(); 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; } /// /// Create a bitmap from the framebuffer. /// 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, IGenericWindow where TScene : GenericScene, new() where TCamera : GenericCamera, new() { private RenderPipeline _renderPipeline; private TScene _scene; /// protected GenericWindow() { _viewportCamera = new TCamera(); } /// /// The viewport camera. /// public TCamera ViewportCamera { get => (TCamera)_viewportCamera; set => _viewportCamera = value; } /// /// This forces the render to use the viewport camera. /// public bool ForceViewportCamera { get; set; } = false; /// /// The current scene. /// public TScene CurrentScene => _scene; /// /// Controls how a scene is rendered. /// public RenderPipeline RenderPipeline => _renderPipeline; /// protected override void Update(FrameEventArgs e, ref UpdateContext context) { base.Update(e, ref context); context.CurrentScene = CurrentScene; CurrentScene?.Update(context); } /// protected override void OnRenderFrame(FrameEventArgs e) { if (!ReactWhileUnfocused && !Focused) return; base.OnRenderFrame(e); GenericWindowCode.Render(this, (float)e.Time); SwapBuffers(); GLDebugging.CheckGLErrors(); } /// protected override void OnResize(EventArgs e) { base.OnResize(e); GenericWindowCode.Resize(this); } /// /// Sets the scene. /// /// public virtual void SetScene(TScene scene) { if (_loading) { _actionsAfterLoading.Add(() => SetScene(scene)); return; } _scene = scene; scene.Activate(); RenderPipeline.SceneChanged(scene); } /// /// Defines the render pipeline. /// /// public void SetRenderPipeline(RenderPipeline pipeline) { if (_loading) { _actionsAfterLoading.Add(() => SetRenderPipeline(pipeline)); return; } _renderPipeline = pipeline; pipeline.Activate(this); } } }