Skip to content

Commit 1fc4436

Browse files
committed
Reorganize input display drawing
I tested all combinations I can think of and this looks correct. Hopefully this can easily be verified with the given code comments now.
1 parent c913c5a commit 1fc4436

File tree

2 files changed

+38
-48
lines changed

2 files changed

+38
-48
lines changed

src/BizHawk.Client.Common/DisplayManager/OSDManager.cs

Lines changed: 38 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -171,29 +171,30 @@ public void DrawMessages(IBlitter g)
171171
}
172172
}
173173

174-
public string InputStrMovie()
174+
private string InputStrMovie()
175175
{
176176
var state = _movieSession.Movie?.GetInputState(_emulator.Frame - 1);
177177
return state is not null ? MakeStringFor(state) : "";
178178
}
179179

180-
public string InputStrImmediate()
180+
private string InputStrCurrent()
181181
=> MakeStringFor(_inputManager.AutofireStickyXorAdapter);
182182

183+
// returns an input string for inputs pressed by the user that are not getting unpressed by the sticky adapters
184+
private string InputStrUser()
185+
=> MakeStringFor(_inputManager.AutofireStickyXorAdapter.And(_inputManager.StickyXorAdapter.Source));
186+
183187
private static string MakeStringFor(IController controller)
184188
{
185189
return Bk2InputDisplayGenerator.Generate(controller);
186190
}
187191

188-
public string MakeIntersectImmediatePrevious()
192+
private string MakeIntersectImmediatePrevious()
189193
{
190-
if (_movieSession.Movie.IsActive())
194+
if (_movieSession.Movie.IsRecording())
191195
{
192-
var m = _movieSession.Movie.IsPlayingOrRecording()
193-
? _movieSession.Movie.GetInputState(_emulator.Frame - 1)
194-
: _movieSession.MovieController;
195-
196-
return MakeStringFor(_inputManager.AutofireStickyXorAdapter.And(m));
196+
var movieInput = _movieSession.Movie.GetInputState(_emulator.Frame - 1);
197+
return MakeStringFor(_inputManager.AutofireStickyXorAdapter.And(movieInput));
197198
}
198199

199200
return "";
@@ -237,42 +238,34 @@ public void DrawScreenInfo(IBlitter g)
237238
}
238239
else // TODO: message config -- allow setting of "mixed", and "auto"
239240
{
240-
var previousColor = Color.FromArgb(_config.LastInputColor);
241-
var immediateColor = Color.FromArgb(_config.MessagesColor);
242-
var autoColor = Color.Pink;
243-
var changedColor = Color.PeachPuff;
244-
245-
// now, we're going to render these repeatedly, with higher-priority things overriding
246-
247-
// first display previous frame's input.
248-
// note: that's only available in case we're working on a movie
249-
var previousStr = InputStrMovie();
250-
251-
//we need some kind of string for calculating position when right-anchoring, of something like that
252-
var point = GetCoordinates(g, _config.InputDisplay, previousStr);
253-
254-
bool atMovieEnd = _movieSession.Movie.IsFinished() && _movieSession.Movie.IsAtEnd();
255-
g.DrawString(previousStr, atMovieEnd ? Color.FromArgb(_config.MovieInput) : previousColor, point.X, point.Y);
256-
257-
// next, draw the immediate input.
258-
// that is, whatever is being held down interactively right this moment even if the game is paused
259-
// this includes things held down due to autohold or autofire
260-
// I know, this is all really confusing
261-
var immediate = InputStrImmediate();
262-
g.DrawString(immediate, immediateColor, point.X, point.Y);
263-
264-
// next draw anything that's pressed because it's sticky.
265-
// this applies to autofire and autohold both. somehow. I don't understand it.
266-
// basically we're tinting whatever is pressed because it's sticky specially
267-
// in order to achieve this we want to avoid drawing anything pink that isn't actually held down right now
268-
// so we make an AND adapter and combine it using immediate & sticky
269-
// (adapter creation moved to InputManager)
270-
var autoString = MakeStringFor(_inputManager.WeirdStickyControllerForInputDisplay);
271-
g.DrawString(autoString, autoColor, point.X, point.Y);
272-
273-
//recolor everything that's changed from the previous input
274-
var immediateOverlay = MakeIntersectImmediatePrevious();
275-
g.DrawString(immediateOverlay, changedColor, point.X, point.Y);
241+
var previousColor = _movieSession.Movie.IsRecording() ? Color.FromArgb(_config.LastInputColor) : Color.FromArgb(_config.MovieInput);
242+
var currentColor = Color.FromArgb(_config.MessagesColor);
243+
var stickyColor = Color.Pink;
244+
var currentAndPreviousColor = Color.PeachPuff;
245+
246+
// now, we're going to render these repeatedly, with higher priority draws overwriting all lower priority draws
247+
// in order of highest priority to lowest, we are effectively displaying (in different colors):
248+
// 1. currently pressed input that was also pressed on the previous frame (movie active + recording mode only)
249+
// 2. currently pressed input that is being pressed by sticky autohold or sticky autofire
250+
// 3. currently pressed input by the user (non-sticky)
251+
// 4. input that was pressed on the previous frame (movie active only)
252+
253+
var previousInput = InputStrMovie();
254+
var currentInput = InputStrCurrent();
255+
var userInput = InputStrUser();
256+
var currentAndPreviousInput = MakeIntersectImmediatePrevious();
257+
258+
// calculate origin for drawing all strings. Mainly relevant when right-anchoring
259+
var point = GetCoordinates(g, _config.InputDisplay, currentInput);
260+
261+
// draw previous input first. Currently pressed input will overwrite this
262+
g.DrawString(previousInput, previousColor, point.X, point.Y);
263+
// draw all currently pressed input with the sticky color
264+
g.DrawString(currentInput, stickyColor, point.X, point.Y);
265+
// draw all currently pressed non-sticky input with the current color, overwriting previously drawn non-sticky input in the wrong color
266+
g.DrawString(userInput, currentColor, point.X, point.Y);
267+
// re-draw all currently pressed inputs that were also pressed on the previous frame in their own color
268+
g.DrawString(currentAndPreviousInput, currentAndPreviousColor, point.X, point.Y);
276269
}
277270
}
278271

src/BizHawk.Client.Common/inputAdapters/InputManager.cs

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -32,8 +32,6 @@ public class InputManager
3232
/// </summary>
3333
public StickyXorAdapter StickyXorAdapter { get; } = new StickyXorAdapter();
3434

35-
public IController WeirdStickyControllerForInputDisplay { get; private set; }
36-
3735
/// <summary>
3836
/// Used to AND to another controller, used for <see cref="IJoypadApi.Set(IReadOnlyDictionary{string, bool}, int?)">JoypadApi.Set</see>
3937
/// </summary>
@@ -79,7 +77,6 @@ public void SyncControls(IEmulator emulator, IMovieSession session, Config confi
7977
// these are all reference types which don't change so this SHOULD be a no-op, but I'm not brave enough to move it to the ctor --yoshi
8078
StickyXorAdapter.Source = UdLRControllerAdapter;
8179
AutofireStickyXorAdapter = new() { Source = StickyXorAdapter };
82-
WeirdStickyControllerForInputDisplay = StickyXorAdapter.Source.Xor(AutofireStickyXorAdapter).And(AutofireStickyXorAdapter);
8380

8481
session.MovieIn = AutofireStickyXorAdapter;
8582
session.StickySource = AutofireStickyXorAdapter;

0 commit comments

Comments
 (0)