Files
glitchy-engine-beef/GlitchyEngine/src/Application.bf
T

262 lines
5.3 KiB
Beef

using System;
using GlitchyEngine.Events;
using GlitchyEngine.ImGui;
using GlitchyEngine.Renderer;
using GlitchyEngine.Debug;
using GlitchyEngine.Content;
using GlitchyEngine.Scripting;
using System.Collections;
using System.Threading;
namespace GlitchyEngine
{
public abstract class Application
{
static Application s_Instance = null;
private Window _window;
private RendererAPI _rendererApi;
private bool _running = true;
private bool _isMinimized = false;
private append LayerStack _layerStack = .();
#if IMGUI
private ImGuiLayer _imGuiLayer;
#endif
private append GameTime _gameTime = .();
private IContentManager _contentManager;
private append List<delegate bool()> _jobQueue = .() ~ ClearAndDeleteItems!(_);
private append Monitor _jobQueueMutex = .();
public bool IsRunning => _running;
public Window Window => _window;
public IContentManager ContentManager => _contentManager;
public bool IsMinimized => _isMinimized;
public GameTime GameTime => _gameTime;
[Inline, Obsolete("Use Application.Instance instead.", false), NoShow]
public static Application Get() => s_Instance;
public static Application Instance => s_Instance;
public Settings Settings {get; private set;} = new .() ~ delete _;
public this()
{
Profiler.ProfileFunction!();
Log.EngineLogger.Assert(s_Instance == null, "Tried to create a second application.");
s_Instance = this;
_contentManager = InitContentManager();
WindowDescription windowDesc = .Default;
windowDesc.Icon = "Resources/Textures/GlitchyEngineIcon.ico";
_window = new Window(windowDesc);
_window.EventCallback = new => OnEvent;
Input.Init();
// TODO: RenderAPI in RenderCommand initialisieren?
_rendererApi = new RendererAPI();
_rendererApi.Context = _window.Context;
SamplerStateManager.Init();
// TODO: Rendercommmand in Renderer initialisieren?
RenderCommand.RendererAPI = _rendererApi;
Renderer.Init();
ScriptEngine.Init();
#if IMGUI
_imGuiLayer = new ImGuiLayer();
PushOverlay(_imGuiLayer);
#endif
GlitchyEngine.Settings.Load();
Settings.Apply();
}
/// Initializes the content manager.
protected abstract IContentManager InitContentManager();
//{
// TODO: init default content manager?
//_contentManager = new ContentManager("./content");
//}
public ~this()
{
Profiler.ProfileFunction!();
_layerStack.ClearLayers();
SamplerStateManager.Uninit();
Renderer.Deinit();
delete _contentManager;
// TODO: Was there a reason, that layerstack gets deleted before _rendererApi and _window but was created before it?
//delete _layerStack;
delete _rendererApi;
delete _window;
ScriptEngine.Shutdown();
}
public void OnEvent(Event e)
{
Debug.Profiler.ProfileFunction!();
if(!_running)
return;
EventDispatcher dispatcher = EventDispatcher(e);
dispatcher.Dispatch<WindowCloseEvent>(scope => OnWindowClose);
dispatcher.Dispatch<WindowResizeEvent>(scope => OnWindowResize);
for(Layer layer in _layerStack)
{
layer.OnEvent(e);
if(e.Handled)
break;
}
}
#if GE_APP_SINGLESTEP
bool allowFrame = false;
bool disableSingleFrame = false;
#else
const bool allowFrame = true;
#endif
public void Run()
{
Debug.Profiler.ProfileFunction!();
while(_running)
{
Debug.Profiler.ProfileScope!("Loop");
if(allowFrame)
{
_gameTime.NewFrame();
}
Input.NewFrame();
#if GE_APP_SINGLESTEP
allowFrame = disableSingleFrame || Input.IsKeyPressing(Key.F10);
if(Input.IsKeyPressing(Key.F11))
{
disableSingleFrame = !disableSingleFrame;
}
#endif
RunJobs();
if(allowFrame && !_isMinimized)
{
Debug.Profiler.ProfileScope!("Update Layers");
for(Layer layer in _layerStack)
layer.Update(_gameTime);
}
_window.Update();
if(allowFrame)
{
#if IMGUI
_imGuiLayer.ImGuiRender();
#endif
_window.Context.SwapChain.Present();
}
}
}
/// Closes the applcation.
public void Close()
{
_running = false;
}
public void PushLayer(Layer ownLayer)
{
Profiler.ProfileFunction!();
_layerStack.PushLayer(ownLayer);
ownLayer.OnAttach();
}
public void PushOverlay(Layer ownOverlay)
{
Profiler.ProfileFunction!();
_layerStack.PushOverlay(ownOverlay);
ownOverlay.OnAttach();
}
public bool OnWindowClose(WindowCloseEvent e)
{
_running = false;
return true;
}
public bool OnWindowResize(WindowResizeEvent e)
{
if(e.Width == 0 || e.Height == 0)
{
_isMinimized = true;
return false;
}
_isMinimized = false;
return false;
}
/// Executes the given Job on the main thread. Takes ownership of the delegate.
public void InvokeOnMainThread(delegate bool() ownJob)
{
using (_jobQueueMutex.Enter())
{
_jobQueue.Add(ownJob);
}
}
private void RunJobs()
{
Debug.Profiler.ProfileFunction!();
using (_jobQueueMutex.Enter())
{
for (let job in _jobQueue)
{
if (job())
{
@job.RemoveFast();
delete job;
}
}
//ClearAndDeleteItems!(_jobQueue);
}
}
}
}