diff --git a/src/SlatedGameToolkit.Framework/Exceptions/SDLException.cs b/src/SlatedGameToolkit.Framework/Exceptions/SDLException.cs
index afe4ff4..cb7eb89 100644
--- a/src/SlatedGameToolkit.Framework/Exceptions/SDLException.cs
+++ b/src/SlatedGameToolkit.Framework/Exceptions/SDLException.cs
@@ -14,18 +14,21 @@ namespace SlatedGameToolkit.Framework.Exceptions
/// Creates an SDL exception.
///
/// Whether or not to fetch the last error message that occurred in SDL.
- public SDLException(bool autoFlush = true) : base() {
+ public SDLException(bool autoFlush = true) : base(autoFlush ? SDL.SDL_GetError() : "SDL error has occurred.") {
if (autoFlush) {
SDLMessage = SDL.SDL_GetError();
SDL.SDL_ClearError();
}
}
- public SDLException(string message, Exception inner) : base(message, inner) {
-
+ public SDLException(string message, bool autoFlush = true) : base(message + " (" + (autoFlush ? SDL.SDL_GetError() : "SDL error has occurred.") + ")") {
+ if (autoFlush) {
+ SDLMessage = SDL.SDL_GetError();
+ SDL.SDL_ClearError();
+ }
}
- public SDLException(string message, bool autoFlush = true) : base(message) {
+ public SDLException(string message, Exception inner, bool autoFlush = true) : base(message + " (" + (autoFlush ? SDL.SDL_GetError() : "SDL error has occurred.") + ")", inner) {
if (autoFlush) {
SDLMessage = SDL.SDL_GetError();
SDL.SDL_ClearError();
diff --git a/src/SlatedGameToolkit.Framework/GameEngine.cs b/src/SlatedGameToolkit.Framework/GameEngine.cs
index a7c564d..7fbe809 100644
--- a/src/SlatedGameToolkit.Framework/GameEngine.cs
+++ b/src/SlatedGameToolkit.Framework/GameEngine.cs
@@ -17,47 +17,69 @@ namespace SlatedGameToolkit.Framework {
CreateLogger();
private static readonly object ignitionLock = new object();
private static Thread thread;
- private static volatile bool exit = false, loopCompleted = true;
- private static long updateDeltaTime = 50, frameDeltaTime = 0;
+ private static volatile bool exit = false, stopped = true;
+ private static volatile bool deltaChanged = true;
+ private static long updateDeltaTime = 25, frameDeltaTime = 16;
///
/// The amount of updates per second.
/// Is floored to milleseconds.
+ /// Maximum updates per second is 200.
///
/// The updates per second.
public static double UpdatesPerSecond {
get {
- return TimeSpan.FromMilliseconds(1 / updateDeltaTime).TotalSeconds;
+ return 1 / TimeSpan.FromMilliseconds(updateDeltaTime).TotalSeconds;
}
set {
- Interlocked.Exchange(ref updateDeltaTime, (long) TimeSpan.FromSeconds(1 / value).TotalMilliseconds);
+ Interlocked.Exchange(ref updateDeltaTime, Math.Min(5, (long) TimeSpan.FromSeconds(1 / value).TotalMilliseconds));
+ deltaChanged = true;
}
}
///
/// The target frames per second. Will not go above this number, but may dip below this number.
- /// This value is floored to millesconds.
+ /// This value is floored to millesconds units.
+ /// Setting this to 0 renders as many frames as the system can handle.
+ /// Default is 60.
///
/// The target frames per second.
public static double targetFPS {
get {
- return TimeSpan.FromMilliseconds(1 / frameDeltaTime).TotalSeconds;
+ if (frameDeltaTime == 0) return 0;
+ return 1 / TimeSpan.FromMilliseconds(frameDeltaTime).TotalSeconds;
}
set {
+ if (value == 0) Interlocked.Exchange(ref frameDeltaTime, 0);
Interlocked.Exchange(ref frameDeltaTime, (long) TimeSpan.FromSeconds(1 / value).TotalMilliseconds);
+ deltaChanged = true;
+ }
+ }
+
+ public static bool Running {
+ get {
+ return !stopped;
}
}
private static void Loop(Object o) {
if (!(o is Manager)) throw new InternalFrameworkException(String.Format("Expected manager object for asynchronous loop. Got {0}", o));
Manager manager = (Manager) o;
+ manager.initialize();
long currentTime = DateTimeOffset.Now.ToUnixTimeMilliseconds();
long timePassedFromLastUpdate = 0;
long timePassedFromLastRender = 0;
- loopCompleted = false;
+ long updateDeltaTime = 0;
+ long frameDeltaTime = 0;
+ stopped = false;
+ logger.Information("Game engine initiated.");
while (!exit) {
- long updateDeltaTime = Interlocked.Read(ref GameEngine.updateDeltaTime);
- long frameDeltaTime = Interlocked.Read(ref GameEngine.frameDeltaTime);
+ if (deltaChanged) {
+ updateDeltaTime = Interlocked.Read(ref GameEngine.updateDeltaTime);
+ frameDeltaTime = Interlocked.Read(ref GameEngine.frameDeltaTime);
+ deltaChanged = false;
+ }
+
long frameStart = DateTimeOffset.Now.ToUnixTimeMilliseconds();
long difference = frameStart - currentTime;
currentTime = frameStart;
@@ -74,8 +96,10 @@ namespace SlatedGameToolkit.Framework {
timePassedFromLastRender = 0;
}
}
- loopCompleted = true;
+ manager.Dispose();
+ stopped = true;
SDL.SDL_Quit();
+ logger.Information("Game engine has stopped.");
}
///
@@ -96,28 +120,25 @@ namespace SlatedGameToolkit.Framework {
/// Requests to start the game engine.
///
/// True iff the engine is not already running.
- private static bool Ignite(Manager manager) {
+ public static bool Ignite(Manager manager) {
if (manager == null) throw new ArgumentNullException("manager");
SDL.SDL_version SDLVersion;
SDL.SDL_version SDLBuiltVersion;
SDL.SDL_GetVersion(out SDLVersion);
SDL.SDL_VERSION(out SDLBuiltVersion);
- logger.Information(String.Format("Attempting to initiate game engine with SDL version: {0}", SDLVersion.ToString()));
- if (SDL.SDL_VERSION_ATLEAST(SDLBuiltVersion.major, SDLBuiltVersion.minor, SDLBuiltVersion.patch)) {
- logger.Warning(String.Format("Engine was designed with SDL version {0}, currently running on {1}", SDLVersion.ToString(), SDLBuiltVersion.ToString()));
+ logger.Information(String.Format("Attempting to initiate game engine with SDL version: {0}.{1}.{2}", SDLVersion.major, SDLVersion.minor, SDLVersion.patch));
+ if (!SDL.SDL_VERSION_ATLEAST(SDLBuiltVersion.major, SDLBuiltVersion.minor, SDLBuiltVersion.patch)) {
+ logger.Warning(String.Format("Engine was designed with SDL version {0}.{1}.{2}, currently running on {3}.{4}.{5}", SDLBuiltVersion.major, SDLBuiltVersion.minor, SDLBuiltVersion.patch, SDLVersion.major, SDLVersion.minor, SDLVersion.patch));
if (SDLVersion.major < 2) {
logger.Error("This engine was designed to work with SDL2. The version you're currently running is severely outdated.");
throw new FrameworkUsageException("Outdated SDL binaries.");
}
}
lock (ignitionLock) {
- if (!loopCompleted) return false;
- loopCompleted = false;
-
- if (SDL.SDL_GL_SetAttribute(SDL.SDL_GLattr.SDL_GL_CONTEXT_MAJOR_VERSION, 3) < 0) throw new FrameworkSDLException();
- if (SDL.SDL_GL_SetAttribute(SDL.SDL_GLattr.SDL_GL_CONTEXT_MINOR_VERSION, 1) < 0) throw new FrameworkSDLException();
- if (SDL.SDL_GL_SetAttribute(SDL.SDL_GLattr.SDL_GL_CONTEXT_PROFILE_MASK, SDL.SDL_GLprofile.SDL_GL_CONTEXT_PROFILE_CORE) < 0) throw new FrameworkSDLException();
-
+ if (!stopped) {
+ logger.Warning("Engine is already running.");
+ return false;
+ }
exit = false;
if (SDL.SDL_Init(SDL.SDL_INIT_VIDEO) != 0) {
throw new FrameworkSDLException();
@@ -125,6 +146,11 @@ namespace SlatedGameToolkit.Framework {
if (SDL.SDL_Init(SDL.SDL_INIT_AUDIO) != 0) {
throw new FrameworkSDLException();
}
+
+ if (SDL.SDL_GL_SetAttribute(SDL.SDL_GLattr.SDL_GL_CONTEXT_MAJOR_VERSION, 3) < 0) throw new FrameworkSDLException();
+ if (SDL.SDL_GL_SetAttribute(SDL.SDL_GLattr.SDL_GL_CONTEXT_MINOR_VERSION, 1) < 0) throw new FrameworkSDLException();
+ if (SDL.SDL_GL_SetAttribute(SDL.SDL_GLattr.SDL_GL_CONTEXT_PROFILE_MASK, SDL.SDL_GLprofile.SDL_GL_CONTEXT_PROFILE_CORE) < 0) throw new FrameworkSDLException();
+
thread = new Thread(Loop);
thread.Start(manager);
return true;
diff --git a/src/SlatedGameToolkit.Framework/Graphics/Window/WindowHandle.cs b/src/SlatedGameToolkit.Framework/Graphics/Window/WindowHandle.cs
index 56ec6f1..eea8dfe 100644
--- a/src/SlatedGameToolkit.Framework/Graphics/Window/WindowHandle.cs
+++ b/src/SlatedGameToolkit.Framework/Graphics/Window/WindowHandle.cs
@@ -207,9 +207,13 @@ namespace SlatedGameToolkit.Framework.Graphics.Window
/// Makes this window the window that is currently being drawn to.
/// More specifically, it sets the OpenGL Context associated with this window to be the one
/// that is actively receiving all OpenGL calls.
+ ///
+ /// If the current context is already of this window, nothing happens.
///
public void DrawToWindow() {
- SDL.SDL_GL_MakeCurrent(window, glContext);
+ if (SDL.SDL_GL_GetCurrentContext() != glContext) {
+ SDL.SDL_GL_MakeCurrent(window, glContext);
+ }
}
///
diff --git a/src/SlatedGameToolkit.Framework/Input/InputMatrix.cs b/src/SlatedGameToolkit.Framework/Input/InputMatrix.cs
deleted file mode 100644
index 37c322f..0000000
--- a/src/SlatedGameToolkit.Framework/Input/InputMatrix.cs
+++ /dev/null
@@ -1,13 +0,0 @@
-using SDL2;
-
-namespace SlatedGameToolkit.Framework.Input
-{
- internal class InputMatrix {
- public void update() {
- SDL.SDL_Event inputEvent;
- while (SDL.SDL_PollEvent(out inputEvent) != 0) {
-
- }
- }
- }
-}
\ No newline at end of file
diff --git a/src/SlatedGameToolkit.Framework/StateSystem/Manager.cs b/src/SlatedGameToolkit.Framework/StateSystem/Manager.cs
index 29f38ff..0bcff20 100644
--- a/src/SlatedGameToolkit.Framework/StateSystem/Manager.cs
+++ b/src/SlatedGameToolkit.Framework/StateSystem/Manager.cs
@@ -26,6 +26,10 @@ namespace SlatedGameToolkit.Framework.StateSystem
if (!this.states.TryGetValue(initialState, out currentState)) throw new ArgumentException("The requested initial state name does not exist in the provided list of states.");
}
+ internal void initialize() {
+ thread = Thread.CurrentThread;
+ }
+
internal void update(double delta) {
if (nextState != null) {
if (currentState.Deactivate() & nextState.Activate()) {
diff --git a/src/SlatedGameToolkit.Tools/Commands/GraphicalPlaygroundCommand.cs b/src/SlatedGameToolkit.Tools/Commands/GraphicalPlaygroundCommand.cs
new file mode 100644
index 0000000..705f3a7
--- /dev/null
+++ b/src/SlatedGameToolkit.Tools/Commands/GraphicalPlaygroundCommand.cs
@@ -0,0 +1,60 @@
+using SlatedGameToolkit.Framework;
+using SlatedGameToolkit.Framework.StateSystem;
+using SlatedGameToolkit.Tools.System;
+using SlatedGameToolkit.Tools.System.Interaction;
+using SlatedGameToolkit.Tools.Utilities.GraphicalPlayground;
+
+namespace SlatedGameToolkit.Tools.Commands
+{
+ public class GraphicalPlaygroundCommand : IInvocable
+ {
+ private readonly string[] invokers = new string[] {"playground"};
+
+ public bool Execute(IInteractable interactable, string[] args)
+ {
+ if (args.Length != 1) return false;
+ if (args[0].Equals("start")) {
+ if (GameEngine.Running) {
+ interactable.Tell("Engine is already running!");
+ return true;
+ }
+ Manager manager = new Manager("main state", new MainState());
+ GameEngine.Ignite(manager);
+ return true;
+ } else if (args[0].Equals("stop")) {
+ if (!GameEngine.Running) {
+ interactable.Tell("Engine was never running!");
+ return true;
+ }
+ GameEngine.Stop();
+ return true;
+ } else if (args[0].Equals("status")) {
+ interactable.Tell("Running: " + GameEngine.Running);
+ interactable.Tell("Target FPS: " + GameEngine.targetFPS);
+ interactable.Tell("Target Update Rate: " + GameEngine.UpdatesPerSecond);
+ return true;
+ }
+ return false;
+ }
+
+ public string getDescription()
+ {
+ return "Starts and stops the graphical playground.";
+ }
+
+ public string[] GetInvokers()
+ {
+ return invokers;
+ }
+
+ public string getUsage(string arg)
+ {
+ return "Usage: \"playground [start | stop | status]\" the required argument being whether to start, stop or get the current status of the game engine.";
+ }
+
+ public void Dispose()
+ {
+ GameEngine.Stop();
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/SlatedGameToolkit.Tools/Commands/HelpCommand.cs b/src/SlatedGameToolkit.Tools/Commands/HelpCommand.cs
index fe25e82..f3a23f5 100644
--- a/src/SlatedGameToolkit.Tools/Commands/HelpCommand.cs
+++ b/src/SlatedGameToolkit.Tools/Commands/HelpCommand.cs
@@ -52,5 +52,10 @@ namespace SlatedGameToolkit.Tools.Commands
{
return invokers;
}
+
+ public void Dispose()
+ {
+
+ }
}
}
\ No newline at end of file
diff --git a/src/SlatedGameToolkit.Tools/Commands/StopCommand.cs b/src/SlatedGameToolkit.Tools/Commands/StopCommand.cs
index 02609d1..b189519 100644
--- a/src/SlatedGameToolkit.Tools/Commands/StopCommand.cs
+++ b/src/SlatedGameToolkit.Tools/Commands/StopCommand.cs
@@ -27,5 +27,9 @@ namespace SlatedGameToolkit.Tools.Commands
{
return invokers;
}
+
+ public void Dispose()
+ {
+ }
}
}
\ No newline at end of file
diff --git a/src/SlatedGameToolkit.Tools/Program.cs b/src/SlatedGameToolkit.Tools/Program.cs
index 03dcb02..acc9ac5 100644
--- a/src/SlatedGameToolkit.Tools/Program.cs
+++ b/src/SlatedGameToolkit.Tools/Program.cs
@@ -11,8 +11,10 @@ namespace SlatedGameToolkit.Tools
static private bool running;
static void Main(string[] args)
{
- CommandMap commands = new CommandMap(new StopCommand());
+ CommandMap commands = new CommandMap();
+ commands.Add(new StopCommand());
commands.Add(new HelpCommand(commands));
+ commands.Add(new GraphicalPlaygroundCommand());
CommandProcessor processor = new CommandProcessor("The command \"{input}\" was not understood. Please type \"help\" for more information.", commands);
AssemblyName name = Assembly.GetExecutingAssembly().GetName();
ConsoleInteraction consoleInteracter = new ConsoleInteraction("Tools");
@@ -24,6 +26,7 @@ namespace SlatedGameToolkit.Tools
processor.Process(consoleInteracter);
}
consoleInteracter.Tell("Exiting tool.");
+ commands.Dispose();
}
public static void Stop() {
diff --git a/src/SlatedGameToolkit.Tools/System/CommandMap.cs b/src/SlatedGameToolkit.Tools/System/CommandMap.cs
index bb35897..f62a3da 100644
--- a/src/SlatedGameToolkit.Tools/System/CommandMap.cs
+++ b/src/SlatedGameToolkit.Tools/System/CommandMap.cs
@@ -5,7 +5,7 @@ using SlatedGameToolkit.Tools.System.Interaction;
namespace SlatedGameToolkit.Tools.System
{
- public class CommandMap : ICollection {
+ public class CommandMap : ICollection, IDisposable {
Dictionary invocations;
HashSet values;
@@ -79,5 +79,17 @@ namespace SlatedGameToolkit.Tools.System
values.Remove(item);
return true;
}
+
+ public void Dispose()
+ {
+ foreach (IInvocable invocable in this)
+ {
+ invocable.Dispose();
+ }
+ }
+
+ ~CommandMap() {
+ Dispose();
+ }
}
}
\ No newline at end of file
diff --git a/src/SlatedGameToolkit.Tools/System/IInvocable.cs b/src/SlatedGameToolkit.Tools/System/IInvocable.cs
index 6beb0c0..f27f63c 100644
--- a/src/SlatedGameToolkit.Tools/System/IInvocable.cs
+++ b/src/SlatedGameToolkit.Tools/System/IInvocable.cs
@@ -1,8 +1,9 @@
+using System;
using SlatedGameToolkit.Tools.System.Interaction;
namespace SlatedGameToolkit.Tools.System
{
- public interface IInvocable
+ public interface IInvocable : IDisposable
{
///
/// Invokers are the strings that should invoke this command.
diff --git a/src/SlatedGameToolkit.Tools/System/Interaction/IInteractable.cs b/src/SlatedGameToolkit.Tools/System/Interaction/IInteractable.cs
index 0aa362c..1530574 100644
--- a/src/SlatedGameToolkit.Tools/System/Interaction/IInteractable.cs
+++ b/src/SlatedGameToolkit.Tools/System/Interaction/IInteractable.cs
@@ -4,7 +4,6 @@ namespace SlatedGameToolkit.Tools.System.Interaction
{
void Tell(string message);
void Separate();
-
string Listen();
}
}
\ No newline at end of file
diff --git a/src/SlatedGameToolkit.Tools/Utilities/GraphicalPlayground/MainState.cs b/src/SlatedGameToolkit.Tools/Utilities/GraphicalPlayground/MainState.cs
new file mode 100644
index 0000000..0fd08f5
--- /dev/null
+++ b/src/SlatedGameToolkit.Tools/Utilities/GraphicalPlayground/MainState.cs
@@ -0,0 +1,40 @@
+using SlatedGameToolkit.Framework.StateSystem;
+using SlatedGameToolkit.Framework.StateSystem.States;
+
+namespace SlatedGameToolkit.Tools.Utilities.GraphicalPlayground
+{
+ public class MainState : IState
+ {
+ public bool Activate()
+ {
+ return true;
+ }
+
+ public bool Deactivate()
+ {
+ return true;
+ }
+
+ public void Dispose()
+ {
+ }
+
+ public string getName()
+ {
+ return "main state";
+ }
+
+ public void Initialize(Manager manager)
+ {
+
+ }
+
+ public void Render(double delta)
+ {
+ }
+
+ public void Update(double delta)
+ {
+ }
+ }
+}
\ No newline at end of file