Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions Boxer/DOS window/BXDOSWindowController.h
Original file line number Diff line number Diff line change
Expand Up @@ -170,6 +170,10 @@ extern NSNotificationName const BXViewDidLiveResizeNotification;
/// Toggle the emulator's active rendering filter.
- (IBAction) toggleRenderingStyle: (id)sender;

/// Refresh and select presets from the bundled custom shader menu.
- (IBAction) refreshShaderPresetMenu: (id)sender;
- (IBAction) selectShaderPreset: (id)sender;

/// Increase the draw size of the fullscreen window.
- (IBAction) incrementFullscreenSize: (id)sender;
/// Decrease the draw size of the fullscreen window.
Expand Down
66 changes: 63 additions & 3 deletions Boxer/DOS window/BXDOSWindowController.m
Original file line number Diff line number Diff line change
Expand Up @@ -166,6 +166,15 @@ - (void) windowDidLoad

//Display the loading panel by default.
[self switchToPanel: BXDOSWindowLoadingPanel animate: NO];

NSString *savedShaderPresetPath = [[NSUserDefaults standardUserDefaults] stringForKey:@"shaderPresetPath"];
if (savedShaderPresetPath.length > 0)
{
if (![self.renderingView loadShaderPresetAtPath:savedShaderPresetPath])
{
[[NSUserDefaults standardUserDefaults] removeObjectForKey:@"shaderPresetPath"];
}
}

self.window.preservesContentDuringLiveResize = NO;
self.window.acceptsMouseMovedEvents = YES;
Expand Down Expand Up @@ -458,10 +467,46 @@ - (IBAction) toggleShaderParametersWindow: (id)sender
- (IBAction) toggleRenderingStyle: (id <NSValidatedUserInterfaceItem>)sender
{
BXRenderingStyle style = (BXRenderingStyle)sender.tag;
[[NSUserDefaults standardUserDefaults] removeObjectForKey:@"shaderPresetPath"];
self.renderingView.renderingStyle = style;
[[NSUserDefaults standardUserDefaults] setInteger: style
forKey: @"renderingStyle"];
}

- (IBAction)refreshShaderPresetMenu:(id)sender
{
// The menu is populated during validation immediately before it is displayed.
}

- (IBAction)selectShaderPreset:(NSMenuItem *)sender
{
NSString *presetPath = sender.representedObject;
if (![presetPath isKindOfClass:NSString.class])
{
return;
}

if ([self.renderingView loadShaderPresetAtPath:presetPath])
{
[[NSUserDefaults standardUserDefaults] setObject:presetPath forKey:@"shaderPresetPath"];
}
}

- (void)populateShaderPresetMenu:(NSMenu *)menu
{
[menu removeAllItems];
for (NSString *presetPath in self.renderingView.availableShaderPresetPaths)
{
NSString *title = presetPath.lastPathComponent.stringByDeletingPathExtension;
NSMenuItem *item = [[NSMenuItem alloc] initWithTitle:title
action:@selector(selectShaderPreset:)
keyEquivalent:@""];
item.target = nil;
item.representedObject = presetPath;
[menu addItem:item];
}
}

- (IBAction) toggleHerculesTintMode: (id <NSValidatedUserInterfaceItem>)sender
{
BXHerculesTintMode tint = (BXHerculesTintMode)sender.tag;
Expand Down Expand Up @@ -926,16 +971,31 @@ - (BOOL) validateMenuItem: (NSMenuItem *)theItem
if (theAction == @selector(toggleRenderingStyle:))
{
BXRenderingStyle renderingStyle = (BXRenderingStyle)theItem.tag;
if (renderingStyle == self.renderingStyle)
if (renderingStyle == self.renderingStyle &&
[[NSUserDefaults standardUserDefaults] stringForKey:@"shaderPresetPath"].length == 0)
{
theItem.state = NSControlStateValueOn;
}
else
{
theItem.state = NSControlStateValueOff;
}
return YES;
}
return YES;
}

if (theAction == @selector(refreshShaderPresetMenu:))
{
[self populateShaderPresetMenu:theItem.submenu];
return YES;
}

if (theAction == @selector(selectShaderPreset:))
{
NSString *presetPath = theItem.representedObject;
theItem.state = [presetPath isEqualToString:self.renderingView.selectedShaderPresetPath]
? NSControlStateValueOn : NSControlStateValueOff;
return YES;
}

if (theAction == @selector(toggleHerculesTintMode:))
{
Expand Down
78 changes: 67 additions & 11 deletions Boxer/Metal Rendering/BXMetalRenderingView.m
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ @implementation BXMetalRenderingView {
NSRect _viewportRect;
NSRect _targetViewportRect;
BXRenderingStyle _renderingStyle;
NSString *_selectedShaderPresetPath;
}

@synthesize currentFrame=_currentFrame;
Expand Down Expand Up @@ -100,39 +101,94 @@ - (BOOL)supportsRenderingStyle:(BXRenderingStyle)style {
return YES;
}

- (void)setRenderingStyle:(BXRenderingStyle)renderingStyle {
if (renderingStyle == _renderingStyle)
- (NSArray<NSString *> *)availableShaderPresetPaths
{
NSURL *shadersURL = [NSBundle.mainBundle.resourceURL URLByAppendingPathComponent:@"Shaders" isDirectory:YES];
NSDirectoryEnumerator<NSURL *> *enumerator = [[NSFileManager defaultManager]
enumeratorAtURL:shadersURL
includingPropertiesForKeys:@[NSURLIsRegularFileKey]
options:(NSDirectoryEnumerationSkipsHiddenFiles | NSDirectoryEnumerationSkipsPackageDescendants)
errorHandler:nil];

if (enumerator == nil)
{
return;
return @[];
}


NSMutableArray<NSString *> *presetPaths = [NSMutableArray array];
for (NSURL *presetURL in enumerator)
{
NSNumber *isRegularFile = nil;
[presetURL getResourceValue:&isRegularFile forKey:NSURLIsRegularFileKey error:nil];
if (!isRegularFile.boolValue || ![presetURL.pathExtension.lowercaseString isEqualToString:@"slangp"])
{
continue;
}

NSString *relativePath = [presetURL.path substringFromIndex:shadersURL.path.length];
relativePath = [relativePath stringByTrimmingCharactersInSet:[NSCharacterSet characterSetWithCharactersInString:@"/"]];
if (relativePath.length > 0)
{
[presetPaths addObject:relativePath];
}
}

[presetPaths sortUsingComparator:^NSComparisonResult(NSString *first, NSString *second) {
return [first.lastPathComponent localizedStandardCompare:second.lastPathComponent];
}];
return presetPaths;
}

- (NSString *)selectedShaderPresetPath
{
return _selectedShaderPresetPath;
}

- (BOOL)loadShaderPresetAtPath:(NSString *)presetPath
{
if (presetPath.length == 0 || ![self.availableShaderPresetPaths containsObject:presetPath])
{
return NO;
}

NSURL *shadersURL = [NSBundle.mainBundle.resourceURL URLByAppendingPathComponent:@"Shaders" isDirectory:YES];
NSURL *presetURL = [shadersURL URLByAppendingPathComponent:presetPath];
NSError *error = nil;
if (![_filterChain setShaderFromURL:presetURL error:&error])
{
NSLog(@"Could not load shader preset at %@: %@", presetPath, error.localizedDescription);
return NO;
}

_selectedShaderPresetPath = [presetPath copy];
self.parameterGroups = _filterChain.shader.parameterGroups;
return YES;
}

- (void)setRenderingStyle:(BXRenderingStyle)renderingStyle {
[self willChangeValueForKey:@"renderingStyle"];

_renderingStyle = renderingStyle;

switch (renderingStyle) {
case BXRenderingStyleNormal: {
NSURL *path = [NSBundle.mainBundle URLForResource:@"Pixellate" withExtension:@"slangp" subdirectory:@"Shaders/Pixellate"];
[_filterChain setShaderFromURL:path error:nil];
[self loadShaderPresetAtPath:@"Pixellate/Pixellate.slangp"];
break;
}

case BXRenderingStyleCRT: {
NSURL *path = [NSBundle.mainBundle URLForResource:@"CRT Geom" withExtension:@"slangp" subdirectory:@"Shaders/CRT Geom"];
[_filterChain setShaderFromURL:path error:nil];
[self loadShaderPresetAtPath:@"CRT Geom/CRT Geom.slangp"];
break;
}

case BXRenderingStyleSmoothed: {
NSURL *path = [NSBundle.mainBundle URLForResource:@"Smooth" withExtension:@"slangp" subdirectory:@"Shaders/Smooth"];
[_filterChain setShaderFromURL:path error:nil];
[self loadShaderPresetAtPath:@"Smooth/Smooth.slangp"];
break;
}
}

[self didChangeValueForKey:@"renderingStyle"];

self.parameterGroups = _filterChain.shader.parameterGroups;
}

- (void)updateWithFrame:(BXVideoFrame *)frame {
Expand Down
10 changes: 10 additions & 0 deletions Boxer/Rendering/BXFrameRenderingView.h
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,16 @@ typedef NS_ENUM(NSInteger, BXRenderingStyle) {
/// Set/get the current rendering style of the view.
@property (readwrite, nonatomic) BXRenderingStyle renderingStyle;

/// Relative paths of the shader presets available in the application bundle.
@property (readonly, nonatomic) NSArray<NSString *> *availableShaderPresetPaths;

/// The relative path of the currently loaded shader preset, if known.
@property (readonly, nullable, nonatomic) NSString *selectedShaderPresetPath;

/// Loads a shader preset discovered in availableShaderPresetPaths.
/// Returns NO without changing the current shader if the preset cannot be found or loaded.
- (BOOL)loadShaderPresetAtPath:(NSString *)presetPath;

/// Whether this rendering view can render in the specified style.
- (BOOL) supportsRenderingStyle: (BXRenderingStyle)style;

Expand Down
8 changes: 8 additions & 0 deletions Resources/Base.lproj/MainMenu.xib
Original file line number Diff line number Diff line change
Expand Up @@ -509,6 +509,14 @@
<action selector="toggleRenderingStyle:" target="-1" id="2384"/>
</connections>
</menuItem>
<menuItem isSeparatorItem="YES" id="shader-separator"/>
<menuItem title="Custom Shaders" id="custom-shaders-item">
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="refreshShaderPresetMenu:" target="-1" id="refresh-custom-shaders"/>
</connections>
<menu key="submenu" title="Custom Shaders" id="custom-shaders-menu"/>
</menuItem>
</items>
</menu>
</menuItem>
Expand Down
24 changes: 24 additions & 0 deletions Resources/mul.lproj/MainMenu.xcstrings
Original file line number Diff line number Diff line change
Expand Up @@ -5011,6 +5011,30 @@
}
}
},
"custom-shaders-item.title" : {
"comment" : "Class = \"NSMenuItem\"; title = \"Custom Shaders\"; ObjectID = \"custom-shaders-item\";",
"extractionState" : "extracted_with_value",
"localizations" : {
"en" : {
"stringUnit" : {
"state" : "new",
"value" : "Custom Shaders"
}
}
}
},
"custom-shaders-menu.title" : {
"comment" : "Class = \"NSMenu\"; title = \"Custom Shaders\"; ObjectID = \"custom-shaders-menu\";",
"extractionState" : "extracted_with_value",
"localizations" : {
"en" : {
"stringUnit" : {
"state" : "new",
"value" : "Custom Shaders"
}
}
}
},
"Wks-tC-vJz.title" : {
"comment" : "Class = \"NSMenuItem\"; title = \"Shader Properties…\"; ObjectID = \"Wks-tC-vJz\";",
"extractionState" : "extracted_with_value",
Expand Down
Loading