diff --git a/Cocoa/Document.h b/Cocoa/Document.h
index 1a722e9..48a2cba 100644
--- a/Cocoa/Document.h
+++ b/Cocoa/Document.h
@@ -25,6 +25,9 @@
@property (strong) IBOutlet NSTextField *vramStatusLabel;
@property (strong) IBOutlet NSTableView *paletteTableView;
@property (strong) IBOutlet NSTableView *spritesTableView;
+@property (strong) IBOutlet NSPanel *printerFeedWindow;
+@property (strong) IBOutlet NSImageView *feedImageView;
+@property (strong) IBOutlet NSButton *feedSaveButton;
-(uint8_t) readMemory:(uint16_t) addr;
-(void) writeMemory:(uint16_t) addr value:(uint8_t)value;
diff --git a/Cocoa/Document.m b/Cocoa/Document.m
index 9c38859..19b826d 100644
--- a/Cocoa/Document.m
+++ b/Cocoa/Document.m
@@ -37,6 +37,9 @@
uint16_t oamCount;
uint8_t oamHeight;
bool oamUpdating;
+
+ NSMutableData *currentPrinterImageData;
+ enum {GBAccessoryNone, GBAccessoryPrinter} accessory;
}
@property GBAudioClient *audioClient;
@@ -46,6 +49,9 @@
- (const char *) getAsyncDebuggerInput;
- (void) cameraRequestUpdate;
- (uint8_t) cameraGetPixelAtX:(uint8_t)x andY:(uint8_t)y;
+- (void) printImage:(uint32_t *)image height:(unsigned) height
+ topMargin:(unsigned) topMargin bottomMargin: (unsigned) bottomMargin
+ exposure:(unsigned) exposure;
@end
static void vblank(GB_gameboy_t *gb)
@@ -75,7 +81,7 @@ static char *asyncConsoleInput(GB_gameboy_t *gb)
static uint32_t rgbEncode(GB_gameboy_t *gb, uint8_t r, uint8_t g, uint8_t b)
{
- return (r << 0) | (g << 8) | (b << 16);
+ return (r << 0) | (g << 8) | (b << 16) | 0xFF000000;
}
static void cameraRequestUpdate(GB_gameboy_t *gb)
@@ -90,6 +96,13 @@ static uint8_t cameraGetPixel(GB_gameboy_t *gb, uint8_t x, uint8_t y)
return [self cameraGetPixelAtX:x andY:y];
}
+static void printImage(GB_gameboy_t *gb, uint32_t *image, uint8_t height,
+ uint8_t top_margin, uint8_t bottom_margin, uint8_t exposure)
+{
+ Document *self = (__bridge Document *)(gb->user_data);
+ [self printImage:image height:height topMargin:top_margin bottomMargin:bottom_margin exposure:exposure];
+}
+
@implementation Document
{
GB_gameboy_t gb;
@@ -132,6 +145,7 @@ static uint8_t cameraGetPixel(GB_gameboy_t *gb, uint8_t x, uint8_t y)
- (void) initCommon
{
+ gb.user_data = (__bridge void *)(self);
GB_set_vblank_callback(&gb, (GB_vblank_callback_t) vblank);
GB_set_log_callback(&gb, (GB_log_callback_t) consoleLog);
GB_set_input_callback(&gb, (GB_input_callback_t) consoleInput);
@@ -139,7 +153,6 @@ static uint8_t cameraGetPixel(GB_gameboy_t *gb, uint8_t x, uint8_t y)
GB_set_rgb_encode_callback(&gb, rgbEncode);
GB_set_camera_get_pixel_callback(&gb, cameraGetPixel);
GB_set_camera_update_request_callback(&gb, cameraRequestUpdate);
- gb.user_data = (__bridge void *)(self);
}
- (void) vblank
@@ -271,6 +284,14 @@ static uint8_t cameraGetPixel(GB_gameboy_t *gb, uint8_t x, uint8_t y)
window_frame.size.height);
[self.mainWindow setFrame:window_frame display:YES];
self.vramStatusLabel.cell.backgroundStyle = NSBackgroundStyleRaised;
+
+
+ [self.feedSaveButton removeFromSuperview];
+ /* contentView.superview.subviews.lastObject is the titlebar view */
+ NSView *titleView = self.printerFeedWindow.contentView.superview.subviews.lastObject;
+ [titleView addSubview: self.feedSaveButton];
+ self.feedSaveButton.frame = (NSRect){{268, 2}, {48, 17}};
+
[self start];
}
@@ -400,6 +421,12 @@ static uint8_t cameraGetPixel(GB_gameboy_t *gb, uint8_t x, uint8_t y)
return false;
}
}
+ else if ([anItem action] == @selector(disconnectAllAccessories:)) {
+ [(NSMenuItem*)anItem setState:accessory == GBAccessoryNone];
+ }
+ else if ([anItem action] == @selector(connectPrinter:)) {
+ [(NSMenuItem*)anItem setState:accessory == GBAccessoryPrinter];
+ }
return [super validateUserInterfaceItem:anItem];
}
@@ -1073,4 +1100,71 @@ static uint8_t cameraGetPixel(GB_gameboy_t *gb, uint8_t x, uint8_t y)
{
[self.vramWindow makeKeyAndOrderFront:sender];
}
+
+- (void) printImage:(uint32_t *)imageBytes height:(unsigned) height
+ topMargin:(unsigned) topMargin bottomMargin: (unsigned) bottomMargin
+ exposure:(unsigned) exposure
+{
+ uint32_t paddedImage[160 * (topMargin + height + bottomMargin)];
+ memset(paddedImage, 0xFF, sizeof(paddedImage));
+ memcpy(paddedImage + (160 * topMargin), imageBytes, 160 * height * sizeof(imageBytes[0]));
+ if (!self.printerFeedWindow.isVisible) {
+ currentPrinterImageData = [[NSMutableData alloc] init];
+ }
+ [currentPrinterImageData appendBytes:paddedImage length:sizeof(paddedImage)];
+ self.feedImageView.image = [Document imageFromData:currentPrinterImageData
+ width:160
+ height:currentPrinterImageData.length / 160 / sizeof(imageBytes[0])
+ scale:2.0];
+ /* UI related code must run on main thread. */
+ dispatch_async(dispatch_get_main_queue(), ^{
+ NSRect frame = self.printerFeedWindow.frame;
+ frame.size = self.feedImageView.image.size;
+ frame.size.height += self.printerFeedWindow.frame.size.height - self.printerFeedWindow.contentView.frame.size.height;
+ [self.printerFeedWindow setMaxSize:frame.size];
+ [self.printerFeedWindow setFrame:frame display:NO animate: self.printerFeedWindow.isVisible];
+ [self.printerFeedWindow orderFront:NULL];
+ });
+
+}
+- (IBAction)savePrinterFeed:(id)sender
+{
+ bool shouldResume = running;
+ [self stop];
+ NSSavePanel * savePanel = [NSSavePanel savePanel];
+ [savePanel setAllowedFileTypes:@[@"png"]];
+ [savePanel beginSheetModalForWindow:self.printerFeedWindow completionHandler:^(NSInteger result){
+ if (result == NSFileHandlingPanelOKButton) {
+ [savePanel orderOut:self];
+ CGImageRef cgRef = [self.feedImageView.image CGImageForProposedRect:NULL
+ context:nil
+ hints:nil];
+ NSBitmapImageRep *imageRep = [[NSBitmapImageRep alloc] initWithCGImage:cgRef];
+ [imageRep setSize:(NSSize){160, self.feedImageView.image.size.height / 2}];
+ NSData *data = [imageRep representationUsingType:NSPNGFileType properties:@{}];
+ [data writeToURL:savePanel.URL atomically:NO];
+ [self.printerFeedWindow setIsVisible:NO];
+ }
+ if (shouldResume) {
+ [self start];
+ }
+ }];
+}
+
+- (IBAction)disconnectAllAccessories:(id)sender
+{
+ [self performAtomicBlock:^{
+ accessory = GBAccessoryNone;
+ GB_disconnect_serial(&gb);
+ }];
+}
+
+- (IBAction)connectPrinter:(id)sender
+{
+ [self performAtomicBlock:^{
+ accessory = GBAccessoryPrinter;
+ GB_connect_printer(&gb, printImage);
+ }];
+}
+
@end
\ No newline at end of file
diff --git a/Cocoa/Document.xib b/Cocoa/Document.xib
index c9cf907..726f0dc 100644
--- a/Cocoa/Document.xib
+++ b/Cocoa/Document.xib
@@ -10,6 +10,8 @@
+
+
@@ -17,6 +19,7 @@
+
@@ -32,7 +35,7 @@
-
+
@@ -679,5 +682,35 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/Cocoa/MainMenu.xib b/Cocoa/MainMenu.xib
index 85376a2..d43f107 100644
--- a/Cocoa/MainMenu.xib
+++ b/Cocoa/MainMenu.xib
@@ -339,6 +339,25 @@
+