From f02bb2f0e6c5beafd4f5b0d8ddec799d23d2e3dc Mon Sep 17 00:00:00 2001 From: Lior Halphon Date: Sun, 20 Feb 2022 01:58:59 +0200 Subject: [PATCH] New and faster OAM viewer --- Cocoa/Document.h | 7 +- Cocoa/Document.m | 89 +++++++---------------- Cocoa/Document.xib | 144 +++++-------------------------------- Cocoa/GBImageCell.h | 5 -- Cocoa/GBImageCell.m | 10 --- Cocoa/GBObjectView.h | 6 ++ Cocoa/GBObjectView.m | 113 +++++++++++++++++++++++++++++ Cocoa/GBObjectViewItem.xib | 94 ++++++++++++++++++++++++ 8 files changed, 259 insertions(+), 209 deletions(-) delete mode 100644 Cocoa/GBImageCell.h delete mode 100644 Cocoa/GBImageCell.m create mode 100644 Cocoa/GBObjectView.h create mode 100644 Cocoa/GBObjectView.m create mode 100644 Cocoa/GBObjectViewItem.xib diff --git a/Cocoa/Document.h b/Cocoa/Document.h index 2cfaa87..0b1d81c 100644 --- a/Cocoa/Document.h +++ b/Cocoa/Document.h @@ -6,6 +6,7 @@ #include "GBOSDView.h" @class GBCheatWindowController; +@class GBObjectView; @interface Document : NSDocument @property (nonatomic, readonly) GB_gameboy_t *gb; @@ -30,7 +31,7 @@ @property (nonatomic, strong) IBOutlet NSPanel *vramWindow; @property (nonatomic, strong) IBOutlet NSTextField *vramStatusLabel; @property (nonatomic, strong) IBOutlet NSTableView *paletteTableView; -@property (nonatomic, strong) IBOutlet NSTableView *objectsTableView; +@property (nonatomic, strong) IBOutlet GBObjectView *objectView; @property (nonatomic, strong) IBOutlet NSPanel *printerFeedWindow; @property (nonatomic, strong) IBOutlet NSImageView *feedImageView; @property (nonatomic, strong) IBOutlet NSTextView *debuggerSideViewInput; @@ -51,7 +52,11 @@ @property (strong) IBOutlet NSSegmentedControl *gbsNextPrevButton; @property (strong) IBOutlet GBVisualizerView *gbsVisualizer; @property (strong) IBOutlet GBOSDView *osdView; +@property (readonly) GB_oam_info_t *oamInfo; +@property uint8_t oamCount; +@property uint8_t oamHeight; ++ (NSImage *) imageFromData:(NSData *)data width:(NSUInteger) width height:(NSUInteger) height scale:(double) scale; -(uint8_t) readMemory:(uint16_t) addr; -(void) writeMemory:(uint16_t) addr value:(uint8_t)value; -(void) performAtomicBlock: (void (^)())block; diff --git a/Cocoa/Document.m b/Cocoa/Document.m index dd97ac5..e2dfb43 100644 --- a/Cocoa/Document.m +++ b/Cocoa/Document.m @@ -1,16 +1,18 @@ -#include -#include -#include -#include "GBAudioClient.h" -#include "Document.h" -#include "AppDelegate.h" -#include "HexFiend/HexFiend.h" -#include "GBMemoryByteArray.h" -#include "GBWarningPopover.h" -#include "GBCheatWindowController.h" -#include "GBTerminalTextFieldCell.h" -#include "BigSurToolbar.h" +#import +#import +#import +#import "GBAudioClient.h" +#import "Document.h" +#import "AppDelegate.h" +#import "HexFiend/HexFiend.h" +#import "GBMemoryByteArray.h" +#import "GBWarningPopover.h" +#import "GBCheatWindowController.h" +#import "GBTerminalTextFieldCell.h" +#import "BigSurToolbar.h" #import "GBPaletteEditorController.h" +#import "GBObjectView.h" + #define GB_MODEL_PAL_BIT_OLD 0x1000 @@ -46,10 +48,7 @@ enum model { AVCaptureConnection *cameraConnection; AVCaptureStillImageOutput *cameraOutput; - GB_oam_info_t oamInfo[40]; - uint16_t oamCount; - uint8_t oamHeight; - bool oamUpdating; + GB_oam_info_t _oamInfo[40]; NSMutableData *currentPrinterImageData; enum {GBAccessoryNone, GBAccessoryPrinter, GBAccessoryWorkboy, GBAccessoryLinkCable} accessory; @@ -1467,13 +1466,9 @@ static unsigned *multiplication_table_for_frequency(unsigned frequency) case 2: /* OAM */ { - oamCount = GB_get_oam_info(&gb, oamInfo, &oamHeight); + _oamCount = GB_get_oam_info(&gb, _oamInfo, &_oamHeight); dispatch_async(dispatch_get_main_queue(), ^{ - if (!oamUpdating) { - oamUpdating = true; - [self.objectsTableView reloadData]; - oamUpdating = false; - } + [self.objectView reloadData:self]; }); } break; @@ -1749,10 +1744,10 @@ static unsigned *multiplication_table_for_frequency(unsigned frequency) window_rect.origin.y += window_rect.size.height; switch ([sender selectedSegment]) { case 0: + case 2: window_rect.size.height = 384 + height_diff + 48; break; case 1: - case 2: window_rect.size.height = 512 + height_diff + 48; break; case 3: @@ -1834,12 +1829,14 @@ static unsigned *multiplication_table_for_frequency(unsigned frequency) if (tableView == self.paletteTableView) { return 16; /* 8 BG palettes, 8 OBJ palettes*/ } - else if (tableView == self.objectsTableView) { - return oamCount; - } return 0; } +- (GB_oam_info_t *)oamInfo +{ + return _oamInfo; +} + - (id)tableView:(NSTableView *)tableView objectValueForTableColumn:(NSTableColumn *)tableColumn row:(NSInteger)row { NSUInteger columnIndex = [[tableView tableColumns] indexOfObject:tableColumn]; @@ -1853,50 +1850,12 @@ static unsigned *multiplication_table_for_frequency(unsigned frequency) uint16_t index = columnIndex - 1 + (row & 7) * 4; return @((palette_data[(index << 1) + 1] << 8) | palette_data[(index << 1)]); } - else if (tableView == self.objectsTableView) { - switch (columnIndex) { - case 0: - return [Document imageFromData:[NSData dataWithBytesNoCopy:oamInfo[row].image - length:64 * 4 * 2 - freeWhenDone:false] - width:8 - height:oamHeight - scale:16.0/oamHeight]; - case 1: - return @((signed)((unsigned)oamInfo[row].x - 8)); - case 2: - return @((signed)((unsigned)oamInfo[row].y - 16)); - case 3: - return [NSString stringWithFormat:@"$%02x", oamInfo[row].tile]; - case 4: - return [NSString stringWithFormat:@"$%04x", 0x8000 + oamInfo[row].tile * 0x10]; - case 5: - return [NSString stringWithFormat:@"$%04x", oamInfo[row].oam_addr]; - case 6: - if (GB_is_cgb(&gb)) { - return [NSString stringWithFormat:@"%c%c%c%d%d", - oamInfo[row].flags & 0x80? 'P' : '-', - oamInfo[row].flags & 0x40? 'Y' : '-', - oamInfo[row].flags & 0x20? 'X' : '-', - oamInfo[row].flags & 0x08? 1 : 0, - oamInfo[row].flags & 0x07]; - } - return [NSString stringWithFormat:@"%c%c%c%d", - oamInfo[row].flags & 0x80? 'P' : '-', - oamInfo[row].flags & 0x40? 'Y' : '-', - oamInfo[row].flags & 0x20? 'X' : '-', - oamInfo[row].flags & 0x10? 1 : 0]; - case 7: - return oamInfo[row].obscured_by_line_limit? @"Dropped: Too many objects in line": @""; - - } - } return nil; } - (BOOL)tableView:(NSTableView *)tableView shouldSelectRow:(NSInteger)row { - return tableView == self.objectsTableView; + return false; } - (BOOL)tableView:(NSTableView *)tableView shouldEditTableColumn:(nullable NSTableColumn *)tableColumn row:(NSInteger)row diff --git a/Cocoa/Document.xib b/Cocoa/Document.xib index 2787aa3..be5cdea 100644 --- a/Cocoa/Document.xib +++ b/Cocoa/Document.xib @@ -25,7 +25,7 @@ - + @@ -346,7 +346,7 @@ - + @@ -503,145 +503,33 @@ - + - + - + - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + - + - @@ -983,7 +871,7 @@ - + diff --git a/Cocoa/GBImageCell.h b/Cocoa/GBImageCell.h deleted file mode 100644 index 0323b41..0000000 --- a/Cocoa/GBImageCell.h +++ /dev/null @@ -1,5 +0,0 @@ -#import - -@interface GBImageCell : NSImageCell - -@end diff --git a/Cocoa/GBImageCell.m b/Cocoa/GBImageCell.m deleted file mode 100644 index de75e0e..0000000 --- a/Cocoa/GBImageCell.m +++ /dev/null @@ -1,10 +0,0 @@ -#import "GBImageCell.h" - -@implementation GBImageCell -- (void)drawWithFrame:(NSRect)cellFrame inView:(NSView *)controlView -{ - CGContextRef context = [[NSGraphicsContext currentContext] graphicsPort]; - CGContextSetInterpolationQuality(context, kCGInterpolationNone); - [super drawWithFrame:cellFrame inView:controlView]; -} -@end diff --git a/Cocoa/GBObjectView.h b/Cocoa/GBObjectView.h new file mode 100644 index 0000000..2d1c955 --- /dev/null +++ b/Cocoa/GBObjectView.h @@ -0,0 +1,6 @@ +#import +#import "Document.h" + +@interface GBObjectView : NSView +- (void)reloadData:(Document *)document; +@end diff --git a/Cocoa/GBObjectView.m b/Cocoa/GBObjectView.m new file mode 100644 index 0000000..0532525 --- /dev/null +++ b/Cocoa/GBObjectView.m @@ -0,0 +1,113 @@ +#import "GBObjectView.h" + +@interface GBObjectViewItem : NSObject +@property IBOutlet NSView *view; +@property IBOutlet NSImageView *image; +@property IBOutlet NSTextField *oamAddress; +@property IBOutlet NSTextField *position; +@property IBOutlet NSTextField *attributes; +@property IBOutlet NSTextField *tile; +@property IBOutlet NSTextField *tileAddress; +@property IBOutlet NSImageView *warningIcon; +@property IBOutlet NSBox *verticalLine; +@end + +@implementation GBObjectViewItem +@end + +@implementation GBObjectView +{ + NSMutableArray *_items; +} + +- (instancetype)initWithCoder:(NSCoder *)coder +{ + self = [super initWithCoder:coder]; + _items = [NSMutableArray array]; + CGFloat height = self.frame.size.height; + for (unsigned i = 0; i < 40; i++) { + GBObjectViewItem *item = [[GBObjectViewItem alloc] init]; + [_items addObject:item]; + [[NSBundle mainBundle] loadNibNamed:@"GBObjectViewItem" owner:item topLevelObjects:nil]; + item.view.hidden = true; + [self addSubview:item.view]; + [item.view setFrameOrigin:NSMakePoint((i % 4) * 120, height - (i / 4 * 68) - 68)]; + item.oamAddress.toolTip = @"OAM address"; + item.position.toolTip = @"Position"; + item.attributes.toolTip = @"Attributes"; + item.tile.toolTip = @"Tile index"; + item.tileAddress.toolTip = @"Tile address"; + item.warningIcon.toolTip = @"Dropped: too many objects in line"; + if ((i % 4) == 3) { + [item.verticalLine removeFromSuperview]; + } + item.view.autoresizingMask = NSViewMaxXMargin | NSViewMinYMargin; + } + return self; +} + +- (void)reloadData:(Document *)document +{ + GB_oam_info_t *info = document.oamInfo; + uint8_t length = document.oamCount; + bool cgb = GB_is_cgb(document.gb); + uint8_t height = document.oamHeight; + for (unsigned i = 0; i < 40; i++) { + GBObjectViewItem *item = _items[i]; + if (i >= length) { + item.view.hidden = true; + } + else { + item.view.hidden = false; + item.oamAddress.stringValue = [NSString stringWithFormat:@"$%04X", info[i].oam_addr]; + item.position.stringValue = [NSString stringWithFormat:@"(%d, %d)", + ((signed)(unsigned)info[i].x) - 8, + ((signed)(unsigned)info[i].y) - 16]; + item.tile.stringValue = [NSString stringWithFormat:@"$%02X", info[i].tile]; + item.tileAddress.stringValue = [NSString stringWithFormat:@"$%04X", 0x8000 + info[i].tile * 0x10]; + item.warningIcon.hidden = !info[i].obscured_by_line_limit; + if (cgb) { + item.attributes.stringValue = [NSString stringWithFormat:@"%c%c%c%d%d", + info[i].flags & 0x80? 'P' : '-', + info[i].flags & 0x40? 'Y' : '-', + info[i].flags & 0x20? 'X' : '-', + info[i].flags & 0x08? 1 : 0, + info[i].flags & 0x07]; + } + else { + item.attributes.stringValue = [NSString stringWithFormat:@"%c%c%c%d", + info[i].flags & 0x80? 'P' : '-', + info[i].flags & 0x40? 'Y' : '-', + info[i].flags & 0x20? 'X' : '-', + info[i].flags & 0x10? 1 : 0]; + } + item.image.image = [Document imageFromData:[NSData dataWithBytesNoCopy:info[i].image + length:64 * 4 * 2 + freeWhenDone:false] + width:8 + height:height + scale:32.0 / height]; + } + } + + NSRect frame = self.frame; + CGFloat newHeight = MAX(68 * ((length + 3) / 4), 408); + frame.origin.y -= newHeight - frame.size.height; + frame.size.height = newHeight; + self.frame = frame; +} + +- (void)drawRect:(NSRect)dirtyRect +{ + if (@available(macOS 10.14, *)) { + [[NSColor alternatingContentBackgroundColors].lastObject setFill]; + } + else { + [[NSColor colorWithDeviceWhite:0.96 alpha:1] setFill]; + } + NSRect frame = self.frame; + for (unsigned i = 1; i <= 5; i++) { + NSRectFill(NSMakeRect(0, frame.size.height - i * 68 * 2, frame.size.width, 68)); + } +} +@end diff --git a/Cocoa/GBObjectViewItem.xib b/Cocoa/GBObjectViewItem.xib new file mode 100644 index 0000000..85b3782 --- /dev/null +++ b/Cocoa/GBObjectViewItem.xib @@ -0,0 +1,94 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +