/// <summary> /// Creates a new SDL_Window and SDL_Renderer. /// /// NOTE: windowClosed will be called asyncronously in parentForm's thread. /// </summary> /// <param name="parentForm">The parent Form of the SDL_Window.</param> /// <param name="windowWidth">Width of the window to create.</param> /// <param name="windowHeight">Height of the window to create.</param> /// <param name="windowTitle">Title to give the SDL_Window.</param> /// <param name="windowClosed">Delegate for the SDL_Window closing by the user clicking the close button.</param> /// <param name="drawsPerSecond">Number of times per second the scene should be rendered.</param> /// <param name="eventsPerSecond">Number of times per second the events should be checked, not the number of events to be processed.</param> /// <param name="fastRender">If false, will make more extensive sanity checks.</param> /// <param name="showCursorOverWindow"> Show the mouse cursor when over the SDL_Window?</param> public SDLRenderer( Form parentForm, int windowWidth, int windowHeight, string windowTitle, void_RendererOnly windowClosed, int drawsPerSecond = DEFAULT_DRAWS_PER_SECOND, int eventsPerSecond = DEFAULT_EVENTS_PER_SECOND, bool fastRender = true, bool showCursorOverWindow = true ) : base() { INTERNAL_Init_Main(parentForm, null, windowWidth, windowHeight, windowTitle, windowClosed, drawsPerSecond, eventsPerSecond, fastRender, showCursorOverWindow); }
protected virtual void Dispose(bool disposing) { if (_disposed) { return; } if (sync != null) { sync.Dispose(); } sync = null; cbInvoke = null; // This is no longer a valid state _disposed = true; }
void INTERNAL_SDLThread_InvokeQueue_PrepareInvoke(void_RendererOnly del, bool asyncBegin) { // Invoke will cause a queued event in the SDL thread. Normal Invoke/BeginInvoke // cannot be used as the main loop for the SDL thread is always running. // Due to this being handled through a queue system the call can be delayed. // Begin/Invoke struct var ueInfo = new Invoke_RendererOnly(); ueInfo.cbInvoke = del; ueInfo.sync = null; if (!asyncBegin) { // Create a semaphore with 1 slot and 0 available to handle Invoke() // This way we already hold the lone semaphore slot before we push // the event to the queue. When the event is handled it will release // the semaphore count and allow this thread to resume execution. ueInfo.sync = new SemaphoreSlim(0, 1); } // Add this event to the queue INTERNAL_SDLThread_InvokeQueue_Add(ueInfo); // Was this an Invoke? if (!asyncBegin) { // Wait for the SDL thread to handle the Invoke() ueInfo.sync.Wait(); ueInfo.sync.Release(); // We need to free the unmanaged resources here ueInfo.Dispose(); ueInfo = null; } }
// The actual constructor void INTERNAL_Init_Main( Form mainForm, Control targetControl, int windowWidth, int windowHeight, string windowTitle, void_RendererOnly windowClosed, int drawsPerSecond, int eventsPerSecond, bool fastRender, bool showCursorOverControl) { // Will this be an anchored window? _anchored = (targetControl != null); // mainForm must be set regardless if (mainForm == null) { throw new ArgumentException("mainForm/parentForm cannot be null!"); } // windowClosed must be set for an unanchored window if ((!_anchored) && (windowClosed == null)) { throw new ArgumentException("windowClosed cannot be null!"); } // Assign the control objects the SDL_Window and SDL_Renderer will attach to _targetControl = targetControl; _parent = _anchored ? targetControl : mainForm; _parentHandle = _parent.Handle; _mainForm = mainForm; _mainFormHandle = _mainForm.Handle; _targetControlHandle = _anchored ? _targetControl.Handle : IntPtr.Zero; _windowSize = _anchored ? _targetControl.Size : new Size(windowWidth, windowHeight); _windowTitle = windowTitle; WindowClosed = windowClosed; // Create an empty invoke queue _invokeQueue = new List <Invoke_RendererOnly>(); // Clear SDLThread controls _threadState = SDLThreadState.Inactive; _exitRequested = false; _pauseThread = false; _rendererResetRequired = false; _rendererResetRequired = false; _windowSaveRequested = false; // Clear SDLThread Performance Feedback variables _actualFPS = 0; _potentialFPS = 0; _averageFrameTime = 0; // Set initial render API state _clearColor = Color.FromArgb(0); _showCursor = showCursorOverControl; _fastRender = fastRender; _drawsPS = drawsPerSecond; _eventsPS = eventsPerSecond; // Since we are not a procedural language, we'll tell SDL to stfu. SDL.SDL_SetMainReady(); // Initialize SDL _sdlInitialized = INTERNAL_Init_SDLSystems( SDL.SDL_INIT_TIMER | SDL.SDL_INIT_VIDEO ); if (!_sdlInitialized) { throw new Exception(string.Format("Unable to initialize SDL!\n\n{0}", SDL.SDL_GetError())); } // Now start the "SDLThread" to handle this renderer var threadInitOk = INTERNAL_Init_SDLThread(); if (!threadInitOk) { throw new Exception(string.Format("Error in thread startup!\n\n{0}", SDL.SDL_GetError())); } }
public void BeginInvoke(void_RendererOnly del) { INTERNAL_SDLThread_InvokeQueue_PrepareInvoke(del, true); }
public void Invoke(void_RendererOnly del) { INTERNAL_SDLThread_InvokeQueue_PrepareInvoke(del, false); }