658 lines
19 KiB
C#
658 lines
19 KiB
C#
using System;
|
|
using System.Diagnostics;
|
|
using System.IO;
|
|
using SDL2;
|
|
using PortableGL;
|
|
using PortableGL.SDL;
|
|
using Blarg.GameFramework.Graphics;
|
|
using Blarg.GameFramework.Input;
|
|
using Blarg.GameFramework.IO;
|
|
|
|
namespace Blarg.GameFramework
|
|
{
|
|
public class SDLApplication : BaseApplication
|
|
{
|
|
const string LOG_TAG = "SDL_APP";
|
|
|
|
#region Fields
|
|
|
|
bool _isSDLinited;
|
|
IntPtr _window;
|
|
IntPtr _glContext;
|
|
SDLLogger _logger;
|
|
SDLKeyboard _keyboard;
|
|
SDLMouse _mouse;
|
|
SDLFileSystem _filesystem;
|
|
SDLWindow _windowInfo;
|
|
SDLGL20 _gl;
|
|
PlatformOS _os;
|
|
|
|
bool _isWindowActive;
|
|
bool _isPaused;
|
|
bool _isQuitting;
|
|
|
|
int _targetUpdatesPerSecond;
|
|
int _ticksPerUpdate;
|
|
float _fixedUpdateInterval;
|
|
float _fixedRenderInterval;
|
|
int _maxFrameSkip = 10;
|
|
|
|
#endregion
|
|
|
|
#region Properties
|
|
|
|
public override PlatformOS OperatingSystem
|
|
{
|
|
get { return _os; }
|
|
}
|
|
|
|
public override PlatformType PlatformType
|
|
{
|
|
get { return PlatformType.Desktop; }
|
|
}
|
|
|
|
public override ILogger Logger
|
|
{
|
|
get { return _logger; }
|
|
}
|
|
|
|
public override IFileSystem FileSystem
|
|
{
|
|
get { return _filesystem; }
|
|
}
|
|
|
|
public override IKeyboard Keyboard
|
|
{
|
|
get { return _keyboard; }
|
|
}
|
|
|
|
public override IMouse Mouse
|
|
{
|
|
get { return _mouse; }
|
|
}
|
|
|
|
public override ITouchScreen TouchScreen
|
|
{
|
|
get { return null; }
|
|
}
|
|
|
|
public override IPlatformWindow Window
|
|
{
|
|
get { return _windowInfo; }
|
|
}
|
|
|
|
public override GL20 GL
|
|
{
|
|
get { return _gl; }
|
|
}
|
|
|
|
#endregion
|
|
|
|
public SDLApplication()
|
|
{
|
|
_logger = new SDLLogger();
|
|
_windowInfo = new SDLWindow();
|
|
|
|
if (CurrentOS.IsWindows)
|
|
_os = PlatformOS.Windows;
|
|
else if (CurrentOS.IsLinux)
|
|
_os = PlatformOS.Linux;
|
|
else if (CurrentOS.IsMac)
|
|
_os = PlatformOS.MacOS;
|
|
else
|
|
throw new Exception("Unable to determine OS.");
|
|
|
|
SetUpdateFrequency(25);
|
|
}
|
|
|
|
public override void Run(IGameApp gameApp, IPlatformConfiguration config)
|
|
{
|
|
if (gameApp == null)
|
|
throw new ArgumentNullException("gameApp");
|
|
GameApp = gameApp;
|
|
|
|
if (config == null)
|
|
throw new ArgumentNullException("config");
|
|
if (!(config is SDLConfiguration))
|
|
throw new ArgumentException("Must pass a SDLConfiguration object.", "config");
|
|
|
|
Logger.Info(LOG_TAG, "Running...");
|
|
|
|
SDLConfiguration sdlConfig = (SDLConfiguration)config;
|
|
|
|
Logger.Info(LOG_TAG, "Received SDL configuration:");
|
|
Logger.Info(LOG_TAG, "\tTitle: {0}", sdlConfig.Title);
|
|
Logger.Info(LOG_TAG, "\tWidth: {0}", sdlConfig.Width);
|
|
Logger.Info(LOG_TAG, "\tHeight: {0}", sdlConfig.Height);
|
|
Logger.Info(LOG_TAG, "\tFullscreen: {0}", sdlConfig.Fullscreen);
|
|
Logger.Info(LOG_TAG, "\tResizeable: {0}", sdlConfig.Resizeable);
|
|
Logger.Info(LOG_TAG, "GL Doublebuffer: {0}", sdlConfig.glDoubleBuffer);
|
|
Logger.Info(LOG_TAG, "GL Depth Buffer Size: {0}", sdlConfig.glDepthBufferSize);
|
|
Logger.Info(LOG_TAG, "GL Red Size: {0}", sdlConfig.glRedSize);
|
|
Logger.Info(LOG_TAG, "GL Green Size: {0}", sdlConfig.glGreenSize);
|
|
Logger.Info(LOG_TAG, "GL Blue Size: {0}", sdlConfig.glBlueSize);
|
|
Logger.Info(LOG_TAG, "GL Alpha Size: {0}", sdlConfig.glAlphaSize);
|
|
|
|
if (!InitSDL())
|
|
{
|
|
Logger.Error(LOG_TAG, "SDL initialization failed. Aborting.");
|
|
return;
|
|
}
|
|
|
|
if (!InitSDLWindow(sdlConfig))
|
|
{
|
|
Logger.Error(LOG_TAG, "SDL window creation failed. Aborting.");
|
|
return;
|
|
}
|
|
|
|
Framework.Set(this);
|
|
|
|
OnInit();
|
|
OnNewContext();
|
|
OnResize(ScreenOrientation.Rotation0, _windowInfo.ClientRectangle);
|
|
OnLoad();
|
|
|
|
Logger.Info(LOG_TAG, "Main loop starting.");
|
|
MainLoop();
|
|
Logger.Info(LOG_TAG, "Main loop finished.");
|
|
|
|
OnUnload();
|
|
OnLostContext();
|
|
OnShutdown();
|
|
|
|
Logger.Info(LOG_TAG, "Cleaning up game application object.");
|
|
GameApp.Dispose();
|
|
GameApp = null;
|
|
|
|
Release();
|
|
}
|
|
|
|
public override void Quit()
|
|
{
|
|
Logger.Info(LOG_TAG, "Quit signaled. Main loop will exit.");
|
|
_isQuitting = true;
|
|
}
|
|
|
|
private void MainLoop()
|
|
{
|
|
_isWindowActive = true;
|
|
_isPaused = false;
|
|
_isQuitting = false;
|
|
|
|
int numUpdatesThisFrame = 0;
|
|
int numLoops = 0;
|
|
int timeElapsed = 0;
|
|
|
|
int updateTime = 0;
|
|
int renderTime = 0;
|
|
int numUpdates = 0;
|
|
int numRenders = 0;
|
|
|
|
int nextUpdateAt = Environment.TickCount;
|
|
int currentTime = Environment.TickCount;
|
|
|
|
while (!_isQuitting)
|
|
{
|
|
if (_isPaused)
|
|
{
|
|
// we always want to be processing events, even when paused
|
|
DoEvents();
|
|
}
|
|
else
|
|
{
|
|
int newTime = Environment.TickCount;
|
|
int frameTime = newTime - currentTime;
|
|
currentTime = newTime;
|
|
timeElapsed += frameTime;
|
|
|
|
// every second recalculate the FPS
|
|
if (timeElapsed >= 1000)
|
|
{
|
|
FPS = numLoops;
|
|
FrameTime = 1000.0f / FPS;
|
|
|
|
RendersPerSecond = numRenders;
|
|
UpdatesPerSecond = numUpdates;
|
|
RenderTime = renderTime;
|
|
UpdateTime = updateTime;
|
|
|
|
numUpdates = 0;
|
|
numRenders = 0;
|
|
renderTime = 0;
|
|
updateTime = 0;
|
|
|
|
numLoops = 0;
|
|
timeElapsed = 0;
|
|
}
|
|
|
|
// we're "running slowly" if we're more then one update behind
|
|
if (currentTime > nextUpdateAt + _ticksPerUpdate)
|
|
IsRunningSlowly = true;
|
|
else
|
|
IsRunningSlowly = false;
|
|
|
|
numUpdatesThisFrame = 0;
|
|
while (Environment.TickCount >= nextUpdateAt && numUpdatesThisFrame < _maxFrameSkip)
|
|
{
|
|
if (numUpdatesThisFrame > 0)
|
|
IsRunningSlowly = true;
|
|
|
|
int before = Environment.TickCount;
|
|
DoEvents();
|
|
OnUpdate(_fixedUpdateInterval);
|
|
updateTime += Environment.TickCount - before;
|
|
|
|
++numUpdatesThisFrame;
|
|
nextUpdateAt += _ticksPerUpdate;
|
|
|
|
++numUpdates;
|
|
}
|
|
|
|
if (_isWindowActive)
|
|
{
|
|
float renderDelta = (float)(Environment.TickCount + _ticksPerUpdate - nextUpdateAt) / (float)_ticksPerUpdate;
|
|
int before = Environment.TickCount;
|
|
OnRender(renderDelta); // TODO
|
|
SDL.SDL_GL_SwapWindow(_window);
|
|
renderTime += Environment.TickCount - before;
|
|
|
|
++numRenders;
|
|
}
|
|
|
|
++numLoops;
|
|
}
|
|
}
|
|
}
|
|
|
|
private void SetUpdateFrequency(int targetFrequency)
|
|
{
|
|
_targetUpdatesPerSecond = targetFrequency;
|
|
_ticksPerUpdate = 1000 / _targetUpdatesPerSecond;
|
|
_fixedUpdateInterval = _ticksPerUpdate / 1000.0f;
|
|
}
|
|
|
|
#region Initialization
|
|
|
|
private bool InitSDL()
|
|
{
|
|
Logger.Info(LOG_TAG, "SDL initialization starting.");
|
|
|
|
SDL.SDL_version sdlVersion;
|
|
SDL.SDL_VERSION(out sdlVersion);
|
|
Logger.Info(LOG_TAG, "SDL Runtime Version: {0}.{1}.{2}", sdlVersion.major, sdlVersion.minor, sdlVersion.patch);
|
|
Logger.Info(LOG_TAG, "SDL Linked Version: {0}.{1}.{2}", SDL.SDL_MAJOR_VERSION, SDL.SDL_MINOR_VERSION, SDL.SDL_PATCHLEVEL);
|
|
|
|
if (SDL.SDL_Init(SDL.SDL_INIT_VIDEO | SDL.SDL_INIT_AUDIO | SDL.SDL_INIT_GAMECONTROLLER | SDL.SDL_INIT_JOYSTICK | SDL.SDL_INIT_TIMER) == -1)
|
|
{
|
|
Logger.Error(LOG_TAG, "SDL_Init() failed: {0}", SDL.SDL_GetError());
|
|
return false;
|
|
}
|
|
_isSDLinited = true;
|
|
|
|
_keyboard = new SDLKeyboard();
|
|
Logger.Info(LOG_TAG, "Keyboard input device ready.");
|
|
|
|
_mouse = new SDLMouse();
|
|
Logger.Info(LOG_TAG, "Mouse input device ready.");
|
|
|
|
int numJoysticks = SDL.SDL_NumJoysticks();
|
|
|
|
Logger.Info(LOG_TAG, "{0} joystick input devices found.", numJoysticks);
|
|
for (int i = 0; i < numJoysticks; ++i)
|
|
{
|
|
Logger.Info(LOG_TAG, "Joystick #{0}. {1}:", (i + 1), SDL.SDL_JoystickNameForIndex(i));
|
|
IntPtr joystick = SDL.SDL_JoystickOpen(i);
|
|
if (joystick != IntPtr.Zero)
|
|
{
|
|
Logger.Info(LOG_TAG, "\tAxes: {0}", SDL.SDL_JoystickNumAxes(joystick));
|
|
Logger.Info(LOG_TAG, "\tBalls: {0}", SDL.SDL_JoystickNumBalls(joystick));
|
|
Logger.Info(LOG_TAG, "\tHats: {0}", SDL.SDL_JoystickNumHats(joystick));
|
|
Logger.Info(LOG_TAG, "\tButtons: {0}", SDL.SDL_JoystickNumButtons(joystick));
|
|
SDL.SDL_JoystickClose(joystick);
|
|
}
|
|
else
|
|
Logger.Warn(LOG_TAG, "\tMore information could not be obtained.");
|
|
}
|
|
|
|
_filesystem = new SDLFileSystem();
|
|
Logger.Info(LOG_TAG, "Filesystem access initialized.");
|
|
|
|
int numVideoDrivers = SDL.SDL_GetNumVideoDrivers();
|
|
Logger.Info(LOG_TAG, "Video drivers present: {0}.", numVideoDrivers);
|
|
for (int i = 0; i < numVideoDrivers; ++i)
|
|
Logger.Info(LOG_TAG, "\t{0}: {1}", (i + 1), SDL.SDL_GetVideoDriver(i));
|
|
Logger.Info(LOG_TAG, "Currently using video driver: {0}", SDL.SDL_GetCurrentVideoDriver());
|
|
|
|
int numAudioDrivers = SDL.SDL_GetNumAudioDrivers();
|
|
Logger.Info(LOG_TAG, "Audio drivers present: {0}", numAudioDrivers);
|
|
for (int i = 0; i < numAudioDrivers; ++i)
|
|
Logger.Info(LOG_TAG, "\t{0}: {1}", (i + 1), SDL.SDL_GetAudioDriver(i));
|
|
Logger.Info(LOG_TAG, "Currently using audio driver: {0}", SDL.SDL_GetCurrentAudioDriver());
|
|
|
|
Logger.Info(LOG_TAG, "SDL initialization finished.");
|
|
return true;
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region Window Management
|
|
|
|
private bool InitSDLWindow(SDLConfiguration config)
|
|
{
|
|
Logger.Info(LOG_TAG, "SDL Window initialization starting.");
|
|
|
|
int flags = (int)SDL.SDL_WindowFlags.SDL_WINDOW_OPENGL | (int)SDL.SDL_WindowFlags.SDL_WINDOW_SHOWN;
|
|
if (config.Fullscreen)
|
|
flags |= (int)SDL.SDL_WindowFlags.SDL_WINDOW_FULLSCREEN;
|
|
if (config.Resizeable)
|
|
flags |= (int)SDL.SDL_WindowFlags.SDL_WINDOW_RESIZABLE;
|
|
|
|
if (!CreateWindow(config.Title, config.Width, config.Height, flags))
|
|
return false;
|
|
|
|
if (!CreateOpenGLContext(config))
|
|
return false;
|
|
|
|
Logger.Info(LOG_TAG, "SDL Window initialization finished.");
|
|
return true;
|
|
}
|
|
|
|
private bool CreateWindow(string title, int width, int height, int flags)
|
|
{
|
|
Logger.Info(LOG_TAG, "Attempting to set up new window with dimensions {0}x{1}.", width, height);
|
|
if (_window != IntPtr.Zero)
|
|
throw new InvalidOperationException("Cannot create new window before destorying existing one.");
|
|
|
|
_window = SDL.SDL_CreateWindow(title, SDL.SDL_WINDOWPOS_UNDEFINED, SDL.SDL_WINDOWPOS_UNDEFINED, width, height, (SDL.SDL_WindowFlags)flags);
|
|
if (_window == IntPtr.Zero)
|
|
{
|
|
Logger.Error(LOG_TAG, "Window creation failed: {0}", SDL.SDL_GetError());
|
|
return false;
|
|
}
|
|
|
|
SetWindowInfo();
|
|
|
|
Logger.Info(LOG_TAG, "Window creation succeeded.");
|
|
return true;
|
|
}
|
|
|
|
private bool DestroyWindow()
|
|
{
|
|
Logger.Info(LOG_TAG, "Destroying window.");
|
|
if (_window == IntPtr.Zero)
|
|
{
|
|
Logger.Warn(LOG_TAG, "No window currently exists, not doing anything.");
|
|
return true;
|
|
}
|
|
|
|
SDL.SDL_DestroyWindow(_window);
|
|
_window = IntPtr.Zero;
|
|
|
|
Logger.Info(LOG_TAG, "Window destroyed.");
|
|
return true;
|
|
}
|
|
|
|
private void SetWindowInfo()
|
|
{
|
|
if (_window == IntPtr.Zero)
|
|
throw new InvalidOperationException("Cannot set window info for a non-existant window.");
|
|
|
|
int windowX;
|
|
int windowY;
|
|
SDL.SDL_GetWindowPosition(_window, out windowX, out windowY);
|
|
|
|
int clientWidth;
|
|
int clientHeight;
|
|
SDL.SDL_GetWindowSize(_window, out clientWidth, out clientHeight);
|
|
|
|
_windowInfo.ClientWidth = clientWidth;
|
|
_windowInfo.ClientHeight = clientHeight;
|
|
_windowInfo.ClientRectangle = new Rect(0, 0, clientWidth, clientHeight);
|
|
|
|
Logger.Info(LOG_TAG, "Window content area set to {0}", _windowInfo.ClientRectangle);
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region OpenGL Context Management
|
|
|
|
private bool CreateOpenGLContext(SDLConfiguration config)
|
|
{
|
|
Logger.Info(LOG_TAG, "Attempting to create OpenGL context.");
|
|
if (_glContext != IntPtr.Zero)
|
|
throw new InvalidOperationException("Cannoy create new OpenGL context before destroying existing one.");
|
|
if (_window == IntPtr.Zero)
|
|
throw new InvalidOperationException("Cannot create an OpenGL context without an existing window.");
|
|
|
|
// minimum requirements
|
|
SDL.SDL_GL_SetAttribute(SDL.SDL_GLattr.SDL_GL_CONTEXT_MAJOR_VERSION, config.glMajorVersion);
|
|
SDL.SDL_GL_SetAttribute(SDL.SDL_GLattr.SDL_GL_CONTEXT_MINOR_VERSION, config.glMinorVersion);
|
|
SDL.SDL_GL_SetAttribute(SDL.SDL_GLattr.SDL_GL_DOUBLEBUFFER, config.glDoubleBuffer ? 1 : 0);
|
|
SDL.SDL_GL_SetAttribute(SDL.SDL_GLattr.SDL_GL_DEPTH_SIZE, config.glDepthBufferSize);
|
|
SDL.SDL_GL_SetAttribute(SDL.SDL_GLattr.SDL_GL_RED_SIZE, config.glRedSize);
|
|
SDL.SDL_GL_SetAttribute(SDL.SDL_GLattr.SDL_GL_GREEN_SIZE, config.glGreenSize);
|
|
SDL.SDL_GL_SetAttribute(SDL.SDL_GLattr.SDL_GL_BLUE_SIZE, config.glBlueSize);
|
|
SDL.SDL_GL_SetAttribute(SDL.SDL_GLattr.SDL_GL_ALPHA_SIZE, config.glAlphaSize);
|
|
|
|
_glContext = SDL.SDL_GL_CreateContext(_window);
|
|
if (_glContext == IntPtr.Zero)
|
|
{
|
|
Logger.Error(LOG_TAG, "OpenGL context creation failed: {0}", SDL.SDL_GetError());
|
|
return false;
|
|
}
|
|
|
|
Logger.Info(LOG_TAG, "OpenGL context creation succeeded.");
|
|
|
|
Logger.Info(LOG_TAG, "Setting OpenTK's OpenGL context and loading OpenGL extensions.");
|
|
_gl = new SDLGL20(_glContext);
|
|
|
|
int redSize;
|
|
int greenSize;
|
|
int blueSize;
|
|
int alphaSize;
|
|
int bufferSize;
|
|
int doubleBuffer;
|
|
int depthSize;
|
|
int stencilSize;
|
|
int accumRedSize;
|
|
int accumGreenSize;
|
|
int accumBlueSize;
|
|
int accumAlphaSize;
|
|
int stereo;
|
|
int multisampleBuffers;
|
|
int multisampleSamples;
|
|
int acceleratedVisual;
|
|
int contextMajorVersion;
|
|
int contextMinorVersion;
|
|
|
|
SDL.SDL_GL_GetAttribute(SDL.SDL_GLattr.SDL_GL_RED_SIZE, out redSize);
|
|
SDL.SDL_GL_GetAttribute(SDL.SDL_GLattr.SDL_GL_GREEN_SIZE, out greenSize);
|
|
SDL.SDL_GL_GetAttribute(SDL.SDL_GLattr.SDL_GL_BLUE_SIZE, out blueSize);
|
|
SDL.SDL_GL_GetAttribute(SDL.SDL_GLattr.SDL_GL_ALPHA_SIZE, out alphaSize);
|
|
SDL.SDL_GL_GetAttribute(SDL.SDL_GLattr.SDL_GL_BUFFER_SIZE, out bufferSize);
|
|
SDL.SDL_GL_GetAttribute(SDL.SDL_GLattr.SDL_GL_DOUBLEBUFFER, out doubleBuffer);
|
|
SDL.SDL_GL_GetAttribute(SDL.SDL_GLattr.SDL_GL_DEPTH_SIZE, out depthSize);
|
|
SDL.SDL_GL_GetAttribute(SDL.SDL_GLattr.SDL_GL_STENCIL_SIZE, out stencilSize);
|
|
SDL.SDL_GL_GetAttribute(SDL.SDL_GLattr.SDL_GL_ACCUM_RED_SIZE, out accumRedSize);
|
|
SDL.SDL_GL_GetAttribute(SDL.SDL_GLattr.SDL_GL_ACCUM_GREEN_SIZE, out accumGreenSize);
|
|
SDL.SDL_GL_GetAttribute(SDL.SDL_GLattr.SDL_GL_ACCUM_BLUE_SIZE, out accumBlueSize);
|
|
SDL.SDL_GL_GetAttribute(SDL.SDL_GLattr.SDL_GL_ACCUM_ALPHA_SIZE, out accumAlphaSize);
|
|
SDL.SDL_GL_GetAttribute(SDL.SDL_GLattr.SDL_GL_STEREO, out stereo);
|
|
SDL.SDL_GL_GetAttribute(SDL.SDL_GLattr.SDL_GL_MULTISAMPLEBUFFERS, out multisampleBuffers);
|
|
SDL.SDL_GL_GetAttribute(SDL.SDL_GLattr.SDL_GL_MULTISAMPLESAMPLES, out multisampleSamples);
|
|
SDL.SDL_GL_GetAttribute(SDL.SDL_GLattr.SDL_GL_ACCELERATED_VISUAL, out acceleratedVisual);
|
|
SDL.SDL_GL_GetAttribute(SDL.SDL_GLattr.SDL_GL_CONTEXT_MAJOR_VERSION, out contextMajorVersion);
|
|
SDL.SDL_GL_GetAttribute(SDL.SDL_GLattr.SDL_GL_CONTEXT_MINOR_VERSION, out contextMinorVersion);
|
|
|
|
Logger.Info(LOG_TAG, "OpenGL context attributes:");
|
|
Logger.Info(LOG_TAG, "\tGL_RED_SIZE: {0}", redSize);
|
|
Logger.Info(LOG_TAG, "\tGL_GREEN_SIZE: {0}", greenSize);
|
|
Logger.Info(LOG_TAG, "\tGL_BLUE_SIZE: {0}", blueSize);
|
|
Logger.Info(LOG_TAG, "\tGL_ALPHA_SIZE: {0}", alphaSize);
|
|
Logger.Info(LOG_TAG, "\tGL_BUFFER_SIZE: {0}", bufferSize);
|
|
Logger.Info(LOG_TAG, "\tGL_DOUBLEBUFFER: {0}", doubleBuffer);
|
|
Logger.Info(LOG_TAG, "\tGL_DEPTH_SIZE: {0}", depthSize);
|
|
Logger.Info(LOG_TAG, "\tGL_STENCIL_SIZE: {0}", stencilSize);
|
|
Logger.Info(LOG_TAG, "\tGL_ACCUM_RED_SIZE: {0}", accumRedSize);
|
|
Logger.Info(LOG_TAG, "\tGL_ACCUM_GREEN_SIZE: {0}", accumGreenSize);
|
|
Logger.Info(LOG_TAG, "\tGL_ACCUM_BLUE_SIZE: {0}", accumBlueSize);
|
|
Logger.Info(LOG_TAG, "\tGL_ACCUM_ALPHA_SIZE: {0}", accumAlphaSize);
|
|
Logger.Info(LOG_TAG, "\tGL_STEREO: {0}", stereo);
|
|
Logger.Info(LOG_TAG, "\tGL_MULTISAMPLEBUFFERS: {0}", multisampleBuffers);
|
|
Logger.Info(LOG_TAG, "\tGL_MULTISAMPLESAMPLES: {0}", multisampleSamples);
|
|
Logger.Info(LOG_TAG, "\tGL_ACCELERATED_VISUAL: {0}", acceleratedVisual);
|
|
Logger.Info(LOG_TAG, "\tGL_CONTEXT_MAJOR_VERSION: {0}", contextMajorVersion);
|
|
Logger.Info(LOG_TAG, "\tGL_CONTEXT_MINOR_VERSION: {0}", contextMinorVersion);
|
|
|
|
Logger.Info(LOG_TAG, "Attempting to enable V-sync.");
|
|
if (SDL.SDL_GL_SetSwapInterval(1) != 0)
|
|
Logger.Warn(LOG_TAG, "Could not set swap interval: {0}", SDL.SDL_GetError());
|
|
else
|
|
Logger.Info(LOG_TAG, "Swap interval set successful.");
|
|
|
|
return true;
|
|
}
|
|
|
|
private bool DestroyOpenGLContext()
|
|
{
|
|
Logger.Info(LOG_TAG, "Destroying OpenGL context.");
|
|
if (_glContext == IntPtr.Zero)
|
|
{
|
|
Logger.Warn(LOG_TAG, "No OpenGL context currently exists, not doing anything.");
|
|
return true;
|
|
}
|
|
|
|
SDL.SDL_GL_DeleteContext(_glContext);
|
|
OpenTK.Graphics.GraphicsContext.CurrentContext = IntPtr.Zero;
|
|
_glContext = IntPtr.Zero;
|
|
|
|
Logger.Info(LOG_TAG, "OpenGL context destroyed.");
|
|
return true;
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region Events
|
|
|
|
private void DoEvents()
|
|
{
|
|
SDL.SDL_Event e;
|
|
while (SDL.SDL_PollEvent(out e) != 0)
|
|
{
|
|
if (e.type == SDL.SDL_EventType.SDL_WINDOWEVENT)
|
|
{
|
|
switch (e.window.windowEvent)
|
|
{
|
|
case SDL.SDL_WindowEventID.SDL_WINDOWEVENT_MINIMIZED:
|
|
Logger.Info(LOG_TAG, "Window focus lost.");
|
|
Logger.Info(LOG_TAG, "Window marked inactive.");
|
|
break;
|
|
|
|
case SDL.SDL_WindowEventID.SDL_WINDOWEVENT_RESTORED:
|
|
Logger.Info(LOG_TAG, "Window focus gained.");
|
|
Logger.Info(LOG_TAG, "Window marked active.");
|
|
break;
|
|
|
|
case SDL.SDL_WindowEventID.SDL_WINDOWEVENT_ENTER:
|
|
Logger.Info(LOG_TAG, "Gained mouse focus.");
|
|
break;
|
|
|
|
case SDL.SDL_WindowEventID.SDL_WINDOWEVENT_LEAVE:
|
|
Logger.Info(LOG_TAG, "Lost mouse focus.");
|
|
break;
|
|
|
|
case SDL.SDL_WindowEventID.SDL_WINDOWEVENT_FOCUS_GAINED:
|
|
Logger.Info(LOG_TAG, "Gained input device focus.");
|
|
OnAppGainFocus();
|
|
break;
|
|
|
|
case SDL.SDL_WindowEventID.SDL_WINDOWEVENT_FOCUS_LOST:
|
|
Logger.Info(LOG_TAG, "Lost input device focus.");
|
|
OnAppLostFocus();
|
|
break;
|
|
|
|
case SDL.SDL_WindowEventID.SDL_WINDOWEVENT_RESIZED:
|
|
Logger.Info(LOG_TAG, "Window resized to {0}x{1}.", e.window.data1, e.window.data2);
|
|
Rect size = new Rect();
|
|
size.Right = e.window.data1;
|
|
size.Bottom = e.window.data2;
|
|
SetWindowInfo();
|
|
OnResize(ScreenOrientation.Rotation0, size);
|
|
break;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
switch (e.type)
|
|
{
|
|
case SDL.SDL_EventType.SDL_QUIT:
|
|
Logger.Info(LOG_TAG, "Event: SQL_QUIT");
|
|
_isQuitting = true;
|
|
break;
|
|
|
|
case SDL.SDL_EventType.SDL_KEYDOWN:
|
|
case SDL.SDL_EventType.SDL_KEYUP:
|
|
_keyboard.OnKeyEvent(e.key);
|
|
break;
|
|
|
|
case SDL.SDL_EventType.SDL_MOUSEMOTION:
|
|
_mouse.OnMotionEvent(e.motion);
|
|
break;
|
|
|
|
case SDL.SDL_EventType.SDL_MOUSEBUTTONDOWN:
|
|
case SDL.SDL_EventType.SDL_MOUSEBUTTONUP:
|
|
_mouse.OnButtonEvent(e.button);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region Support Functions
|
|
|
|
public override IPlatformBitmap LoadBitmap(Stream file)
|
|
{
|
|
return new SDLBitmap(file);
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region IDisposable
|
|
|
|
protected override void Release()
|
|
{
|
|
if (!_isSDLinited)
|
|
return;
|
|
|
|
Logger.Info(LOG_TAG, "Releasing SDL application object.");
|
|
base.Release();
|
|
|
|
Logger.Info(LOG_TAG, "Releasing SDL.");
|
|
DestroyOpenGLContext();
|
|
DestroyWindow();
|
|
SDL.SDL_Quit();
|
|
_isSDLinited = false;
|
|
|
|
Logger.Info(LOG_TAG, "SDL shutdown.");
|
|
}
|
|
|
|
~SDLApplication()
|
|
{
|
|
Release();
|
|
}
|
|
|
|
public override void Dispose()
|
|
{
|
|
base.Dispose();
|
|
Logger.Info(LOG_TAG, "Disposing.");
|
|
Release();
|
|
GC.SuppressFinalize(this);
|
|
}
|
|
|
|
#endregion
|
|
}
|
|
}
|
|
|