blob: 0ff5122a2e2af1c024e95799b293a1429cdf286d (
plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
|
#import "scene.hh"
#import "impl/display-spritekit.hh"
#import "impl/file-browser-posix.hh"
#import "impl/input-device-gc-keyboard.hh"
#import "impl/input-device-gc-gamepad.hh"
#import "impl/input-device-serial-controller.hh"
#import "nes/app/application.hh"
#import <memory>
#import <optional>
namespace
{
constexpr auto const serial_controller_path = "/dev/cu.usbserial-FTB6SPL3";
} // namespace
@implementation Scene
{
std::unique_ptr<nes::app::mac::display_spritekit> _display;
std::unique_ptr<nes::app::mac::file_browser_posix> _fileBrowser;
std::unique_ptr<nes::app::mac::input_device_serial_controller> _serialController;
std::unique_ptr<nes::app::mac::input_device_gc_keyboard> _keyboard;
std::vector<std::unique_ptr<nes::app::mac::input_device_gc_gamepad>> _controllers;
std::unique_ptr<nes::app::application> _app;
std::optional<NSTimeInterval> _lastTimestamp;
}
- (instancetype)init
{
self = [super initWithSize:CGSizeMake(nes::display::width, nes::display::height)];
if (self)
{
auto node = [[SKSpriteNode alloc] init];
[node setAnchorPoint:CGPointZero];
[node setSize:[self size]];
[self setScaleMode:SKSceneScaleModeAspectFit];
[self addChild:node];
_display = std::make_unique<nes::app::mac::display_spritekit>(node);
_fileBrowser = std::make_unique<nes::app::mac::file_browser_posix>();
_serialController = std::make_unique<nes::app::mac::input_device_serial_controller>(serial_controller_path);
_keyboard = std::make_unique<nes::app::mac::input_device_gc_keyboard>([[GCKeyboard coalescedKeyboard] keyboardInput]);
_app = std::make_unique<nes::app::application>(*_display, *_keyboard, *_fileBrowser);
_app->add_controller(*_serialController);
for (GCController* controller in [GCController controllers])
{
auto gamepad = [controller extendedGamepad];
if (gamepad)
{
auto adapter = std::make_unique<nes::app::mac::input_device_gc_gamepad>(gamepad);
_app->add_controller(*adapter);
_controllers.emplace_back(std::move(adapter));
}
}
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(handleKeyboardConnected:)
name:GCKeyboardDidConnectNotification
object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(handleControllerConnected:)
name:GCControllerDidConnectNotification
object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(handleControllerDisconnected:)
name:GCControllerDidDisconnectNotification
object:nil];
}
return self;
}
- (void)dealloc
{
[[NSNotificationCenter defaultCenter] removeObserver:self];
}
- (void)keyUp:(NSEvent*)event
{
// Handled by Game Controller
}
- (void)keyDown:(NSEvent*)event
{
// Handled by Game Controller
}
- (void)update:(NSTimeInterval)currentTime
{
auto const lastTimestamp = _lastTimestamp.value_or(currentTime);
_lastTimestamp = currentTime;
auto deltaMicroseconds = static_cast<nes::u64>((currentTime - lastTimestamp) * 1000. * 1000.);
deltaMicroseconds = std::min(deltaMicroseconds, nes::u64{ 50000 });
_app->frame(std::chrono::microseconds{ deltaMicroseconds });
}
- (void)handleKeyboardConnected:(NSNotification*)notification
{
_keyboard->set_profile([[GCKeyboard coalescedKeyboard] keyboardInput]);
}
- (void)handleControllerConnected:(NSNotification*)notification
{
auto controller = (GCController*)[notification object];
auto gamepad = [controller extendedGamepad];
if (gamepad)
{
auto adapter = std::make_unique<nes::app::mac::input_device_gc_gamepad>(gamepad);
_app->add_controller(*adapter);
_controllers.emplace_back(std::move(adapter));
}
}
- (void)handleControllerDisconnected:(NSNotification*)notification
{
auto controller = (GCController*)[notification object];
for (auto i = _controllers.size(); i > 0; --i)
{
auto& adapter = *_controllers[i - 1];
if (adapter.get_controller() == controller)
{
_app->remove_controller(adapter);
_controllers.erase(_controllers.begin() + static_cast<int>(i - 1));
}
}
}
@end
|