public void RequestDock(Player player, string nickname) { actions.Enqueue(() => { var obj = Players[player]; FLLog.Info("Server", $"{player.Name} requested dock at {nickname}"); var dock = GameWorld.Objects.FirstOrDefault(x => x.Nickname.Equals(nickname, StringComparison.OrdinalIgnoreCase)); if (dock == null) { FLLog.Warning("Server", $"Dock object {nickname} does not exist."); } else { var component = dock.GetComponent <SDockableComponent>(); if (component == null) { FLLog.Warning("Server", $"object {nickname} is not dockable."); } else { component.StartDock(obj, 0); } } }); }
public void Update(TimeSpan delta) { int counter = 0; accumTime += delta.TotalSeconds; while (accumTime > (1.0 / 120.0)) { _Update(TimeSpan.FromSeconds(TIMESTEP)); accumTime -= TIMESTEP; counter++; if (counter > MAX_STEPS) { // okay, okay... we can't keep up FLLog.Warning("Thn", "Can't keep up!"); accumTime = 0.0f; break; } } if (Running) { var pos = camera.Transform.Position; game.Sound.SetListenerParams(pos); } }
public void ActivateTrigger(string trigger) { var t = Script.AvailableTriggers[trigger]; foreach (var cond in t.Conditions) { if (cond.Type == TriggerConditions.Cnd_ProjHit) { Player.WorldAction(() => { var obj = Player.World.GameWorld.GetObject(cond.Entry[0].ToString()); if (obj != null) { obj.GetComponent <SNPCComponent>().ProjectileHitHook = ProjectileHit; } else { FLLog.Warning("Mission", $"Cnd_ProjHit won't register for not spawned {cond.Entry[0]}"); } }); } } activeTriggers.Add(new ActiveTrigger() { Trigger = t, Conditions = new List <MissionCondition>(t.Conditions) }); }
public MaterialMap() { if (_instance != null) { FLLog.Warning("MaterialMap", "Switching global material map. TODO make instance"); } _instance = this; }
public override VMeshData FindMesh(uint vMeshLibId) { VMeshData vms; meshes.TryGetValue(vMeshLibId, out vms); if (vms == null) { FLLog.Warning("ResourceManager", "Mesh " + vMeshLibId + " not found"); } return(vms); }
//Set only the first one //Without this, order ships spawn in the wrong place in M01A static void Set <T>(Dictionary <string, T> dict, string k, T value) { if (!dict.ContainsKey(k)) { dict[k] = value; } else { FLLog.Warning("Mission", $"Duplicate {typeof(T)} `{k}`, ignoring."); } }
public void QueueOrientation(uint ms, Quaternion orient) { uint lastMs = 0; if (orientBuffer.Count > 0) { lastMs = orientBuffer.Peek().Tick; } receivedOrientTime += SeqDiff(ms, lastMs); if (orientBuffer.Count == orientBuffer.Capacity) { FLLog.Warning("Net", "Something bad happened lerp orient"); receivedOrientTime = 0; orientBuffer.Clear(); } orientBuffer.Enqueue(new OrientState() { Tick = ms, Orient = orient }); }
public void QueuePosition(uint ms, Vector3 pos) { uint lastMs = 0; if (posBuffer.Count > 0) { lastMs = posBuffer.Peek().Tick; } receivedPosTime += SeqDiff(ms, lastMs); if (posBuffer.Count == posBuffer.Capacity) { FLLog.Warning("Net", "Something bad happened lerp pos"); receivedPosTime = 0; posBuffer.Clear(); } posBuffer.Enqueue(new PosState() { Tick = ms, Pos = pos }); }
public void Update(TimeSpan delta) { int counter = 0; accumTime += delta.TotalSeconds; while (accumTime > (1.0 / 120.0)) { _Update(TimeSpan.FromSeconds(TIMESTEP)); accumTime -= TIMESTEP; counter++; if (counter > MAX_STEPS) { // okay, okay... we can't keep up FLLog.Warning("Thn", "Can't keep up!"); accumTime = 0.0f; break; } } }
public void Run() { SSEMath.Load(); 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_CONTEXT_MAJOR_VERSION, 3); SDL.SDL_GL_SetAttribute(SDL.SDL_GLattr.SDL_GL_CONTEXT_MINOR_VERSION, 2); SDL.SDL_GL_SetAttribute(SDL.SDL_GLattr.SDL_GL_CONTEXT_PROFILE_MASK, (int)SDL.SDL_GLprofile.SDL_GL_CONTEXT_PROFILE_CORE); 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; 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) { FLLog.Error("SDL", "Failed to create window, exiting."); return; } windowptr = sdlWin; if (forceANGLE) { LoadANGLE(); } else { var glcontext = SDL.SDL_GL_CreateContext(sdlWin); bool check = GL.CheckStringSDL(); if (!check) { FLLog.Warning("GL", "GL Version Insufficient - Using DX9"); SDL.SDL_GL_DeleteContext(glcontext); } if (glcontext == IntPtr.Zero || !check) { if (Platform.RunningOS == OS.Windows) { LoadANGLE(); } else { FLLog.Error("OpenGL", "Failed to create OpenGL context, exiting."); return; } } else { GL.LoadSDL(); Renderer = string.Format("{0} ({1})", GL.GetString(GL.GL_VERSION), GL.GetString(GL.GL_RENDERER)); } } SetVSync(true); //Init game state RenderState = new RenderState(); Load(); //Start game running = true; var timer = new Stopwatch(); timer.Start(); double last = 0; double elapsed = 0; SDL.SDL_Event e; SDL.SDL_StopTextInput(); while (running) { //Pump message queue while (SDL.SDL_PollEvent(out e) != 0) { 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 = e.motion.x; Mouse.Y = e.motion.y; Mouse.OnMouseMove(); break; } case SDL.SDL_EventType.SDL_MOUSEBUTTONDOWN: { Mouse.X = e.button.x; Mouse.Y = e.button.y; var btn = GetMouseButton(e.button.button); Mouse.Buttons |= btn; Mouse.OnMouseDown(btn); break; } case SDL.SDL_EventType.SDL_MOUSEBUTTONUP: { Mouse.X = e.button.x; Mouse.Y = e.button.y; var btn = GetMouseButton(e.button.button); Mouse.Buttons &= ~btn; Mouse.OnMouseUp(btn); break; } case SDL.SDL_EventType.SDL_MOUSEWHEEL: { Mouse.OnMouseWheel(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.sym, (KeyModifiers)e.key.keysym.mod, e.key.repeat != 0); break; } case SDL.SDL_EventType.SDL_KEYUP: { Keyboard.OnKeyUp((Keys)e.key.keysym.sym, (KeyModifiers)e.key.keysym.mod); break; } case SDL.SDL_EventType.SDL_WINDOWEVENT: if (e.window.windowEvent == SDL.SDL_WindowEventID.SDL_WINDOWEVENT_RESIZED) { SDL.SDL_GetWindowSize(windowptr, out width, out height); } break; } } //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); //Frame time before, FPS after var tk = timer.Elapsed.TotalSeconds - totalTime; frameTime = CalcAverageTime(tk); if (_screenshot) { TakeScreenshot(); _screenshot = false; } if (angle != null) { angle.SwapBuffers(); } else { 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(); }
public void Process(ThnEvent ev, Cutscene cs) { if (!cs.Objects.ContainsKey((string)ev.Targets[0])) { FLLog.Error("Thn", $"Entity {ev.Targets[0]} does not exist"); return; } var obj = cs.Objects[(string)ev.Targets[0]]; if (obj.Light == null) { FLLog.Error("Thn", $"Entity {ev.Targets[0]} is not a light"); return; } object tmp; LuaTable lightprops; if (ev.Properties.TryGetValue("lightprops", out tmp)) { lightprops = (LuaTable)tmp; } else { FLLog.Warning("Thn", "Light prop animation with no properties"); return; } Vector3 vtmp; Color3f?targetDiffuse = null; Color3f?targetAmbient = null; if (lightprops.TryGetValue("on", out tmp)) { obj.Light.Active = ThnEnum.Check <bool>(tmp); } if (lightprops.TryGetVector3("diffuse", out vtmp)) { targetDiffuse = new Color3f(vtmp); if (ev.Duration <= 0) { obj.Light.Light.Color = new Color3f(vtmp); } } if (lightprops.TryGetVector3("ambient", out vtmp)) { targetAmbient = new Color3f(vtmp); if (ev.Duration <= 0) { obj.Light.Light.Ambient = new Color3f(vtmp); } } if (ev.Duration > 0) { cs.Coroutines.Add(new AnimLightProp() { Source = obj.Light.Light, Target = obj.Light, TargetDiffuse = targetDiffuse, TargetAmbient = targetAmbient, Duration = ev.Duration, ParamCurve = ev.ParamCurve }); } }
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(); }
public void Run() { FLLog.Info("Engine", "Version: " + Platform.GetInformationalVersion <Game>()); //TODO: This makes i5-7200U on mesa 18 faster, but this should probably be a configurable option 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_CONTEXT_MAJOR_VERSION, 3); SDL.SDL_GL_SetAttribute(SDL.SDL_GLattr.SDL_GL_CONTEXT_MINOR_VERSION, 2); SDL.SDL_GL_SetAttribute(SDL.SDL_GLattr.SDL_GL_CONTEXT_PROFILE_MASK, (int)SDL.SDL_GLprofile.SDL_GL_CONTEXT_PROFILE_CORE); 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; 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) { FLLog.Error("SDL", "Failed to create window, exiting."); return; } SDL.SDL_EventState(SDL.SDL_EventType.SDL_DROPFILE, SDL.SDL_ENABLE); windowptr = sdlWin; var glcontext = SDL.SDL_GL_CreateContext(sdlWin); if (glcontext == IntPtr.Zero || !GL.CheckStringSDL()) { SDL.SDL_GL_DeleteContext(glcontext); if (Platform.RunningOS == OS.Windows) { SDL.SDL_ShowSimpleMessageBox(SDL.SDL_MessageBoxFlags.SDL_MESSAGEBOX_ERROR, "Librelancer", "Failed to create OpenGL context, exiting.", IntPtr.Zero); } FLLog.Error("OpenGL", "Failed to create OpenGL context, exiting."); return; } else { GL.LoadSDL(); Renderer = string.Format("{0} ({1})", GL.GetString(GL.GL_VERSION), GL.GetString(GL.GL_RENDERER)); } SetVSync(true); //Init game state RenderState = new RenderState(); Load(); //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; //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; } } //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 = e.motion.x; Mouse.Y = e.motion.y; Mouse.OnMouseMove(); break; } case SDL.SDL_EventType.SDL_MOUSEBUTTONDOWN: { Mouse.X = e.button.x; Mouse.Y = 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 = e.button.x; Mouse.Y = 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.OnMouseWheel(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) { SDL.SDL_GetWindowSize(windowptr, out width, out height); OnResize(); } break; case SDL.SDL_EventType.SDL_DROPFILE: { var file = UnsafeHelpers.PtrToStringUTF8(e.drop.file); OnDrop(file); SDL.SDL_free(e.drop.file); break; } } } //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); //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(); }
void AddEntities(ThnScript thn) { foreach (var kv in thn.Entities) { if (Objects.ContainsKey(kv.Key)) { continue; } if ((kv.Value.ObjectFlags & ThnObjectFlags.Reference) == ThnObjectFlags.Reference) { continue; } var obj = new ThnObject(); obj.Name = kv.Key; obj.Translate = kv.Value.Position ?? Vector3.Zero; obj.Rotate = kv.Value.RotationMatrix ?? Matrix4x4.Identity; //PlayerShip object if (spawnObjects && scriptContext.PlayerShip != null && kv.Value.Type == EntityTypes.Compound && kv.Value.Template.Equals("playership", StringComparison.InvariantCultureIgnoreCase)) { obj.Object = scriptContext.PlayerShip; obj.Object.RenderComponent.LitDynamic = (kv.Value.ObjectFlags & ThnObjectFlags.LitDynamic) == ThnObjectFlags.LitDynamic; obj.Object.RenderComponent.LitAmbient = (kv.Value.ObjectFlags & ThnObjectFlags.LitAmbient) == ThnObjectFlags.LitAmbient; obj.Object.RenderComponent.NoFog = kv.Value.NoFog; ((ModelRenderer)obj.Object.RenderComponent).LightGroup = kv.Value.LightGroup; obj.Entity = kv.Value; Vector3 transform = kv.Value.Position ?? Vector3.Zero; obj.Object.Transform = (kv.Value.RotationMatrix ?? Matrix4x4.Identity) * Matrix4x4.CreateTranslation(transform); obj.HpMount = scriptContext.PlayerShip.GetHardpoint("HpMount"); World.Objects.Add(obj.Object); Objects.Add(kv.Key, obj); continue; } var template = kv.Value.Template; string replacement; if (scriptContext != null && scriptContext.Substitutions.TryGetValue(kv.Value.Template, out replacement)) { template = replacement; } var resman = game.GetService <ResourceManager>(); if (spawnObjects && kv.Value.Type == EntityTypes.Compound) { bool getHpMount = false; //Fetch model IDrawable drawable = null; if (!string.IsNullOrEmpty(template)) { switch (kv.Value.MeshCategory.ToLowerInvariant()) { case "solar": drawable = gameData.GetSolar(template); break; case "ship": case "spaceship": getHpMount = true; var sh = gameData.GetShip(template); drawable = sh.ModelFile.LoadFile(resman); break; case "prop": drawable = gameData.GetProp(template); break; case "room": drawable = gameData.GetRoom(template); break; case "equipment cart": drawable = gameData.GetCart(template); break; case "equipment": var eq = gameData.GetEquipment(template); drawable = eq?.ModelFile.LoadFile(resman); break; case "asteroid": drawable = gameData.GetAsteroid(kv.Value.Template); break; default: throw new NotImplementedException("Mesh Category " + kv.Value.MeshCategory); } } else { FLLog.Warning("Thn", $"object '{kv.Value.Name}' has empty template, category " + $"'{kv.Value.MeshCategory}'"); } drawable?.Initialize(resman); if (kv.Value.UserFlag != 0) { //This is a starsphere layers.Add(new Tuple <IDrawable, ThnObject>(drawable, obj)); } else { obj.Object = new GameObject(drawable, game.GetService <ResourceManager>(), true, false, false); obj.Object.Name = kv.Value.Name; obj.Object.PhysicsComponent = null; //Jitter seems to interfere with directly setting orientation if (getHpMount) { obj.HpMount = obj.Object.GetHardpoint("HpMount"); } var r = (ModelRenderer)obj.Object.RenderComponent; if (r != null) { r.LightGroup = kv.Value.LightGroup; r.LitDynamic = (kv.Value.ObjectFlags & ThnObjectFlags.LitDynamic) == ThnObjectFlags.LitDynamic; r.LitAmbient = (kv.Value.ObjectFlags & ThnObjectFlags.LitAmbient) == ThnObjectFlags.LitAmbient; //HIDDEN just seems to be an editor flag? //r.Hidden = (kv.Value.ObjectFlags & ThnObjectFlags.Hidden) == ThnObjectFlags.Hidden; r.NoFog = kv.Value.NoFog; } } } else if (kv.Value.Type == EntityTypes.PSys) { var fx = gameData.GetEffect(kv.Value.Template); if (fx != null) { obj.Object = new GameObject(); obj.Object.RenderComponent = new ParticleEffectRenderer(fx.GetEffect(resman)) { Active = false }; } } else if (kv.Value.Type == EntityTypes.Scene) { if (kv.Value.DisplayText != null) { text = kv.Value.DisplayText; } if (hasScene) { //throw new Exception("Thn can only have one scene"); //TODO: This needs to be handled better continue; } var amb = kv.Value.Ambient.Value; if (amb.X == 0 && amb.Y == 0 && amb.Z == 0) { continue; } hasScene = true; Renderer.SystemLighting.Ambient = new Color4(amb.X / 255f, amb.Y / 255f, amb.Z / 255f, 1); } else if (kv.Value.Type == EntityTypes.Light) { var lt = new DynamicLight(); lt.LightGroup = kv.Value.LightGroup; lt.Active = kv.Value.LightProps.On; lt.Light = kv.Value.LightProps.Render; obj.Light = lt; obj.LightDir = lt.Light.Direction; if (kv.Value.RotationMatrix.HasValue) { var m = kv.Value.RotationMatrix.Value; lt.Light.Direction = Vector3.TransformNormal(lt.Light.Direction, m); } if (Renderer != null) { Renderer.SystemLighting.Lights.Add(lt); } } else if (kv.Value.Type == EntityTypes.Camera) { obj.Camera = new ThnCameraTransform(); obj.Camera.Position = kv.Value.Position.Value; obj.Camera.Orientation = kv.Value.RotationMatrix ?? Matrix4x4.Identity; obj.Camera.FovH = kv.Value.FovH ?? obj.Camera.FovH; obj.Camera.AspectRatio = kv.Value.HVAspect ?? obj.Camera.AspectRatio; if (kv.Value.NearPlane != null) { obj.Camera.Znear = kv.Value.NearPlane.Value; } if (kv.Value.FarPlane != null) { obj.Camera.Zfar = kv.Value.FarPlane.Value; } } else if (kv.Value.Type == EntityTypes.Marker) { obj.Object = new GameObject(); obj.Object.Name = "Marker"; obj.Object.Nickname = ""; } else if (kv.Value.Type == EntityTypes.Deformable) { obj.Object = new GameObject(); gameData.GetCostume(template, out DfmFile body, out DfmFile head, out DfmFile leftHand, out DfmFile rightHand); var skel = new DfmSkeletonManager(body, head, leftHand, rightHand); obj.Object.RenderComponent = new CharacterRenderer(skel); var anmComponent = new AnimationComponent(obj.Object, gameData.GetCharacterAnimations()); obj.Object.AnimationComponent = anmComponent; obj.Object.Components.Add(anmComponent); } else if (kv.Value.Type == EntityTypes.Sound) { obj.Sound = new ThnSound(kv.Value.Template, game.GetService <SoundManager>(), kv.Value.AudioProps, obj); obj.Sound.Spatial = (kv.Value.ObjectFlags & ThnObjectFlags.SoundSpatial) == ThnObjectFlags.SoundSpatial; } if (obj.Object != null) { Vector3 transform = kv.Value.Position ?? Vector3.Zero; obj.Object.Transform = (kv.Value.RotationMatrix ?? Matrix4x4.Identity) * Matrix4x4.CreateTranslation(transform); World.Objects.Add(obj.Object); } obj.Entity = kv.Value; Objects[kv.Key] = obj; } }
void InitWithDrawable(IDrawable drawable, ResourceManager res, bool staticpos) { Resources = res; dr = drawable; Shape collisionShape = null; bool isCmp = false; if (dr is SphFile) { var radius = ((SphFile)dr).Radius; collisionShape = new SphereShape(radius); } else if (dr is ModelFile) { var mdl = dr as ModelFile; var path = Path.ChangeExtension(mdl.Path, "sur"); if (File.Exists(path)) { SurFile sur = res.GetSur(path); var shs = new List <CompoundSurShape.TransformedShape>(); foreach (var s in sur.GetShape(0)) { shs.Add(new CompoundSurShape.TransformedShape(s, Matrix3.Identity, Vector3.Zero)); } collisionShape = new CompoundSurShape(shs); } } else if (dr is CmpFile) { isCmp = true; var cmp = dr as CmpFile; CmpParts = new List <Part>(); CmpConstructs = cmp.Constructs.CloneAll(); foreach (var part in cmp.Parts.Values) { CmpParts.Add(part.Clone(CmpConstructs)); } if (cmp.Animation != null) { AnimationComponent = new AnimationComponent(this, cmp.Animation); Components.Add(AnimationComponent); } var path = Path.ChangeExtension(cmp.Path, "sur"); if (File.Exists(path)) { SurFile sur = res.GetSur(path); var shapes = new List <CompoundSurShape.TransformedShape>(); foreach (var part in CmpParts) { var crc = CrcTool.FLModelCrc(part.ObjectName); if (!sur.HasShape(crc)) { FLLog.Warning("Sur", "No hitbox for " + part.ObjectName); continue; } var colshape = sur.GetShape(crc); if (part.Construct == null) { foreach (var s in colshape) { shapes.Add(new CompoundSurShape.TransformedShape(s, Matrix3.Identity, Vector3.Zero)); } } else { var tr = part.Construct.Transform; var pos = tr.ExtractTranslation(); var q = tr.ExtractRotation(true); var rot = Matrix3.CreateFromQuaternion(q); foreach (var s in colshape) { shapes.Add(new CompoundSurShape.TransformedShape(s, rot, pos) { Tag = part.Construct }); } } } collisionShape = new CompoundSurShape(shapes); } } if (collisionShape != null) { PhysicsComponent = new RigidBody(collisionShape); PhysicsComponent.Tag = this; PhysicsComponent.IsStatic = staticpos; if (staticpos) { PhysicsComponent.Material.Restitution = 1; } } PopulateHardpoints(dr); if (isCmp) { RenderComponent = new ModelRenderer(CmpParts, (dr as CmpFile)); } else { RenderComponent = new ModelRenderer(dr); } }
void CalculateBillboards() { Vector3 position; BoundingFrustum frustum; billboardCount = 0; lock (_camera) { position = _camera.Position; frustum = _camera.Frustum; } var close = AsteroidFieldShared.GetCloseCube(cameraPos, field.FillDist * 2); var checkRad = field.FillDist + field.BillboardSize.Y; int checkCount = 0; for (var x = -1; x <= 1; x++) { for (int y = -1; y <= 1; y++) { for (int z = -1; z <= 1; z++) { var center = close + new Vector3(x, y, z) * (field.FillDist * 2); //early bail for billboards too far if (Vector3.Distance(position, center) - checkRad > field.FillDist) { continue; } //bail billboards outside of zone - avoids popping if (field.Zone.Shape.ScaledDistance(center) > 1.1f) { continue; } //rotate var rotation = AsteroidCubeRotation.Default.GetRotation(AsteroidFieldShared.PositionHash(center)); for (int i = 0; i < billboardCube.Length; i++) { var spritepos = center + Vector3.Transform(billboardCube[i].Position, rotation); //cull individual billboards too far if (Vector3.Distance(position, spritepos) > field.FillDist) { continue; } billboardBuffer[checkCount] = billboardCube[i]; billboardBuffer[checkCount].Position = spritepos; billboardBuffer[checkCount++].Distance = Vector3.DistanceSquared(center, cameraPos); } } } } //Highly unlikely this check will succeed. If it does there's something wrong with the cube code if (checkCount > field.BillboardCount) { if (!warnedTooManyBillboards) { warnedTooManyBillboards = true; FLLog.Warning("Asteroids", "Too many billboards in sort task for field " + field.Zone.Nickname); } Array.Sort(billboardBuffer, 0, checkCount); //Get closest checkCount = field.BillboardCount; } //Cull ones that aren't on screen for (int i = 0; i < checkCount; i++) { var billboard = billboardBuffer[i]; var sphere = new BoundingSphere(billboard.Position, billboard.Size * 1.5f); if (!frustum.Intersects(sphere)) { continue; } calculatedBillboards[billboardCount++] = billboard; } }