// // 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([frameBufferSize, self](auto frameBuffer) { _runEmulation = NO; CGDataProviderRef dataProvider = CGDataProviderCreateWithData(NULL, (void*)frameBuffer, frameBufferSize, NULL); CGColorSpaceRef colorspace = CGColorSpaceCreateDeviceRGB(); CGImageRef image = CGImageCreate(nes::Ppu::SCREEN_WIDTH, nes::Ppu::SCREEN_HEIGHT, 8, sizeof(nes::Pixel)*8, nes::Ppu::SCREEN_WIDTH * sizeof(nes::Pixel), colorspace, kCGImageAlphaPremultipliedLast, dataProvider, NULL, true, kCGRenderingIntentDefault); CGDataProviderRelease(dataProvider); CGColorSpaceRelease(colorspace); dispatch_async(dispatch_get_main_queue(), ^{ _frame = image; }); }); } return self; } - (void)runRom:(NSURL*)url { _system->insertCartridge([url fileSystemRepresentation]); dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ while(TRUE) { [_condition lock]; while (!_runEmulation) { [_condition wait]; } while(_runEmulation) { _system->tick(); } [_condition unlock]; } }); } - (void)stepToNextFrame { [_condition lock]; _runEmulation = YES; [_condition signal]; [_condition unlock]; } @end