Printer support in Cocoa
This commit is contained in:
parent
527ae01e0e
commit
613d3b2e82
@ -25,6 +25,9 @@
|
|||||||
@property (strong) IBOutlet NSTextField *vramStatusLabel;
|
@property (strong) IBOutlet NSTextField *vramStatusLabel;
|
||||||
@property (strong) IBOutlet NSTableView *paletteTableView;
|
@property (strong) IBOutlet NSTableView *paletteTableView;
|
||||||
@property (strong) IBOutlet NSTableView *spritesTableView;
|
@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;
|
-(uint8_t) readMemory:(uint16_t) addr;
|
||||||
-(void) writeMemory:(uint16_t) addr value:(uint8_t)value;
|
-(void) writeMemory:(uint16_t) addr value:(uint8_t)value;
|
||||||
|
@ -37,6 +37,9 @@
|
|||||||
uint16_t oamCount;
|
uint16_t oamCount;
|
||||||
uint8_t oamHeight;
|
uint8_t oamHeight;
|
||||||
bool oamUpdating;
|
bool oamUpdating;
|
||||||
|
|
||||||
|
NSMutableData *currentPrinterImageData;
|
||||||
|
enum {GBAccessoryNone, GBAccessoryPrinter} accessory;
|
||||||
}
|
}
|
||||||
|
|
||||||
@property GBAudioClient *audioClient;
|
@property GBAudioClient *audioClient;
|
||||||
@ -46,6 +49,9 @@
|
|||||||
- (const char *) getAsyncDebuggerInput;
|
- (const char *) getAsyncDebuggerInput;
|
||||||
- (void) cameraRequestUpdate;
|
- (void) cameraRequestUpdate;
|
||||||
- (uint8_t) cameraGetPixelAtX:(uint8_t)x andY:(uint8_t)y;
|
- (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
|
@end
|
||||||
|
|
||||||
static void vblank(GB_gameboy_t *gb)
|
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)
|
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)
|
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];
|
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
|
@implementation Document
|
||||||
{
|
{
|
||||||
GB_gameboy_t gb;
|
GB_gameboy_t gb;
|
||||||
@ -132,6 +145,7 @@ static uint8_t cameraGetPixel(GB_gameboy_t *gb, uint8_t x, uint8_t y)
|
|||||||
|
|
||||||
- (void) initCommon
|
- (void) initCommon
|
||||||
{
|
{
|
||||||
|
gb.user_data = (__bridge void *)(self);
|
||||||
GB_set_vblank_callback(&gb, (GB_vblank_callback_t) vblank);
|
GB_set_vblank_callback(&gb, (GB_vblank_callback_t) vblank);
|
||||||
GB_set_log_callback(&gb, (GB_log_callback_t) consoleLog);
|
GB_set_log_callback(&gb, (GB_log_callback_t) consoleLog);
|
||||||
GB_set_input_callback(&gb, (GB_input_callback_t) consoleInput);
|
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_rgb_encode_callback(&gb, rgbEncode);
|
||||||
GB_set_camera_get_pixel_callback(&gb, cameraGetPixel);
|
GB_set_camera_get_pixel_callback(&gb, cameraGetPixel);
|
||||||
GB_set_camera_update_request_callback(&gb, cameraRequestUpdate);
|
GB_set_camera_update_request_callback(&gb, cameraRequestUpdate);
|
||||||
gb.user_data = (__bridge void *)(self);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void) vblank
|
- (void) vblank
|
||||||
@ -271,6 +284,14 @@ static uint8_t cameraGetPixel(GB_gameboy_t *gb, uint8_t x, uint8_t y)
|
|||||||
window_frame.size.height);
|
window_frame.size.height);
|
||||||
[self.mainWindow setFrame:window_frame display:YES];
|
[self.mainWindow setFrame:window_frame display:YES];
|
||||||
self.vramStatusLabel.cell.backgroundStyle = NSBackgroundStyleRaised;
|
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];
|
[self start];
|
||||||
|
|
||||||
}
|
}
|
||||||
@ -400,6 +421,12 @@ static uint8_t cameraGetPixel(GB_gameboy_t *gb, uint8_t x, uint8_t y)
|
|||||||
return false;
|
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];
|
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];
|
[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
|
@end
|
@ -10,6 +10,8 @@
|
|||||||
<outlet property="consoleInput" destination="l22-S8-uji" id="Heu-am-YgB"/>
|
<outlet property="consoleInput" destination="l22-S8-uji" id="Heu-am-YgB"/>
|
||||||
<outlet property="consoleOutput" destination="doS-dM-hnl" id="Gn5-ju-Wb0"/>
|
<outlet property="consoleOutput" destination="doS-dM-hnl" id="Gn5-ju-Wb0"/>
|
||||||
<outlet property="consoleWindow" destination="21F-Ah-yHX" id="eQ4-ug-LsT"/>
|
<outlet property="consoleWindow" destination="21F-Ah-yHX" id="eQ4-ug-LsT"/>
|
||||||
|
<outlet property="feedImageView" destination="Ar0-nN-eop" id="wHa-St-o4G"/>
|
||||||
|
<outlet property="feedSaveButton" destination="RLc-0I-sYZ" id="Yy9-dG-xXY"/>
|
||||||
<outlet property="gridButton" destination="fL6-2S-Rgd" id="jtV-jh-GHC"/>
|
<outlet property="gridButton" destination="fL6-2S-Rgd" id="jtV-jh-GHC"/>
|
||||||
<outlet property="mainWindow" destination="xOd-HO-29H" id="h8M-YB-vcC"/>
|
<outlet property="mainWindow" destination="xOd-HO-29H" id="h8M-YB-vcC"/>
|
||||||
<outlet property="memoryBankInput" destination="rdV-q6-hc6" id="KBx-9T-2mX"/>
|
<outlet property="memoryBankInput" destination="rdV-q6-hc6" id="KBx-9T-2mX"/>
|
||||||
@ -17,6 +19,7 @@
|
|||||||
<outlet property="memoryView" destination="8hr-8o-3rN" id="fF0-rh-8ND"/>
|
<outlet property="memoryView" destination="8hr-8o-3rN" id="fF0-rh-8ND"/>
|
||||||
<outlet property="memoryWindow" destination="mRm-dL-mCj" id="VPR-lu-vtI"/>
|
<outlet property="memoryWindow" destination="mRm-dL-mCj" id="VPR-lu-vtI"/>
|
||||||
<outlet property="paletteTableView" destination="gfC-d3-dmq" id="fTC-eL-Qg3"/>
|
<outlet property="paletteTableView" destination="gfC-d3-dmq" id="fTC-eL-Qg3"/>
|
||||||
|
<outlet property="printerFeedWindow" destination="NdE-0B-WCf" id="yVK-cS-NOJ"/>
|
||||||
<outlet property="spritesTableView" destination="TOc-XJ-w9w" id="O4R-4Z-9hU"/>
|
<outlet property="spritesTableView" destination="TOc-XJ-w9w" id="O4R-4Z-9hU"/>
|
||||||
<outlet property="tilemapImageView" destination="LlK-tV-bjv" id="nSY-Xd-BjZ"/>
|
<outlet property="tilemapImageView" destination="LlK-tV-bjv" id="nSY-Xd-BjZ"/>
|
||||||
<outlet property="tilemapMapButton" destination="YIJ-Qc-SIZ" id="BB7-Gg-7XP"/>
|
<outlet property="tilemapMapButton" destination="YIJ-Qc-SIZ" id="BB7-Gg-7XP"/>
|
||||||
@ -32,7 +35,7 @@
|
|||||||
</customObject>
|
</customObject>
|
||||||
<customObject id="-1" userLabel="First Responder" customClass="FirstResponder"/>
|
<customObject id="-1" userLabel="First Responder" customClass="FirstResponder"/>
|
||||||
<customObject id="-3" userLabel="Application" customClass="NSObject"/>
|
<customObject id="-3" userLabel="Application" customClass="NSObject"/>
|
||||||
<window title="Window" allowsToolTipsWhenApplicationIsInactive="NO" autorecalculatesKeyViewLoop="NO" releasedWhenClosed="NO" visibleAtLaunch="NO" animationBehavior="default" id="xOd-HO-29H" userLabel="Window">
|
<window title="Window" allowsToolTipsWhenApplicationIsInactive="NO" autorecalculatesKeyViewLoop="NO" oneShot="NO" releasedWhenClosed="NO" visibleAtLaunch="NO" animationBehavior="default" id="xOd-HO-29H" userLabel="Window">
|
||||||
<windowStyleMask key="styleMask" titled="YES" closable="YES" miniaturizable="YES" resizable="YES"/>
|
<windowStyleMask key="styleMask" titled="YES" closable="YES" miniaturizable="YES" resizable="YES"/>
|
||||||
<windowCollectionBehavior key="collectionBehavior" fullScreenPrimary="YES"/>
|
<windowCollectionBehavior key="collectionBehavior" fullScreenPrimary="YES"/>
|
||||||
<windowPositionMask key="initialPositionMask" leftStrut="YES" rightStrut="YES" topStrut="YES" bottomStrut="YES"/>
|
<windowPositionMask key="initialPositionMask" leftStrut="YES" rightStrut="YES" topStrut="YES" bottomStrut="YES"/>
|
||||||
@ -679,5 +682,35 @@
|
|||||||
<contentBorderThickness minY="24"/>
|
<contentBorderThickness minY="24"/>
|
||||||
<point key="canvasLocation" x="182" y="760"/>
|
<point key="canvasLocation" x="182" y="760"/>
|
||||||
</window>
|
</window>
|
||||||
|
<window title="Printer Feed" allowsToolTipsWhenApplicationIsInactive="NO" autorecalculatesKeyViewLoop="NO" hidesOnDeactivate="YES" oneShot="NO" releasedWhenClosed="NO" showsToolbarButton="NO" visibleAtLaunch="NO" animationBehavior="default" id="NdE-0B-WCf" customClass="NSPanel">
|
||||||
|
<windowStyleMask key="styleMask" titled="YES" closable="YES"/>
|
||||||
|
<windowPositionMask key="initialPositionMask" leftStrut="YES" rightStrut="YES" topStrut="YES" bottomStrut="YES"/>
|
||||||
|
<rect key="contentRect" x="272" y="172" width="320" height="288"/>
|
||||||
|
<rect key="screenRect" x="0.0" y="0.0" width="2560" height="1417"/>
|
||||||
|
<view key="contentView" id="RRS-aa-bPT">
|
||||||
|
<rect key="frame" x="0.0" y="0.0" width="320" height="288"/>
|
||||||
|
<autoresizingMask key="autoresizingMask"/>
|
||||||
|
<subviews>
|
||||||
|
<imageView horizontalHuggingPriority="251" verticalHuggingPriority="251" id="Ar0-nN-eop" customClass="GBImageView">
|
||||||
|
<rect key="frame" x="0.0" y="0.0" width="320" height="288"/>
|
||||||
|
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
||||||
|
<imageCell key="cell" refusesFirstResponder="YES" alignment="left" imageAlignment="topLeft" id="sff-hk-4nM"/>
|
||||||
|
</imageView>
|
||||||
|
</subviews>
|
||||||
|
</view>
|
||||||
|
<point key="canvasLocation" x="-159" y="356"/>
|
||||||
|
</window>
|
||||||
|
<button verticalHuggingPriority="750" id="RLc-0I-sYZ">
|
||||||
|
<rect key="frame" x="0.0" y="0.0" width="48" height="25"/>
|
||||||
|
<autoresizingMask key="autoresizingMask" flexibleMinX="YES" flexibleMinY="YES"/>
|
||||||
|
<buttonCell key="cell" type="roundTextured" title="Save" bezelStyle="texturedRounded" alignment="center" controlSize="mini" borderStyle="border" imageScaling="proportionallyDown" inset="2" id="shw-MJ-B3T">
|
||||||
|
<behavior key="behavior" pushIn="YES" lightByBackground="YES" lightByGray="YES"/>
|
||||||
|
<font key="font" metaFont="miniSystem"/>
|
||||||
|
</buttonCell>
|
||||||
|
<connections>
|
||||||
|
<action selector="savePrinterFeed:" target="-2" id="Y3g-fU-2te"/>
|
||||||
|
</connections>
|
||||||
|
<point key="canvasLocation" x="-507" y="397"/>
|
||||||
|
</button>
|
||||||
</objects>
|
</objects>
|
||||||
</document>
|
</document>
|
||||||
|
@ -339,6 +339,25 @@
|
|||||||
</items>
|
</items>
|
||||||
</menu>
|
</menu>
|
||||||
</menuItem>
|
</menuItem>
|
||||||
|
<menuItem title="Connectivity" id="IcW-ZC-4wb">
|
||||||
|
<modifierMask key="keyEquivalentModifierMask"/>
|
||||||
|
<menu key="submenu" title="Connectivity" id="BDM-Cv-BOm">
|
||||||
|
<items>
|
||||||
|
<menuItem title="None" id="SiH-Q4-OBY">
|
||||||
|
<modifierMask key="keyEquivalentModifierMask"/>
|
||||||
|
<connections>
|
||||||
|
<action selector="disconnectAllAccessories:" target="-1" id="5hY-9U-nRn"/>
|
||||||
|
</connections>
|
||||||
|
</menuItem>
|
||||||
|
<menuItem title="GameBoy Printer" id="zHR-Ha-pOR">
|
||||||
|
<modifierMask key="keyEquivalentModifierMask"/>
|
||||||
|
<connections>
|
||||||
|
<action selector="connectPrinter:" target="-1" id="tl1-CL-tAw"/>
|
||||||
|
</connections>
|
||||||
|
</menuItem>
|
||||||
|
</items>
|
||||||
|
</menu>
|
||||||
|
</menuItem>
|
||||||
<menuItem title="Developer" id="IwX-DJ-dBk">
|
<menuItem title="Developer" id="IwX-DJ-dBk">
|
||||||
<modifierMask key="keyEquivalentModifierMask"/>
|
<modifierMask key="keyEquivalentModifierMask"/>
|
||||||
<menu key="submenu" title="Developer" id="UVb-cc-at0">
|
<menu key="submenu" title="Developer" id="UVb-cc-at0">
|
||||||
|
Loading…
Reference in New Issue
Block a user