Exemplo n.º 1
0
        public void Run()
        {
            //Try to set DPI Awareness on Win32
            if (Platform.RunningOS == OS.Windows)
            {
                try {
                    SetProcessDPIAware();
                }
                catch {
                }
            }

            FLLog.Info("Engine", "Version: " + Platform.GetInformationalVersion <Game>());
            //TODO: This makes i5-7200U on mesa 18 faster, but this should probably be a configurable option
            bool setMesaThread = string.IsNullOrWhiteSpace(Environment.GetEnvironmentVariable("mesa_glthread"));

            if (setMesaThread)
            {
                Environment.SetEnvironmentVariable("mesa_glthread", "true");
            }
            if (SDL.SDL_Init(SDL.SDL_INIT_VIDEO) != 0)
            {
                FLLog.Error("SDL", "SDL_Init failed, exiting.");
                return;
            }
            SDL.SDL_SetHint(SDL.SDL_HINT_IME_INTERNAL_EDITING, "1");
            SDL.SDL_SetHint(SDL.SDL_HINT_VIDEO_X11_NET_WM_BYPASS_COMPOSITOR, "0");
            //Set GL states
            SDL.SDL_GL_SetAttribute(SDL.SDL_GLattr.SDL_GL_DEPTH_SIZE, 24);
            //Create Window
            var flags = SDL.SDL_WindowFlags.SDL_WINDOW_OPENGL | SDL.SDL_WindowFlags.SDL_WINDOW_RESIZABLE |
                        SDL.SDL_WindowFlags.SDL_WINDOW_ALLOW_HIGHDPI;

            if (fullscreen)
            {
                flags |= SDL.SDL_WindowFlags.SDL_WINDOW_FULLSCREEN_DESKTOP;
            }
            var sdlWin = SDL.SDL_CreateWindow(
                "LibreLancer",
                SDL.SDL_WINDOWPOS_CENTERED,
                SDL.SDL_WINDOWPOS_CENTERED,
                width,
                height,
                flags
                );

            //Cursors
            curArrow      = SDL.SDL_CreateSystemCursor(SDL.SDL_SystemCursor.SDL_SYSTEM_CURSOR_ARROW);
            curMove       = SDL.SDL_CreateSystemCursor(SDL.SDL_SystemCursor.SDL_SYSTEM_CURSOR_CROSSHAIR);
            curTextInput  = SDL.SDL_CreateSystemCursor(SDL.SDL_SystemCursor.SDL_SYSTEM_CURSOR_IBEAM);
            curResizeNS   = SDL.SDL_CreateSystemCursor(SDL.SDL_SystemCursor.SDL_SYSTEM_CURSOR_SIZENS);
            curResizeEW   = SDL.SDL_CreateSystemCursor(SDL.SDL_SystemCursor.SDL_SYSTEM_CURSOR_SIZEWE);
            curResizeNESW = SDL.SDL_CreateSystemCursor(SDL.SDL_SystemCursor.SDL_SYSTEM_CURSOR_SIZENESW);
            curResizeNWSE = SDL.SDL_CreateSystemCursor(SDL.SDL_SystemCursor.SDL_SYSTEM_CURSOR_SIZENWSE);
            //Window sizing
            if (minWindowSize != Point.Zero)
            {
                SDL.SDL_SetWindowMinimumSize(sdlWin, minWindowSize.X, minWindowSize.Y);
            }
            if (sdlWin == IntPtr.Zero)
            {
                Dialogs.CrashWindow.Run("Librelancer", "Failed to create SDL window",
                                        "SDL Error: " + (SDL.SDL_GetError() ?? ""));
                return;
            }
            SDL.SDL_EventState(SDL.SDL_EventType.SDL_DROPFILE, SDL.SDL_ENABLE);
            windowptr = sdlWin;
            IntPtr glcontext = IntPtr.Zero;

            if (Environment.GetEnvironmentVariable("LIBRELANCER_RENDERER") == "GLES" ||
                !CreateContextCore(sdlWin, out glcontext))
            {
                if (!CreateContextES(sdlWin, out glcontext))
                {
                    Dialogs.CrashWindow.Run("Librelancer", "Failed to create OpenGL context",
                                            "Your driver or gpu does not support at least OpenGL 3.2 or OpenGL ES 3.1\n" + SDL.SDL_GetError() ?? "");
                    return;
                }
            }
            GL.LoadSDL();
            Renderer = string.Format("{0} ({1})", GL.GetString(GL.GL_VERSION), GL.GetString(GL.GL_RENDERER));
            FLLog.Info("GL", $"Renderer: {GL.GetString(GL.GL_RENDERER)}");
            SetVSync(true);
            //Init game state
            RenderContext = new RenderContext();
            SDL.SDL_GetWindowSize(sdlWin, out int windowWidth, out int windowHeight);
            SDL.SDL_GL_GetDrawableSize(sdlWin, out width, out height);
            var scaleW = (float)width / windowWidth;
            var scaleH = (float)height / windowHeight;

            if (Platform.RunningOS != OS.Windows)
            {
                DpiScale = scaleH;
            }
            else
            {
                if (SDL.SDL_GetDisplayDPI(0, out float ddpi, out _, out _) == 0)
                {
                    DpiScale = ddpi / 96.0f;
                }
            }
            FLLog.Info("GL", $"Dpi Scale: {DpiScale:F4}");
            Load();
            //kill the value we set so it doesn't crash child processes
            if (setMesaThread)
            {
                Environment.SetEnvironmentVariable("mesa_glthread", null);
            }
            //Start game
            running = true;
            timer   = new Stopwatch();
            timer.Start();
            double last    = 0;
            double elapsed = 0;

            SDL.SDL_Event e = new SDL.SDL_Event();
            SDL.SDL_StopTextInput();
            MouseButtons doRelease = 0;

            while (running)
            {
                //Window State
                var winFlags = (SDL.SDL_WindowFlags)SDL.SDL_GetWindowFlags(sdlWin);
                Focused = (winFlags & SDL.SDL_WindowFlags.SDL_WINDOW_MOUSE_FOCUS) ==
                          SDL.SDL_WindowFlags.SDL_WINDOW_MOUSE_FOCUS ||
                          (winFlags & SDL.SDL_WindowFlags.SDL_WINDOW_INPUT_FOCUS) ==
                          SDL.SDL_WindowFlags.SDL_WINDOW_INPUT_FOCUS;
                EventsThisFrame = false;
                //Get Size
                SDL.SDL_GetWindowSize(sdlWin, out windowWidth, out windowHeight);
                SDL.SDL_GL_GetDrawableSize(sdlWin, out width, out height);
                scaleW = (float)width / windowWidth;
                scaleH = (float)height / windowHeight;
                if (Platform.RunningOS != OS.Windows)
                {
                    DpiScale = scaleH;
                }
                //This allows for press/release in same frame to have
                //button down for one frame, e.g. trackpoint middle click on Linux/libinput.
                MouseButtons pressedThisFrame = 0;
                Mouse.Buttons &= ~doRelease;
                doRelease      = 0;
                bool eventWaited = false;
                if (waitForEvent)
                {
                    waitForEvent = false;
                    if (SDL.SDL_WaitEventTimeout(out e, 2000) != 0)
                    {
                        eventWaited = true;
                    }
                }
                Mouse.Wheel = 0;
                //Pump message queue
                while (eventWaited || SDL.SDL_PollEvent(out e) != 0)
                {
                    eventWaited     = false;
                    EventsThisFrame = true;
                    switch (e.type)
                    {
                    case SDL.SDL_EventType.SDL_QUIT:
                    {
                        if (WillClose != null)
                        {
                            WillClose();
                        }
                        running = false;         //TODO: Raise Event
                        break;
                    }

                    case SDL.SDL_EventType.SDL_MOUSEMOTION:
                    {
                        Mouse.X = (int)(scaleW * e.motion.x);
                        Mouse.Y = (int)(scaleH * e.motion.y);
                        Mouse.OnMouseMove();
                        break;
                    }

                    case SDL.SDL_EventType.SDL_MOUSEBUTTONDOWN:
                    {
                        Mouse.X = (int)(scaleW * e.button.x);
                        Mouse.Y = (int)(scaleH * e.button.y);
                        var btn = GetMouseButton(e.button.button);
                        Mouse.Buttons    |= btn;
                        pressedThisFrame |= btn;
                        Mouse.OnMouseDown(btn);
                        break;
                    }

                    case SDL.SDL_EventType.SDL_MOUSEBUTTONUP:
                    {
                        Mouse.X = (int)(scaleW * e.button.x);
                        Mouse.Y = (int)(scaleH * e.button.y);
                        var btn = GetMouseButton(e.button.button);
                        if ((pressedThisFrame & btn) == btn)
                        {
                            doRelease |= btn;
                        }
                        else
                        {
                            Mouse.Buttons &= ~btn;
                        }
                        Mouse.OnMouseUp(btn);
                        break;
                    }

                    case SDL.SDL_EventType.SDL_MOUSEWHEEL:
                    {
                        Mouse.Wheel += e.wheel.y;
                        break;
                    }

                    case SDL.SDL_EventType.SDL_TEXTINPUT:
                    {
                        Keyboard.OnTextInput(GetEventText(ref e));
                        break;
                    }

                    case SDL.SDL_EventType.SDL_KEYDOWN:
                    {
                        Keyboard.OnKeyDown((Keys)e.key.keysym.scancode, (KeyModifiers)e.key.keysym.mod, e.key.repeat != 0);
                        break;
                    }

                    case SDL.SDL_EventType.SDL_KEYUP:
                    {
                        Keyboard.OnKeyUp((Keys)e.key.keysym.scancode, (KeyModifiers)e.key.keysym.mod);
                        break;
                    }

                    case SDL.SDL_EventType.SDL_KEYMAPCHANGED:
                        KeysExtensions.ResetKeyNames();
                        break;

                    case SDL.SDL_EventType.SDL_WINDOWEVENT:
                        if (e.window.windowEvent == SDL.SDL_WindowEventID.SDL_WINDOWEVENT_RESIZED)
                        {
                            OnResize();
                        }
                        break;

                    case SDL.SDL_EventType.SDL_DROPFILE:
                    {
                        var file = UnsafeHelpers.PtrToStringUTF8(e.drop.file);
                        OnDrop(file);
                        SDL.SDL_free(e.drop.file);
                        break;
                    }
                    }
                }
                Mouse.Wheel /= 2.5f;
                //Do game things
                if (!running)
                {
                    break;
                }
                Action work;
                while (actions.TryDequeue(out work))
                {
                    work();
                }
                totalTime = timer.Elapsed.TotalSeconds;
                Update(elapsed);
                if (!running)
                {
                    break;
                }
                Draw(elapsed);
                RenderContext.EndFrame();
                //Frame time before, FPS after
                var tk = timer.Elapsed.TotalSeconds - totalTime;
                frameTime = CalcAverageTime(tk);
                if (_screenshot)
                {
                    TakeScreenshot();
                    _screenshot = false;
                }
                SDL.SDL_GL_SwapWindow(sdlWin);
                if (GL.FrameHadErrors()) //If there was a GL error, track it down.
                {
                    GL.ErrorChecking = true;
                }
                elapsed         = timer.Elapsed.TotalSeconds - last;
                renderFrequency = (1.0 / CalcAverageTick(elapsed));
                last            = timer.Elapsed.TotalSeconds;
                totalTime       = timer.Elapsed.TotalSeconds;
                if (elapsed < 0)
                {
                    elapsed = 0;
                    FLLog.Warning("Timing", "Stopwatch returned negative time!");
                }
            }
            Cleanup();
            SDL.SDL_Quit();
        }