Skip to content
66 changes: 46 additions & 20 deletions STROOP.Core/CoreLoop.cs
Original file line number Diff line number Diff line change
@@ -1,23 +1,36 @@
using System.Diagnostics;
using System.Runtime.InteropServices;
using Windows.Win32;

namespace STROOP.Core;

public class CoreLoop
{
private List<double> _fpsTimes = new List<double>();
private Queue<long> _frameTimes = new Queue<long>();
private byte[] _ram;
private object _mStreamProcess = new object();

public double FpsInPractice => _fpsTimes.Count == 0 ? 0 : 1 / _fpsTimes.Average();
public double lastFrameTime => _fpsTimes.Count == 0 ? double.NaN : _fpsTimes.Last();
public double FpsInPractice => _frameTimes.Count == 0 ? 0 : Stopwatch.Frequency / _frameTimes.Average();
public double lastFrameTime => _frameTimes.Count == 0 ? double.NaN : _frameTimes.Last() / (double)Stopwatch.Frequency;

public void Run(CancellationToken cancellationToken, Action handleEvents, Func<double> getTargetedFps)
public void Run(CancellationToken cancellationToken, Action handleEvents, Func<double> getTargetedRefreshRate)
{
Stopwatch frameStopwatch = Stopwatch.StartNew();
using var _ = new HighResTimer(1); // request ~1ms resolution

// since computation of the time to wait for takes time itself, compensate with a few ticks
const int BUFFER_TICKS = 1000;

long ticksPerTwoMs = 2 * Stopwatch.Frequency / 1000;

Stopwatch frameStopwatch = new Stopwatch();
Queue<long> extraTime = new Queue<long>();
extraTime.Enqueue(0);

while (!cancellationToken.IsCancellationRequested)
{
double timeToWait;
long ticksPerFrame = (long)(Stopwatch.Frequency * getTargetedRefreshRate());

frameStopwatch.Restart();
lock (_mStreamProcess)
{
ProcessStream.Instance.RefreshRam();
Expand All @@ -26,23 +39,36 @@ public void Run(CancellationToken cancellationToken, Action handleEvents, Func<d

handleEvents();

// Calculate delay to match correct FPS
frameStopwatch.Stop();
double timePassed = frameStopwatch.ElapsedTicks / (double)Stopwatch.Frequency;
timeToWait = getTargetedFps() - timePassed;
timeToWait = Math.Max(timeToWait, 0);
while (frameStopwatch.ElapsedTicks < ticksPerFrame - ticksPerTwoMs)
Thread.Sleep(1);
do
Thread.Yield();
while (frameStopwatch.ElapsedTicks < ticksPerFrame - extraTime.Average());

long frameTicks = frameStopwatch.ElapsedTicks;
// Calculate Fps
while (_fpsTimes.Count() >= 10)
_fpsTimes.RemoveAt(0);
_fpsTimes.Add(timePassed + timeToWait);

frameStopwatch.Restart();
while (_frameTimes.Count() >= 10)
_frameTimes.Dequeue();
_frameTimes.Enqueue(frameStopwatch.ElapsedTicks);

if (timeToWait > 0)
Thread.Sleep(new TimeSpan((long)(timeToWait * 10000000)));
else
Thread.Yield();
while (extraTime.Count() >= 10)
extraTime.Dequeue();
extraTime.Enqueue(frameStopwatch.ElapsedTicks - frameTicks + BUFFER_TICKS);
}
}
}
file class HighResTimer : IDisposable
{
readonly uint _period;

public HighResTimer(uint periodMs)
{
_period = periodMs;
PInvoke.timeBeginPeriod(_period);
}

public void Dispose()
{
PInvoke.timeEndPeriod(_period);
}
}
3 changes: 3 additions & 0 deletions STROOP.Win32/NativeMethods.txt
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
IsWow64Process

PSAPI_WORKING_SET_EX_INFORMATION
MEMORY_BASIC_INFORMATION

Check warning on line 15 in STROOP.Win32/NativeMethods.txt

View workflow job for this annotation

GitHub Actions / debug-build

This API is only available when targeting a specific CPU architecture. AnyCPU cannot generate this API.

CHARFORMAT2A
CFE_EFFECTS
Expand All @@ -24,3 +24,6 @@
GetAsyncKeyState
GetSystemMetrics
SYSTEM_METRICS_INDEX

timeBeginPeriod
timeEndPeriod
26 changes: 9 additions & 17 deletions STROOP/Tabs/MapTab/DataUtil/HoverDatas.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
using System.Collections.Generic;
using OpenTK.Mathematics;
using STROOP.Core;
using STROOP.Tabs.MapTab.Views;

namespace STROOP.Tabs.MapTab.MapObjects
{
Expand All @@ -22,13 +23,9 @@ public PointHoverData(MapObject parent)
this.parent = parent;
}

public virtual void LeftClick(Vector3 position)
{
}
public virtual void LeftClick(Vector3 position) { }

public virtual void RightClick(Vector3 position)
{
}
public virtual void RightClick(Vector3 position) { }

public virtual DragMask CanDrag() => parent.dragMask;

Expand All @@ -45,11 +42,8 @@ public void DragTo(Vector3 newPosition, bool setY)
SetPosition(newPosition);
}

public virtual void Pivot(MapTab tab)
{
tab.graphics.view.camera3DMode = MapView.Camera3DMode.FocusOnPositionAngle;
tab.graphics.view.focusPositionAngle = PositionAngle.Custom(GetPosition(), 0);
}
protected virtual void Pivot(MapTab tab)
=> (tab.graphics.currentView as PivotingView)?.Pivot(PositionAngle.Custom(GetPosition(), 0));

public virtual void AddContextMenuItems(MapTab tab, ContextMenuStrip menu)
{
Expand Down Expand Up @@ -114,7 +108,7 @@ public virtual void AddContextMenuItems(MapTab tab, ContextMenuStrip menu)
);
myItem.DropDownItems.Add(makeReferencePointItem);

if (tab.graphics.view.mode != MapView.ViewMode.TopDown)
if (tab.graphics.viewMode != MapGraphics.ViewMode.TopDown)
{
var pivotItem = new ToolStripMenuItem("Make Pivot Point");
pivotItem.Click += (_, __) => Pivot(tab);
Expand All @@ -129,9 +123,7 @@ protected class MapObjectHoverData : PointHoverData, IPositionCalculatorProvider
{
public PositionAngle currentPositionAngle;

public MapObjectHoverData(MapObject parent) : base(parent)
{
}
public MapObjectHoverData(MapObject parent) : base(parent) { }

protected override void SetPosition(Vector3 position)
{
Expand All @@ -144,11 +136,11 @@ protected override void SetPosition(Vector3 position)

protected override Vector3 GetPosition() => currentPositionAngle?.position ?? Vector3.Zero;

public override void Pivot(MapTab tab)
protected override void Pivot(MapTab tab)
{
if (currentPositionAngle == null)
return;
tab.graphics.view.Pivot(currentPositionAngle);
(tab.graphics.currentView as PivotingView)?.Pivot(currentPositionAngle);
}

public override string ToString() => currentPositionAngle.ToString();
Expand Down
34 changes: 17 additions & 17 deletions STROOP/Tabs/MapTab/MapGraphics.LegacyControlScheme.cs
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,7 @@ private void UpdateCenter()
if (!isMainMap)
return;

if (view.mode == MapView.ViewMode.ThreeDimensional)
if (viewMode == ViewMode.ThreeDimensional)
return;

if (mapTab.radioButtonMapControllersCenterBestFit.Checked)
Expand All @@ -93,14 +93,14 @@ private void UpdateCenter()
{
case MapCenter.BestFit:
RectangleF rectangle = MapViewScaleWasCourseDefault ? mapTab.GetMapLayout().Coordinates : MAX_COURSE_SIZE;
view.position.X = rectangle.X + rectangle.Width / 2;
view.position.Z = rectangle.Y + rectangle.Height / 2;
currentView.position.X = rectangle.X + rectangle.Width / 2;
currentView.position.Z = rectangle.Y + rectangle.Height / 2;
break;
case MapCenter.Origin:
view.position = new Vector3(0.5f);
currentView.position = new Vector3(0.5f);
break;
case MapCenter.Mario:
view.position = new Vector3(Config.Stream.GetSingle(MarioConfig.StructAddress + MarioConfig.XOffset),
currentView.position = new Vector3(Config.Stream.GetSingle(MarioConfig.StructAddress + MarioConfig.XOffset),
Config.Stream.GetSingle(MarioConfig.StructAddress + MarioConfig.YOffset),
Config.Stream.GetSingle(MarioConfig.StructAddress + MarioConfig.ZOffset));
break;
Expand All @@ -109,36 +109,36 @@ private void UpdateCenter()
mapTab.textBoxMapControllersCenterCustom.LastSubmittedText);
if (posAngle != null)
{
view.position = posAngle.position;
currentView.position = posAngle.position;
break;
}

List<string> stringValues = ParsingUtilities.ParseStringList(
mapTab.textBoxMapControllersCenterCustom.LastSubmittedText, replaceComma: false);
if (stringValues.Count >= 3)
{
view.position.X = ParsingUtilities.ParseFloatNullable(stringValues[0]) ?? 0;
view.position.Y = ParsingUtilities.ParseFloatNullable(stringValues[1]) ?? 0;
view.position.Z = ParsingUtilities.ParseFloatNullable(stringValues[2]) ?? 0;
currentView.position.X = ParsingUtilities.ParseFloatNullable(stringValues[0]) ?? 0;
currentView.position.Y = ParsingUtilities.ParseFloatNullable(stringValues[1]) ?? 0;
currentView.position.Z = ParsingUtilities.ParseFloatNullable(stringValues[2]) ?? 0;
}
else if (stringValues.Count >= 2)
{
view.position.X = ParsingUtilities.ParseFloatNullable(stringValues[0]) ?? 0;
view.position.Z = ParsingUtilities.ParseFloatNullable(stringValues[1]) ?? 0;
currentView.position.X = ParsingUtilities.ParseFloatNullable(stringValues[0]) ?? 0;
currentView.position.Z = ParsingUtilities.ParseFloatNullable(stringValues[1]) ?? 0;
}
else if (stringValues.Count == 1)
{
view.position = new Vector3(ParsingUtilities.ParseFloatNullable(stringValues[0]) ?? 0);
currentView.position = new Vector3(ParsingUtilities.ParseFloatNullable(stringValues[0]) ?? 0);
}
else
view.position = new Vector3();
currentView.position = new Vector3();

break;
}

if (MapViewCenter != MapCenter.Custom)
{
mapTab.textBoxMapControllersCenterCustom.SubmitTextLoosely($"{view.position.X}; {view.position.Y}; {view.position.Z}");
mapTab.textBoxMapControllersCenterCustom.SubmitTextLoosely($"{currentView.position.X}; {currentView.position.Y}; {currentView.position.Z}");
}
}

Expand Down Expand Up @@ -243,9 +243,9 @@ public void ChangeCenter(int xSign, int zSign, object value)
(float xOffsetRotated, float zOffsetRotated) = ((float, float))MoreMath.RotatePointAboutPointAnAngularDistance(
xOffset, zOffset, 0, 0, MapViewAngleValue);
float multiplier = MapViewCenterChangeByPixels ? 1 / MapViewScaleValue : 1;
float newCenterXValue = view.position.X + xOffsetRotated * multiplier;
float newCenterZValue = view.position.Z + zOffsetRotated * multiplier;
mapTab.textBoxMapControllersCenterCustom.SubmitText($"{newCenterXValue}; {view.position.Y}; {newCenterZValue}");
float newCenterXValue = currentView.position.X + xOffsetRotated * multiplier;
float newCenterZValue = currentView.position.Z + zOffsetRotated * multiplier;
mapTab.textBoxMapControllersCenterCustom.SubmitText($"{newCenterXValue}; {currentView.position.Y}; {newCenterZValue}");
}

public void ChangeAngle(int sign, object value)
Expand Down
Loading
Loading