mirror of
https://github.com/Stone-Red-Code/StoneRed.LogicSimulator.git
synced 2026-09-04 00:56:23 +02:00
Implement new simulator
This commit is contained in:
@@ -1,25 +1,20 @@
|
||||
using Microsoft.Xna.Framework.Graphics;
|
||||
|
||||
using StoneRed.LogicSimulator.Api.Utilities;
|
||||
using StoneRed.LogicSimulator.Simulation;
|
||||
|
||||
namespace StoneRed.LogicSimulator.Api;
|
||||
#pragma warning disable S112 // General exceptions should never be thrown
|
||||
|
||||
internal abstract class LogicGate
|
||||
{
|
||||
private readonly List<LogicGateConnection> logicGateConnections = new();
|
||||
private bool logicGateConnectionsChnaged = false;
|
||||
private int currentInput;
|
||||
private int newInput;
|
||||
private int output;
|
||||
private int cachedOutput;
|
||||
private LogicGateConnection[] logicGateConnectionsArray = Array.Empty<LogicGateConnection>();
|
||||
private readonly List<LogicGateConnection> logicGateConnections = [];
|
||||
public abstract int OutputCount { get; set; }
|
||||
public abstract int InputCount { get; set; }
|
||||
internal IReadOnlyList<LogicGateConnection> LogicGateConnections => logicGateConnections.AsReadOnly();
|
||||
internal GraphicsDevice? GraphicsDevice { get; set; }
|
||||
internal LogicGateWorldData WorldData { get; init; } = new LogicGateWorldData();
|
||||
internal ulong Id { get; set; }
|
||||
internal int SimulatorGateId { get; set; } = -1;
|
||||
|
||||
public override bool Equals(object? obj)
|
||||
{
|
||||
@@ -32,44 +27,14 @@ internal abstract class LogicGate
|
||||
return Id.GetHashCode();
|
||||
}
|
||||
|
||||
internal void NextTick()
|
||||
{
|
||||
currentInput = newInput;
|
||||
newInput = 0;
|
||||
output = 0;
|
||||
}
|
||||
|
||||
internal void SetInput(int value, int index)
|
||||
{
|
||||
if (index >= InputCount)
|
||||
{
|
||||
throw new IndexOutOfRangeException();
|
||||
}
|
||||
|
||||
// Inputs should act as or gates
|
||||
|
||||
if (value == 1)
|
||||
{
|
||||
newInput.SetBit(1, index);
|
||||
}
|
||||
}
|
||||
|
||||
internal void Connect(LogicGate logicGate, int inputIndex, int outputIndex)
|
||||
{
|
||||
if (inputIndex >= logicGate.InputCount)
|
||||
{
|
||||
throw new IndexOutOfRangeException();
|
||||
}
|
||||
|
||||
if (outputIndex >= OutputCount)
|
||||
{
|
||||
throw new IndexOutOfRangeException();
|
||||
}
|
||||
ArgumentOutOfRangeException.ThrowIfGreaterThanOrEqual(inputIndex, logicGate.InputCount);
|
||||
ArgumentOutOfRangeException.ThrowIfGreaterThanOrEqual(outputIndex, OutputCount);
|
||||
|
||||
lock (logicGateConnections)
|
||||
{
|
||||
logicGateConnections.Add(new LogicGateConnection(logicGate, inputIndex, outputIndex));
|
||||
logicGateConnectionsChnaged = true;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -93,89 +58,24 @@ internal abstract class LogicGate
|
||||
(!inputIndex.HasValue || c.InputIndex == inputIndex) &&
|
||||
(!outputIndex.HasValue || c.OutputIndex == outputIndex));
|
||||
logicGateConnections.RemoveAt(index);
|
||||
logicGateConnectionsChnaged = true;
|
||||
}
|
||||
}
|
||||
|
||||
internal void Update()
|
||||
{
|
||||
Execute();
|
||||
cachedOutput = output;
|
||||
PublishOutput();
|
||||
}
|
||||
|
||||
internal int GetCachedOutputBit(int index)
|
||||
{
|
||||
if (index < 0 || index >= OutputCount)
|
||||
{
|
||||
throw new IndexOutOfRangeException();
|
||||
}
|
||||
|
||||
return cachedOutput.GetBit(index);
|
||||
}
|
||||
|
||||
protected internal virtual void Initialize()
|
||||
{ }
|
||||
|
||||
protected abstract void Execute();
|
||||
|
||||
protected int GetInputBit(int index)
|
||||
{
|
||||
if (index < 0 || index >= InputCount)
|
||||
{
|
||||
throw new IndexOutOfRangeException();
|
||||
}
|
||||
|
||||
return currentInput.GetBit(index);
|
||||
}
|
||||
|
||||
protected void SetOutputBit(int value, int index)
|
||||
{
|
||||
if (index < 0 || index >= OutputCount)
|
||||
{
|
||||
throw new IndexOutOfRangeException();
|
||||
}
|
||||
|
||||
output.SetBit(value, index);
|
||||
}
|
||||
protected internal abstract void Register(ICircuitSimulator circuitSimulator);
|
||||
|
||||
protected Texture2D CreateTexture(int width, int height)
|
||||
{
|
||||
return new Texture2D(GraphicsDevice, width, height);
|
||||
}
|
||||
|
||||
private void PublishOutput()
|
||||
{
|
||||
if (logicGateConnectionsChnaged)
|
||||
{
|
||||
lock (logicGateConnections)
|
||||
{
|
||||
logicGateConnectionsArray = logicGateConnections.ToArray();
|
||||
logicGateConnectionsChnaged = false;
|
||||
}
|
||||
}
|
||||
|
||||
for (int i = 0; i < logicGateConnectionsArray.Length; i++)
|
||||
{
|
||||
LogicGateConnection connection = logicGateConnectionsArray[i];
|
||||
connection.LogicGate.SetInput(output.GetBit(connection.OutputIndex), connection.InputIndex);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#pragma warning restore S112 // General exceptions should never be thrown
|
||||
|
||||
internal class LogicGateConnection
|
||||
internal class LogicGateConnection(LogicGate logicGate, int inputIndex, int outputIndex)
|
||||
{
|
||||
public LogicGate LogicGate { get; }
|
||||
public LogicGate LogicGate { get; } = logicGate;
|
||||
|
||||
public int InputIndex { get; }
|
||||
public int OutputIndex { get; }
|
||||
|
||||
public LogicGateConnection(LogicGate logicGate, int inputIndex, int outputIndex)
|
||||
{
|
||||
LogicGate = logicGate;
|
||||
InputIndex = inputIndex;
|
||||
OutputIndex = outputIndex;
|
||||
}
|
||||
public int InputIndex { get; } = inputIndex;
|
||||
public int OutputIndex { get; } = outputIndex;
|
||||
};
|
||||
@@ -1,7 +1,7 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net6.0</TargetFramework>
|
||||
<TargetFramework>net8.0</TargetFramework>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<Nullable>enable</Nullable>
|
||||
</PropertyGroup>
|
||||
@@ -13,5 +13,8 @@
|
||||
<PackageReference Include="MonoGame.Extended.Input" Version="3.8.0" />
|
||||
<PackageReference Include="MonoGame.Framework.DesktopGL" Version="3.8.1.303" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\StoneRed.LogicSimulator.Simulation\StoneRed.LogicSimulator.Simulation.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
|
||||
@@ -14,6 +14,8 @@ internal class LogicGateSimulator
|
||||
private DateTime dateTime;
|
||||
private bool logicGatesUpdated = false;
|
||||
private ulong logicGateId = 0;
|
||||
private ICircuitSimulator? circuitSimulator;
|
||||
|
||||
public int TargetTicksPerSecond { get; set; } = 100;
|
||||
|
||||
public int ActualTicksPerSecond { get; private set; }
|
||||
@@ -34,13 +36,18 @@ internal class LogicGateSimulator
|
||||
|
||||
public void Start()
|
||||
{
|
||||
if (IsRunning)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
IsRunning = true;
|
||||
|
||||
Thread thread = new Thread(SimulationThread)
|
||||
{
|
||||
IsBackground = true
|
||||
};
|
||||
|
||||
IsRunning = true;
|
||||
|
||||
thread.Start();
|
||||
}
|
||||
|
||||
@@ -55,6 +62,11 @@ internal class LogicGateSimulator
|
||||
logicGatesUpdated = logicGates.TryAdd(gate.Id, gate);
|
||||
}
|
||||
|
||||
public void LogicGatesUpdated()
|
||||
{
|
||||
logicGatesUpdated = true;
|
||||
}
|
||||
|
||||
public LogicGate GetLogicGate(ulong id)
|
||||
{
|
||||
return logicGates[id];
|
||||
@@ -75,24 +87,25 @@ internal class LogicGateSimulator
|
||||
logicGatesUpdated = logicGates.TryRemove(logicGate.Id, out _);
|
||||
}
|
||||
|
||||
public bool GetGateOutput(LogicGate gate)
|
||||
{
|
||||
if (circuitSimulator == null || gate.SimulatorGateId < 0)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return circuitSimulator.GetOutput(gate.SimulatorGateId);
|
||||
}
|
||||
|
||||
private void SimulationThread()
|
||||
{
|
||||
int tps = 0;
|
||||
float iterations = 10000;
|
||||
float sleepDelayIterations = 10000;
|
||||
int sleepDelayMs = 10;
|
||||
|
||||
LogicGate[] logicGatesArray = logicGates.Values.ToArray();
|
||||
circuitSimulator = new CycleCircuitSimulator();
|
||||
|
||||
while (IsRunning)
|
||||
{
|
||||
tps++;
|
||||
|
||||
if (logicGatesUpdated)
|
||||
{
|
||||
logicGatesArray = logicGates.Values.ToArray();
|
||||
logicGatesUpdated = false;
|
||||
}
|
||||
|
||||
if (DateTime.Now > dateTime.AddSeconds(1))
|
||||
Timer timeCheckTimer = new Timer(_ =>
|
||||
{
|
||||
ActualTicksPerSecond = tps;
|
||||
dateTime = DateTime.Now;
|
||||
@@ -102,41 +115,62 @@ internal class LogicGateSimulator
|
||||
{
|
||||
float percentage = Math.Abs((TargetTicksPerSecond - (float)ActualTicksPerSecond) / Math.Abs((float)ActualTicksPerSecond) * 100);
|
||||
|
||||
if (ActualTicksPerSecond / 2 > TargetTicksPerSecond)
|
||||
{
|
||||
iterations *= 2;
|
||||
}
|
||||
else if (ActualTicksPerSecond * 2 < TargetTicksPerSecond)
|
||||
{
|
||||
iterations /= 2;
|
||||
}
|
||||
else if (percentage > 5)
|
||||
{
|
||||
iterations *= (float)ActualTicksPerSecond / TargetTicksPerSecond;
|
||||
}
|
||||
sleepDelayIterations *= (float)ActualTicksPerSecond / TargetTicksPerSecond;
|
||||
|
||||
ClockCalibrating = percentage > 5;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Update cached sleep delay when target TPS changes
|
||||
sleepDelayMs = Math.Max((int)(1000f / TargetTicksPerSecond), 1);
|
||||
}
|
||||
}, null, TimeSpan.FromSeconds(1), TimeSpan.FromSeconds(1));
|
||||
|
||||
while (IsRunning)
|
||||
{
|
||||
tps++;
|
||||
|
||||
if (logicGatesUpdated)
|
||||
{
|
||||
circuitSimulator = new CycleCircuitSimulator();
|
||||
|
||||
// Register all gates first
|
||||
foreach (LogicGate gate in logicGates.Values)
|
||||
{
|
||||
gate.Register(circuitSimulator);
|
||||
}
|
||||
|
||||
for (int i = 0; i < logicGatesArray.Length; i++)
|
||||
// Then connect them based on LogicGate connections
|
||||
foreach (LogicGate gate in logicGates.Values)
|
||||
{
|
||||
logicGatesArray[i].NextTick();
|
||||
foreach (LogicGateConnection connection in gate.LogicGateConnections)
|
||||
{
|
||||
// Connect: this gate's output → connected gate's input
|
||||
circuitSimulator.ConnectGates(
|
||||
gate.SimulatorGateId,
|
||||
connection.LogicGate.SimulatorGateId,
|
||||
connection.InputIndex
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
for (int i = 0; i < logicGatesArray.Length; i++)
|
||||
{
|
||||
logicGatesArray[i].Update();
|
||||
circuitSimulator.Reset();
|
||||
|
||||
logicGatesUpdated = false;
|
||||
}
|
||||
|
||||
circuitSimulator.Step();
|
||||
|
||||
if (HighPerformanceClock)
|
||||
{
|
||||
Thread.SpinWait((int)iterations);
|
||||
Thread.SpinWait((int)sleepDelayIterations);
|
||||
}
|
||||
else
|
||||
{
|
||||
Thread.Sleep(Math.Max((int)(1f / TargetTicksPerSecond * 1000), 1));
|
||||
Thread.Sleep(sleepDelayMs);
|
||||
}
|
||||
}
|
||||
|
||||
_ = timeCheckTimer.Change(Timeout.Infinite, Timeout.Infinite);
|
||||
}
|
||||
}
|
||||
@@ -11,8 +11,8 @@ internal class AndGate : LogicGate
|
||||
|
||||
public override int OutputCount { get; set; } = 1;
|
||||
|
||||
protected override void Execute()
|
||||
protected internal override void Register(ICircuitSimulator circuitSimulator)
|
||||
{
|
||||
SetOutputBit(GetInputBit(0) == 1 && GetInputBit(1) == 1 ? 1 : 0, 0);
|
||||
SimulatorGateId = circuitSimulator.AddGate(GateKind.And2);
|
||||
}
|
||||
}
|
||||
@@ -11,30 +11,30 @@ namespace StoneRed.LogicSimulator.Simulation.LogicGates;
|
||||
[LogicGateDescription("A button is a momentary switch that can be turned on and off.")]
|
||||
internal class Button : LogicGate, IInteractable, IColorable
|
||||
{
|
||||
private ICircuitSimulator? circuitSimulator;
|
||||
private int gateId;
|
||||
private bool isPressed;
|
||||
|
||||
public override int OutputCount { get; set; } = 1;
|
||||
|
||||
public override int InputCount { get; set; } = 0;
|
||||
|
||||
public bool IsPressed { get; set; }
|
||||
public Color Color { get; set; } = Color.Purple;
|
||||
public string Info { get; set; } = "OFF";
|
||||
|
||||
public void OnInteraction(MouseStateExtended mouseState, MouseStateExtended previousMouseState, KeyboardStateExtended keyboardStateExtended)
|
||||
{
|
||||
IsPressed = mouseState.IsButtonDown(MouseButton.Left);
|
||||
Color = IsPressed ? Color.Green : Color.Purple;
|
||||
Info = IsPressed ? "ON" : "OFF";
|
||||
isPressed = mouseState.IsButtonDown(MouseButton.Left);
|
||||
Color = isPressed ? Color.Green : Color.Purple;
|
||||
Info = isPressed ? "ON" : "OFF";
|
||||
|
||||
circuitSimulator?.SetSource(gateId, isPressed);
|
||||
}
|
||||
|
||||
protected override void Execute()
|
||||
protected internal override void Register(ICircuitSimulator circuitSimulator)
|
||||
{
|
||||
if (IsPressed)
|
||||
{
|
||||
SetOutputBit(1, 0);
|
||||
}
|
||||
else
|
||||
{
|
||||
SetOutputBit(0, 0);
|
||||
}
|
||||
this.circuitSimulator = circuitSimulator;
|
||||
SimulatorGateId = circuitSimulator.AddGate(GateKind.Source);
|
||||
gateId = SimulatorGateId;
|
||||
}
|
||||
}
|
||||
@@ -11,8 +11,12 @@ namespace StoneRed.LogicSimulator.Simulation.LogicGates;
|
||||
[LogicGateDescription("A clock is a circuit that oscillates between a high and a low state.")]
|
||||
internal class Clock : LogicGate, IInteractable
|
||||
{
|
||||
private ICircuitSimulator? circuitSimulator;
|
||||
private int gateId;
|
||||
private int count = 0;
|
||||
private int tickRate = 0;
|
||||
private bool currentState = false;
|
||||
|
||||
public override int OutputCount { get; set; } = 1;
|
||||
|
||||
public override int InputCount { get; set; } = 0;
|
||||
@@ -49,28 +53,41 @@ internal class Clock : LogicGate, IInteractable
|
||||
tickRate = Math.Clamp(tickRate, 0, int.MaxValue);
|
||||
}
|
||||
|
||||
protected override void Execute()
|
||||
protected internal override void Register(ICircuitSimulator circuitSimulator)
|
||||
{
|
||||
this.circuitSimulator = circuitSimulator;
|
||||
SimulatorGateId = circuitSimulator.AddGate(GateKind.Source);
|
||||
gateId = SimulatorGateId;
|
||||
|
||||
// Watch own output to count ticks and toggle
|
||||
circuitSimulator.WatchGate(SimulatorGateId, (oldMask, newMask) =>
|
||||
{
|
||||
if (tickRate <= 0)
|
||||
{
|
||||
SetOutputBit(0, 0);
|
||||
count = 0;
|
||||
currentState = false;
|
||||
circuitSimulator.SetSource(gateId, false);
|
||||
return;
|
||||
}
|
||||
|
||||
// Count the tick
|
||||
count++;
|
||||
|
||||
if (count >= tickRate * 2)
|
||||
{
|
||||
count = 0;
|
||||
}
|
||||
|
||||
count++;
|
||||
// Toggle state based on count
|
||||
bool newState = count > tickRate;
|
||||
if (newState != currentState)
|
||||
{
|
||||
currentState = newState;
|
||||
circuitSimulator.SetSource(gateId, newState);
|
||||
}
|
||||
});
|
||||
|
||||
if (count > tickRate)
|
||||
{
|
||||
SetOutputBit(1, 0);
|
||||
}
|
||||
else
|
||||
{
|
||||
SetOutputBit(0, 0);
|
||||
}
|
||||
// Initialize to off state
|
||||
circuitSimulator.SetSource(gateId, false);
|
||||
}
|
||||
}
|
||||
@@ -15,8 +15,15 @@ internal class Lamp : LogicGate, IColorable
|
||||
|
||||
public Color Color { get; set; } = Color.CadetBlue;
|
||||
|
||||
protected override void Execute()
|
||||
protected internal override void Register(ICircuitSimulator circuitSimulator)
|
||||
{
|
||||
Color = GetInputBit(0) == 0 ? Color.CadetBlue : Color.Yellow;
|
||||
SimulatorGateId = circuitSimulator.AddGate(GateKind.Sink);
|
||||
|
||||
// Watch input to update lamp color
|
||||
circuitSimulator.WatchGate(SimulatorGateId, (oldMask, newMask) =>
|
||||
{
|
||||
bool isOn = (newMask & 1) != 0;
|
||||
Color = isOn ? Color.Yellow : Color.CadetBlue;
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -11,8 +11,8 @@ internal class NotGate : LogicGate
|
||||
|
||||
public override int OutputCount { get; set; } = 1;
|
||||
|
||||
protected override void Execute()
|
||||
protected internal override void Register(ICircuitSimulator circuitSimulator)
|
||||
{
|
||||
SetOutputBit(GetInputBit(0) == 1 ? 0 : 1, 0);
|
||||
SimulatorGateId = circuitSimulator.AddGate(GateKind.Not);
|
||||
}
|
||||
}
|
||||
@@ -11,8 +11,8 @@ internal class OrGate : LogicGate
|
||||
|
||||
public override int OutputCount { get; set; } = 1;
|
||||
|
||||
protected override void Execute()
|
||||
protected internal override void Register(ICircuitSimulator circuitSimulator)
|
||||
{
|
||||
SetOutputBit(GetInputBit(0), 0);
|
||||
SimulatorGateId = circuitSimulator.AddGate(GateKind.Or2);
|
||||
}
|
||||
}
|
||||
@@ -11,11 +11,8 @@ internal class Pin : LogicGate
|
||||
|
||||
public override int InputCount { get; set; } = 1;
|
||||
|
||||
protected override void Execute()
|
||||
protected internal override void Register(ICircuitSimulator circuitSimulator)
|
||||
{
|
||||
for (int i = 0; i < InputCount; i++)
|
||||
{
|
||||
SetOutputBit(GetInputBit(i), i);
|
||||
}
|
||||
SimulatorGateId = circuitSimulator.AddGate(GateKind.Buffer);
|
||||
}
|
||||
}
|
||||
@@ -12,6 +12,8 @@ namespace StoneRed.LogicSimulator.Simulation.LogicGates;
|
||||
[LogicGateDescription("A switch is a toggleable switch that can be turned on and off.")]
|
||||
internal class Switch : LogicGate, IInteractable, IColorable
|
||||
{
|
||||
private ICircuitSimulator? circuitSimulator;
|
||||
private int gateId;
|
||||
private bool isPressed;
|
||||
public override int OutputCount { get; set; } = 1;
|
||||
|
||||
@@ -28,17 +30,15 @@ internal class Switch : LogicGate, IInteractable, IColorable
|
||||
|
||||
Color = isPressed ? Color.Green : Color.Purple;
|
||||
Info = isPressed ? "ON" : "OFF";
|
||||
|
||||
circuitSimulator?.SetSource(gateId, isPressed);
|
||||
}
|
||||
|
||||
protected override void Execute()
|
||||
protected internal override void Register(ICircuitSimulator circuitSimulator)
|
||||
{
|
||||
if (isPressed)
|
||||
{
|
||||
SetOutputBit(1, 0);
|
||||
}
|
||||
else
|
||||
{
|
||||
SetOutputBit(0, 0);
|
||||
}
|
||||
this.circuitSimulator = circuitSimulator;
|
||||
|
||||
SimulatorGateId = circuitSimulator.AddGate(GateKind.Source);
|
||||
gateId = SimulatorGateId;
|
||||
}
|
||||
}
|
||||
@@ -33,28 +33,38 @@ internal class TestLogicGate : LogicGate, Api.Interfaces.IDrawable
|
||||
texture = CreateTexture(15, 15);
|
||||
}
|
||||
|
||||
protected override void Execute()
|
||||
protected internal override void Register(ICircuitSimulator circuitSimulator)
|
||||
{
|
||||
SimulatorGateId = circuitSimulator.AddGate(GateKind.Sink);
|
||||
|
||||
// Watch all 7 inputs to update display
|
||||
circuitSimulator.WatchGate(SimulatorGateId, (oldMask, newMask) =>
|
||||
{
|
||||
// Extract each bit from the input mask
|
||||
bool inputA = (newMask & (1 << 0)) != 0;
|
||||
bool inputB = (newMask & (1 << 1)) != 0;
|
||||
bool inputC = (newMask & (1 << 2)) != 0;
|
||||
bool inputD = (newMask & (1 << 3)) != 0;
|
||||
bool inputE = (newMask & (1 << 4)) != 0;
|
||||
bool inputF = (newMask & (1 << 5)) != 0;
|
||||
bool inputG = (newMask & (1 << 6)) != 0;
|
||||
|
||||
// Update 7-segment display
|
||||
// A
|
||||
SetRangeWithSpacing(20, 24, 1, GetInputBit(0) == 1 ? Color.Red : Color.Gray);
|
||||
|
||||
SetRangeWithSpacing(20, 24, 1, inputA ? Color.Red : Color.Gray);
|
||||
// B
|
||||
SetRangeWithSpacing(40, 100, 15, GetInputBit(1) == 1 ? Color.Red : Color.Gray);
|
||||
|
||||
SetRangeWithSpacing(40, 100, 15, inputB ? Color.Red : Color.Gray);
|
||||
// C
|
||||
SetRangeWithSpacing(130, 190, 15, GetInputBit(2) == 1 ? Color.Red : Color.Gray);
|
||||
|
||||
SetRangeWithSpacing(130, 190, 15, inputC ? Color.Red : Color.Gray);
|
||||
// D
|
||||
SetRangeWithSpacing(200, 204, 1, GetInputBit(3) == 1 ? Color.Red : Color.Gray);
|
||||
|
||||
SetRangeWithSpacing(200, 204, 1, inputD ? Color.Red : Color.Gray);
|
||||
// E
|
||||
SetRangeWithSpacing(124, 184, 15, GetInputBit(4) == 1 ? Color.Red : Color.Gray);
|
||||
|
||||
SetRangeWithSpacing(124, 184, 15, inputE ? Color.Red : Color.Gray);
|
||||
// F
|
||||
SetRangeWithSpacing(34, 94, 15, GetInputBit(5) == 1 ? Color.Red : Color.Gray);
|
||||
|
||||
SetRangeWithSpacing(34, 94, 15, inputF ? Color.Red : Color.Gray);
|
||||
// G
|
||||
SetRangeWithSpacing(110, 114, 1, GetInputBit(6) == 1 ? Color.Red : Color.Gray);
|
||||
SetRangeWithSpacing(110, 114, 1, inputG ? Color.Red : Color.Gray);
|
||||
});
|
||||
}
|
||||
|
||||
private void SetRangeWithSpacing(int start, int end, int spacing, Color value)
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
<PropertyGroup>
|
||||
<OutputType>WinExe</OutputType>
|
||||
<TargetFramework>net6.0</TargetFramework>
|
||||
<TargetFramework>net8.0</TargetFramework>
|
||||
<RollForward>Major</RollForward>
|
||||
<PublishReadyToRun>false</PublishReadyToRun>
|
||||
<TieredCompilation>false</TieredCompilation>
|
||||
@@ -35,6 +35,7 @@
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\StoneRed.LogicSimulator.Api\StoneRed.LogicSimulator.Api.csproj" />
|
||||
<ProjectReference Include="..\StoneRed.LogicSimulator.Simulation\StoneRed.LogicSimulator.Simulation.csproj" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Compile Update="UserInterface\Windows\SettingsWindow.cs">
|
||||
|
||||
@@ -141,7 +141,7 @@ internal class WorldScreen : SrlsScreen<Grid>
|
||||
// Draw logic gate connections
|
||||
foreach (LogicGateConnection connection in logicGate.LogicGateConnections)
|
||||
{
|
||||
Color lineColor = logicGate.GetCachedOutputBit(connection.OutputIndex) == 1 ? Color.Red : Color.LightBlue;
|
||||
Color lineColor = simulator.GetGateOutput(logicGate) ? Color.Red : Color.LightBlue;
|
||||
srls.SpriteBatch.DrawLine((logicGate.WorldData.Position * srls.Scale) + (logicGateSize / 2 * srls.Scale), (connection.LogicGate.WorldData.Position * srls.Scale) + (logicGateSize / 2 * srls.Scale), lineColor, 5 * srls.Scale, hideCablesBehindGatesCheckBox.IsChecked ? 0.5f : 0.1f);
|
||||
}
|
||||
}
|
||||
@@ -423,6 +423,7 @@ internal class WorldScreen : SrlsScreen<Grid>
|
||||
}
|
||||
}
|
||||
|
||||
simulator.LogicGatesUpdated();
|
||||
connectionContext = null;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user