// All code here should be running in it's own thread created in INTERNAL_Init_SDLThread()
        // and should never be called outside of the thread itself.

        void INTERNAL_SDLThread_Main()
        {
            Console.Write("INTERNAL_SDLThread_Main()\n");

            _threadState = SDLThreadState.Starting;

            // Create the SDL_Window
            var windowOK = INTERNAL_SDLThread_InitWindow();

            if (!windowOK)
            {
                INTERNAL_SDLThread_Cleanup(SDLThreadState.Error);
                return;
            }

            // Create the SDL_Renderer
            var rendererOK = INTERNAL_SDLThread_InitRenderer();

            if (!rendererOK)
            {
                INTERNAL_SDLThread_Cleanup(SDLThreadState.Error);
                return;
            }

            // Translate the state machine into something meaningful to SDL
            INTERNAL_UpdateState_FunctionPointers();
            INTERNAL_UpdateState_CursorVisibility();
            INTERNAL_UpdateState_ThreadIntervals();

            // Now do the main thread loop
            INTERNAL_SDLThread_MainLoop();

            // Clean up after the thread
            INTERNAL_SDLThread_Cleanup(SDLThreadState.Inactive);
        }
        void INTERNAL_SDLThread_Cleanup(SDLThreadState newState)
        {
            Console.Write("INTERNAL_SDLThread_Cleanup()\n");

            // Dispose of the renderer, window, etc
            INTERNAL_SDLThread_ReleaseWindowAndRenderer();

            _sdlThread   = null;
            _threadState = newState;
        }
        void INTERNAL_SDLThread_MainLoop()
        {
            Console.Write("INTERNAL_SDLThread_MainLoop()\n");

            TimeSpan loopTime       = TimeSpan.FromTicks(0);
            long     loopStartTick  = 0;
            long     loopDelayTicks = 0;
            long     loopEndTick    = 0;
            TimeSpan loopSleepTime;
            int      loopSleepMS    = 0;
            long     lastDrawTick   = 0;
            long     lastEventTick  = 0;
            long     drawTickDelta  = 0;
            long     eventTickDelta = 0;

            long lastFPSCount = 0;
            long fpsTicks     = 0;
            long frameStart   = 0;
            long frameEnd     = 0;
            long frameTime    = 0;

            // Thread timing
            _threadTimer = new Stopwatch();

            // Mark the thread as running
            _threadState = SDLThreadState.Running;
            _threadTimer.Start();

            // Loop until we exit
            Console.Write("INTERNAL_SDLThread_MainLoop() :: Loop_Enter\n");
            while (!_exitRequested)
            {
                //Console.Write( "INTERNAL_SDLThread_MainLoop() :: Loop_Top\n" );

                // Get the loop start timestamp
                if (!_exitRequested)
                {
                    loopStartTick   = _threadTimer.Elapsed.Ticks;
                    loopDelayTicks += loopTime.Ticks;
                }

                // Pause the thread at the top of the loop
                if (_pauseThread)
                {
                    // Pause the thread until _pauseThread returns to false.  "Pausing" in
                    // this case is sleeping for 1ms in a loop. Ideally we would sleep for
                    // less than 1ms though, but 0 will make us return as soon as we can
                    // and use a bunch of CPU which we don't want.  1ms isn't even the true
                    // amount of time we'll sleep for, but 1 is the lowest positive value
                    // and will translate into the actual platform minimum sleep time
                    // (typically 15ms on Windows).
                    _threadState = SDLThreadState.Paused;

                    Console.Write("INTERNAL_SDLThread_MainLoop() :: Loop_Pause\n");
                    while (_pauseThread)
                    {
                        Thread.Sleep(1);
                    }
                    Console.Write("INTERNAL_SDLThread_MainLoop() :: Loop_Resume\n");

                    _threadState = SDLThreadState.Running;
                }

                // Save the last frame drawn to an image file
                if ((!_exitRequested) && (_windowSaveRequested))
                {
                    INTERNAL_SDLThread_SaveWindowToFile();
                }

                // Handle any invokes that have been queued
                if ((!_exitRequested) && (!_invokeQueue.NullOrEmpty()))
                {
                    INTERNAL_SDLThread_InvokeQueue_Dispatcher();
                }

                // Window needs to be recreated, do that before anything else
                if ((!_exitRequested) && (_windowResetRequired))
                {
                    _exitRequested = !INTERNAL_SDLThread_ResetWindow();
                }

                // Renderer needs to be recreated, do that before anything else
                if ((!_exitRequested) && (_rendererResetRequired))
                {
                    _exitRequested = !INTERNAL_SDLThread_ResetRenderer();
                }

                // Render the scene and handle events if we haven't been asked to terminate
                if (!_exitRequested)
                {
                    if (loopDelayTicks >= _baseFrameDelay)
                    {
                        loopDelayTicks -= _baseFrameDelay;
                        drawTickDelta   = loopStartTick - lastDrawTick;
                        eventTickDelta  = loopStartTick - lastEventTick;

                        if (drawTickDelta >= _drawTicks)
                        {
                            // Time to render the scene
                            lastFPSCount++;
                            drawTickDelta -= _drawTicks;
                            lastDrawTick   = loopStartTick;
                            frameStart     = _threadTimer.Elapsed.Ticks;
                            INTERNAL_SDLThread_RenderScene();
                            frameEnd   = _threadTimer.Elapsed.Ticks;
                            frameTime += (frameEnd - frameStart);
                        }

                        if (eventTickDelta >= _eventTicks)
                        {
                            // Time to check and handle events
                            eventTickDelta -= _eventTicks;
                            lastEventTick   = loopStartTick;
                            INTERNAL_SDLThread_EventDispatcher();
                        }
                    }
                }

                // If a client event handler requested an exit, don't worry about timings
                if (!_exitRequested)
                {
                    // Sleep until the next expected update
                    loopSleepTime = TimeSpan.FromTicks(_baseFrameDelay - loopDelayTicks);
                    loopSleepMS   = (int)loopSleepTime.TotalMilliseconds;
                    if (loopSleepMS >= 0)
                    {
                        Thread.Sleep(loopSleepMS);
                    }

                    // End of loop, get time elapsed for this loop
                    loopEndTick = _threadTimer.Elapsed.Ticks;
                    loopTime    = TimeSpan.FromTicks(loopEndTick - loopStartTick);

                    // Performance feedback
                    fpsTicks += loopTime.Ticks;
                    if ((fpsTicks >= TimeSpan.TicksPerSecond) && (lastFPSCount > 0))
                    {
                        _actualFPS        = (int)((lastFPSCount * TimeSpan.TicksPerSecond) / fpsTicks);
                        _potentialFPS     = (int)((lastFPSCount * TimeSpan.TicksPerSecond) / frameTime);
                        _averageFrameTime = frameTime / lastFPSCount;
                        lastFPSCount      = 0;
                        fpsTicks          = 0;
                        frameTime         = 0;
                    }
                }
                //Console.Write( "INTERNAL_SDLThread_MainLoop() :: Loop_Bottom\n" );
            }
            Console.Write("INTERNAL_SDLThread_MainLoop() :: Loop_Exit\n");

            // Mark the thread as no longer running
            _threadTimer.Stop();
            _threadState      = SDLThreadState.Stopping;
            _actualFPS        = 0;
            _potentialFPS     = 0;
            _averageFrameTime = 0;
        }