// // NesSystem.mm // // // Created by Selim Mustafaev on 27.09.2023. // #import "NesSystem.h" #import #import @interface NesSystem() @end @implementation NesSystem { std::unique_ptr _system; NSCondition* _condition; BOOL _runEmulation; } - (instancetype)init { if(self = [super init]) { _system = std::make_unique(); _condition = [NSCondition new]; _runEmulation = YES; size_t frameBufferSize = nes::Ppu::SCREEN_WIDTH * nes::Ppu::SCREEN_HEIGHT * sizeof(nes::Pixel); _system->setNewFrameCallback([&](auto frameBuffer) { _runEmulation = NO; CGDataProviderRef dataProvider = CGDataProviderCreateWithData(NULL, (void*)frameBuffer, frameBufferSize, NULL); CGColorSpaceRef colorspace = CGColorSpaceCreateDeviceRGB(); _frame = CGImageCreate(nes::Ppu::SCREEN_WIDTH, nes::Ppu::SCREEN_HEIGHT, 8, sizeof(nes::Pixel)*8, nes::Ppu::SCREEN_WIDTH * sizeof(nes::Pixel), colorspace, kCGBitmapByteOrderDefault, dataProvider, NULL, true, kCGRenderingIntentDefault); CGDataProviderRelease(dataProvider); CGColorSpaceRelease(colorspace); }); } return self; } - (void)runRom:(NSURL*)url { _system->insertCartridge([url fileSystemRepresentation]); dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ [_condition lock]; while (!_runEmulation) { [_condition wait]; } while(_runEmulation) { _system->tick(); } [_condition unlock]; }); } - (void)stepToNextFrame { [_condition lock]; _runEmulation = YES; [_condition signal]; [_condition unlock]; } @end