1
0
mirror of https://github.com/TomHarte/CLK.git synced 2024-07-09 21:29:53 +00:00

Merge pull request #947 from TomHarte/AppleIISquarePixels

Adds optional square pixel output for the Apple II
This commit is contained in:
Thomas Harte 2021-06-08 18:04:08 -04:00 committed by GitHub
commit 95a52a9f62
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
14 changed files with 225 additions and 28 deletions

View File

@ -787,12 +787,14 @@ template <Analyser::Static::AppleII::Target::Model model> class ConcreteMachine:
std::unique_ptr<Reflection::Struct> get_options() final {
auto options = std::make_unique<Options>(Configurable::OptionsType::UserFriendly);
options->output = get_video_signal_configurable();
options->use_square_pixels = video_.get_use_square_pixels();
return options;
}
void set_options(const std::unique_ptr<Reflection::Struct> &str) {
const auto options = dynamic_cast<Options *>(str.get());
set_video_signal_configurable(options->output);
video_.set_use_square_pixels(options->use_square_pixels);
}
// MARK: MediaTarget

View File

@ -30,8 +30,11 @@ class Machine {
class Options: public Reflection::StructImpl<Options>, public Configurable::DisplayOption<Options> {
friend Configurable::DisplayOption<Options>;
public:
Options(Configurable::OptionsType) : Configurable::DisplayOption<Options>(Configurable::Display::CompositeColour) {
bool use_square_pixels = false;
Options(Configurable::OptionsType) : Configurable::DisplayOption<Options>(Configurable::Display::CompositeColour) {
if(needs_declare()) {
DeclareField(use_square_pixels);
declare_display_option();
limit_enum(&output, Configurable::Display::CompositeMonochrome, Configurable::Display::CompositeColour, -1);
}

View File

@ -15,9 +15,8 @@ VideoBase::VideoBase(bool is_iie, std::function<void(Cycles)> &&target) :
crt_(910, 1, Outputs::Display::Type::NTSC60, Outputs::Display::InputDataType::Luminance1),
is_iie_(is_iie) {
// Show only the centre 75% of the TV frame.
crt_.set_display_type(Outputs::Display::DisplayType::CompositeColour);
crt_.set_visible_area(Outputs::Display::Rect(0.118f, 0.122f, 0.77f, 0.77f));
set_use_square_pixels(use_square_pixels_);
// TODO: there seems to be some sort of bug whereby switching modes can cause
// a signal discontinuity that knocks phase out of whack. So it isn't safe to
@ -26,6 +25,41 @@ VideoBase::VideoBase(bool is_iie, std::function<void(Cycles)> &&target) :
// crt_.set_immediate_default_phase(0.5f);
}
void VideoBase::set_use_square_pixels(bool use_square_pixels) {
use_square_pixels_ = use_square_pixels;
// HYPER-UGLY HACK. See correlated hack in the Macintosh.
#ifdef __APPLE__
crt_.set_visible_area(Outputs::Display::Rect(0.128f, 0.122f, 0.75f, 0.77f));
#else
if(use_square_pixels) {
crt_.set_visible_area(Outputs::Display::Rect(0.128f, 0.112f, 0.75f, 0.73f));
} else {
crt_.set_visible_area(Outputs::Display::Rect(0.128f, 0.12f, 0.75f, 0.77f));
}
#endif
if(use_square_pixels) {
// From what I can make out, many contemporary Apple II monitors were
// calibrated slightly to stretch the Apple II's display slightly wider
// than it should be per the NTSC standards, for approximately square
// pixels. This reproduces that.
// 243 lines and 52µs are visible.
// i.e. to be square, 1 pixel should be: (1/243 * 52) * (3/4) = 156/972 = 39/243 µs
// On an Apple II each pixel is actually 1/7µs.
// Therefore the adjusted aspect ratio should be (4/3) * (39/243)/(1/7) = (4/3) * 273/243 = 1092/729 = 343/243 ~= 1.412
crt_.set_aspect_ratio(343.0f / 243.0f);
} else {
// Standard NTSC aspect ratio.
crt_.set_aspect_ratio(4.0f / 3.0f);
}
}
bool VideoBase::get_use_square_pixels() {
return use_square_pixels_;
}
void VideoBase::set_scan_target(Outputs::Display::ScanTarget *scan_target) {
crt_.set_scan_target(scan_target);
}

View File

@ -51,8 +51,14 @@ class VideoBase: public VideoSwitches<Cycles> {
/// Gets the type of output.
Outputs::Display::DisplayType get_display_type() const;
/// Sets whether the current CRT should be recalibrated away from normative NTSC
/// to produce square pixels in 40-column text mode.
void set_use_square_pixels(bool);
bool get_use_square_pixels();
protected:
Outputs::CRT::CRT crt_;
bool use_square_pixels_ = false;
// State affecting output video stream generation.
uint8_t *pixel_pointer_ = nullptr;

View File

@ -15,6 +15,8 @@
4B051C912669C90B00CA44E8 /* ROMCatalogue.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4B051C5826670A9300CA44E8 /* ROMCatalogue.cpp */; };
4B051C922669C90B00CA44E8 /* ROMCatalogue.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4B051C5826670A9300CA44E8 /* ROMCatalogue.cpp */; };
4B051C93266D9D6900CA44E8 /* ROMImages in Resources */ = {isa = PBXBuildFile; fileRef = 4BC9DF441D044FCA00F44158 /* ROMImages */; };
4B051C95266EF50200CA44E8 /* AppleIIOptionsPanel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4B051C94266EF50200CA44E8 /* AppleIIOptionsPanel.swift */; };
4B051C97266EF5F600CA44E8 /* CSAppleII.mm in Sources */ = {isa = PBXBuildFile; fileRef = 4B051C96266EF5F600CA44E8 /* CSAppleII.mm */; };
4B05401E219D1618001BF69C /* ScanTarget.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4B05401D219D1618001BF69C /* ScanTarget.cpp */; };
4B05401F219D1618001BF69C /* ScanTarget.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4B05401D219D1618001BF69C /* ScanTarget.cpp */; };
4B055A7A1FAE78A00060FFFF /* SDL2.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 4B055A771FAE78210060FFFF /* SDL2.framework */; };
@ -1023,6 +1025,9 @@
4B04B65622A58CB40006AB58 /* Target.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = Target.hpp; sourceTree = "<group>"; };
4B051C5826670A9300CA44E8 /* ROMCatalogue.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = ROMCatalogue.cpp; sourceTree = "<group>"; };
4B051C5926670A9300CA44E8 /* ROMCatalogue.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = ROMCatalogue.hpp; sourceTree = "<group>"; };
4B051C94266EF50200CA44E8 /* AppleIIOptionsPanel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AppleIIOptionsPanel.swift; sourceTree = "<group>"; };
4B051C96266EF5F600CA44E8 /* CSAppleII.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; path = CSAppleII.mm; sourceTree = "<group>"; };
4B051C98266EF60500CA44E8 /* CSAppleII.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = CSAppleII.h; sourceTree = "<group>"; };
4B05401D219D1618001BF69C /* ScanTarget.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = ScanTarget.cpp; sourceTree = "<group>"; };
4B055A6A1FAE763F0060FFFF /* Clock Signal Kiosk */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = "Clock Signal Kiosk"; sourceTree = BUILT_PRODUCTS_DIR; };
4B055A771FAE78210060FFFF /* SDL2.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = SDL2.framework; path = ../../../../Library/Frameworks/SDL2.framework; sourceTree = SOURCE_ROOT; };
@ -2405,8 +2410,10 @@
4B2A53981D117D36003C6002 /* Wrappers */ = {
isa = PBXGroup;
children = (
4B051C98266EF60500CA44E8 /* CSAppleII.h */,
4B2A53991D117D36003C6002 /* CSAtari2600.h */,
4B14978D1EE4B4D200CE2596 /* CSZX8081.h */,
4B051C96266EF5F600CA44E8 /* CSAppleII.mm */,
4B2A539A1D117D36003C6002 /* CSAtari2600.mm */,
4B14978E1EE4B4D200CE2596 /* CSZX8081.mm */,
);
@ -2777,6 +2784,7 @@
4B55CE551C3B7D360093A61B /* Documents */ = {
isa = PBXGroup;
children = (
4B051C94266EF50200CA44E8 /* AppleIIOptionsPanel.swift */,
4B8FE21F1DA19D7C0090D3CE /* Atari2600OptionsPanel.swift */,
4B55CE5E1C3B7D960093A61B /* MachineDocument.swift */,
4B8FE2211DA19FB20090D3CE /* MachinePanel.swift */,
@ -5402,11 +5410,13 @@
4B4518861F75E91A00926311 /* MFMDiskController.cpp in Sources */,
4B0ACC2C23775819008902D0 /* IntelligentKeyboard.cpp in Sources */,
4B92E26A234AE35100CD6D1B /* MFP68901.cpp in Sources */,
4B051C97266EF5F600CA44E8 /* CSAppleII.mm in Sources */,
4B0ACC2A23775819008902D0 /* Video.cpp in Sources */,
4B54C0BF1F8D8F450050900F /* Keyboard.cpp in Sources */,
4B3FE75E1F3CF68B00448EE4 /* CPM.cpp in Sources */,
4B2BFDB21DAEF5FF001A68B8 /* Video.cpp in Sources */,
4BEDA3BF25B25563000C2DBD /* Decoder.cpp in Sources */,
4B051C95266EF50200CA44E8 /* AppleIIOptionsPanel.swift in Sources */,
4B4DC82B1D2C27A4003C5BF8 /* SerialBus.cpp in Sources */,
4BE8EB6625C750B50040BC40 /* DAT.cpp in Sources */,
4BBFFEE61F7B27F1005F3FEB /* TrackSerialiser.cpp in Sources */,

View File

@ -56,13 +56,17 @@
argument = "/Users/thomasharte/Downloads/test-dsk-for-rw-and-50-60-hz/TEST-RW-60Hz.DSK"
isEnabled = "NO">
</CommandLineArgument>
<CommandLineArgument
argument = "&quot;/Users/thomasharte/Desktop/Soft/Apple II/WOZs/Prince of Persia side A.woz&quot;"
isEnabled = "YES">
</CommandLineArgument>
<CommandLineArgument
argument = "--rompath=~/ROMs"
isEnabled = "NO">
</CommandLineArgument>
<CommandLineArgument
argument = "--has-disk-drive"
isEnabled = "YES">
isEnabled = "NO">
</CommandLineArgument>
<CommandLineArgument
argument = "&quot;/Users/thomasharte/Library/Mobile Documents/com~apple~CloudDocs/Desktop/Soft/Macintosh/MusicWorks 0.42.image&quot;"
@ -78,7 +82,7 @@
</CommandLineArgument>
<CommandLineArgument
argument = "--volume=0.001"
isEnabled = "NO">
isEnabled = "YES">
</CommandLineArgument>
<CommandLineArgument
argument = "--new=amstradcpc"
@ -114,7 +118,7 @@
</CommandLineArgument>
<CommandLineArgument
argument = "--rompath=/Users/thomasharte/Projects/CLK/ROMImages"
isEnabled = "NO">
isEnabled = "YES">
</CommandLineArgument>
<CommandLineArgument
argument = "--help"
@ -125,7 +129,11 @@
isEnabled = "NO">
</CommandLineArgument>
<CommandLineArgument
argument = "--new=vic20"
argument = "--new=appleii"
isEnabled = "NO">
</CommandLineArgument>
<CommandLineArgument
argument = "--use-square-pixels"
isEnabled = "YES">
</CommandLineArgument>
</CommandLineArguments>

View File

@ -1,8 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<document type="com.apple.InterfaceBuilder3.Cocoa.XIB" version="3.0" toolsVersion="14460.31" targetRuntime="MacOSX.Cocoa" propertyAccessControl="none" useAutolayout="YES" customObjectInstantitationMethod="direct">
<document type="com.apple.InterfaceBuilder3.Cocoa.XIB" version="3.0" toolsVersion="18122" targetRuntime="MacOSX.Cocoa" propertyAccessControl="none" useAutolayout="YES" customObjectInstantitationMethod="direct">
<dependencies>
<deployment identifier="macosx"/>
<plugIn identifier="com.apple.InterfaceBuilder.CocoaPlugin" version="14460.31"/>
<plugIn identifier="com.apple.InterfaceBuilder.CocoaPlugin" version="18122"/>
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
</dependencies>
<objects>
@ -13,17 +13,27 @@
</customObject>
<customObject id="-1" userLabel="First Responder" customClass="FirstResponder"/>
<customObject id="-3" userLabel="Application" customClass="NSObject"/>
<window title="Options" allowsToolTipsWhenApplicationIsInactive="NO" autorecalculatesKeyViewLoop="NO" hidesOnDeactivate="YES" releasedWhenClosed="NO" visibleAtLaunch="NO" frameAutosaveName="" animationBehavior="default" id="ZW7-Bw-4RP" customClass="MachinePanel" customModule="Clock_Signal" customModuleProvider="target">
<window title="Options" allowsToolTipsWhenApplicationIsInactive="NO" autorecalculatesKeyViewLoop="NO" hidesOnDeactivate="YES" releasedWhenClosed="NO" visibleAtLaunch="NO" frameAutosaveName="" animationBehavior="default" id="ZW7-Bw-4RP" customClass="AppleIIOptionsPanel" customModule="Clock_Signal" customModuleProvider="target">
<windowStyleMask key="styleMask" titled="YES" closable="YES" utility="YES" nonactivatingPanel="YES" HUD="YES"/>
<windowPositionMask key="initialPositionMask" leftStrut="YES" rightStrut="YES" topStrut="YES" bottomStrut="YES"/>
<rect key="contentRect" x="80" y="150" width="200" height="61"/>
<rect key="screenRect" x="0.0" y="0.0" width="1440" height="900"/>
<rect key="contentRect" x="80" y="150" width="200" height="159"/>
<rect key="screenRect" x="0.0" y="0.0" width="2560" height="1440"/>
<view key="contentView" id="tpZ-0B-QQu">
<rect key="frame" x="0.0" y="0.0" width="200" height="61"/>
<rect key="frame" x="0.0" y="0.0" width="200" height="84"/>
<autoresizingMask key="autoresizingMask"/>
<subviews>
<button verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="kDb-7g-cVx">
<rect key="frame" x="18" y="47" width="162" height="18"/>
<buttonCell key="cell" type="check" title="Use Square Pixels" bezelStyle="regularSquare" imagePosition="left" state="on" inset="2" id="h9q-Wb-em8">
<behavior key="behavior" changeContents="YES" doesNotDimImage="YES" lightByContents="YES"/>
<font key="font" metaFont="system"/>
</buttonCell>
<connections>
<action selector="optionDidChange:" target="ZW7-Bw-4RP" id="pNS-aK-0no"/>
</connections>
</button>
<popUpButton verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="ex3-VM-58z">
<rect key="frame" x="18" y="17" width="165" height="25"/>
<rect key="frame" x="17" y="16" width="167" height="25"/>
<popUpButtonCell key="cell" type="push" title="Colour" bezelStyle="rounded" alignment="left" lineBreakMode="truncatingTail" state="on" borderStyle="borderAndBezel" tag="1" imageScaling="proportionallyDown" inset="2" selectedItem="gOu-dv-tre" id="u3N-Je-c2L">
<behavior key="behavior" lightByBackground="YES" lightByGray="YES"/>
<font key="font" metaFont="menu"/>
@ -40,16 +50,20 @@
</popUpButton>
</subviews>
<constraints>
<constraint firstAttribute="bottom" secondItem="ex3-VM-58z" secondAttribute="bottom" constant="20" id="4ZS-q5-TJL"/>
<constraint firstAttribute="bottom" secondItem="ex3-VM-58z" secondAttribute="bottom" constant="20" symbolic="YES" id="4ZS-q5-TJL"/>
<constraint firstItem="ex3-VM-58z" firstAttribute="leading" secondItem="tpZ-0B-QQu" secondAttribute="leading" constant="20" id="8Pj-Ns-TrJ"/>
<constraint firstAttribute="trailing" secondItem="kDb-7g-cVx" secondAttribute="trailing" constant="20" symbolic="YES" id="KHa-of-eY7"/>
<constraint firstItem="kDb-7g-cVx" firstAttribute="leading" secondItem="tpZ-0B-QQu" secondAttribute="leading" constant="20" symbolic="YES" id="OcZ-Xa-394"/>
<constraint firstAttribute="trailing" secondItem="ex3-VM-58z" secondAttribute="trailing" constant="20" id="QWA-lY-ugz"/>
<constraint firstItem="ex3-VM-58z" firstAttribute="top" secondItem="tpZ-0B-QQu" secondAttribute="top" constant="20" id="szw-WO-3tS"/>
<constraint firstItem="ex3-VM-58z" firstAttribute="top" secondItem="kDb-7g-cVx" secondAttribute="bottom" constant="8" id="jDW-N8-c4V"/>
<constraint firstItem="kDb-7g-cVx" firstAttribute="top" secondItem="tpZ-0B-QQu" secondAttribute="top" constant="20" symbolic="YES" id="wdj-PF-zxO"/>
</constraints>
</view>
<connections>
<outlet property="displayTypeButton" destination="ex3-VM-58z" id="lmZ-aN-lcj"/>
<outlet property="squarePixelButton" destination="kDb-7g-cVx" id="zbx-o8-7yC"/>
</connections>
<point key="canvasLocation" x="-161" y="38.5"/>
<point key="canvasLocation" x="-161" y="104.5"/>
</window>
</objects>
</document>

View File

@ -1,8 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<document type="com.apple.InterfaceBuilder3.Cocoa.XIB" version="3.0" toolsVersion="14113" targetRuntime="MacOSX.Cocoa" propertyAccessControl="none" useAutolayout="YES" customObjectInstantitationMethod="direct">
<document type="com.apple.InterfaceBuilder3.Cocoa.XIB" version="3.0" toolsVersion="18122" targetRuntime="MacOSX.Cocoa" propertyAccessControl="none" useAutolayout="YES" customObjectInstantitationMethod="direct">
<dependencies>
<deployment identifier="macosx"/>
<plugIn identifier="com.apple.InterfaceBuilder.CocoaPlugin" version="14113"/>
<plugIn identifier="com.apple.InterfaceBuilder.CocoaPlugin" version="18122"/>
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
</dependencies>
<objects>
@ -13,17 +13,17 @@
</customObject>
<customObject id="-1" userLabel="First Responder" customClass="FirstResponder"/>
<customObject id="-3" userLabel="Application" customClass="NSObject"/>
<window title="Options" allowsToolTipsWhenApplicationIsInactive="NO" autorecalculatesKeyViewLoop="NO" hidesOnDeactivate="YES" oneShot="NO" releasedWhenClosed="NO" showsToolbarButton="NO" visibleAtLaunch="NO" frameAutosaveName="" animationBehavior="default" id="gsl-7V-TTU" customClass="Atari2600OptionsPanel" customModule="Clock_Signal" customModuleProvider="target">
<window title="Options" allowsToolTipsWhenApplicationIsInactive="NO" autorecalculatesKeyViewLoop="NO" hidesOnDeactivate="YES" releasedWhenClosed="NO" visibleAtLaunch="NO" frameAutosaveName="" animationBehavior="default" id="gsl-7V-TTU" customClass="Atari2600OptionsPanel" customModule="Clock_Signal" customModuleProvider="target">
<windowStyleMask key="styleMask" titled="YES" closable="YES" utility="YES" nonactivatingPanel="YES" HUD="YES"/>
<windowPositionMask key="initialPositionMask" leftStrut="YES" rightStrut="YES" topStrut="YES" bottomStrut="YES"/>
<rect key="contentRect" x="80" y="150" width="200" height="121"/>
<rect key="screenRect" x="0.0" y="0.0" width="1440" height="900"/>
<rect key="screenRect" x="0.0" y="0.0" width="2560" height="1440"/>
<view key="contentView" id="aQh-Pm-DEo">
<rect key="frame" x="0.0" y="0.0" width="200" height="121"/>
<autoresizingMask key="autoresizingMask"/>
<subviews>
<button verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="rQO-uD-fwn">
<rect key="frame" x="14" y="73" width="86" height="32"/>
<rect key="frame" x="13" y="74" width="88" height="32"/>
<buttonCell key="cell" type="push" title="Reset" bezelStyle="rounded" alignment="center" borderStyle="border" imageScaling="proportionallyDown" inset="2" id="l3H-0m-aK0">
<behavior key="behavior" pushIn="YES" lightByBackground="YES" lightByGray="YES"/>
<font key="font" metaFont="system"/>
@ -33,7 +33,7 @@
</connections>
</button>
<button translatesAutoresizingMaskIntoConstraints="NO" id="3qw-C1-NYW">
<rect key="frame" x="18" y="58" width="164" height="18"/>
<rect key="frame" x="18" y="58" width="162" height="18"/>
<buttonCell key="cell" type="check" title="Black and White" bezelStyle="regularSquare" imagePosition="left" inset="2" id="UP7-mf-IKo">
<behavior key="behavior" changeContents="YES" doesNotDimImage="YES" lightByContents="YES"/>
<font key="font" metaFont="system"/>
@ -43,7 +43,7 @@
</connections>
</button>
<button translatesAutoresizingMaskIntoConstraints="NO" id="Xbc-cw-Sc2">
<rect key="frame" x="18" y="38" width="164" height="18"/>
<rect key="frame" x="18" y="36" width="162" height="18"/>
<buttonCell key="cell" type="check" title="Left Player Difficulty" bezelStyle="regularSquare" imagePosition="left" inset="2" id="wlJ-8s-PEh">
<behavior key="behavior" changeContents="YES" doesNotDimImage="YES" lightByContents="YES"/>
<font key="font" metaFont="system"/>
@ -53,7 +53,7 @@
</connections>
</button>
<button translatesAutoresizingMaskIntoConstraints="NO" id="kPV-Tm-TTc">
<rect key="frame" x="18" y="18" width="164" height="18"/>
<rect key="frame" x="18" y="14" width="162" height="18"/>
<buttonCell key="cell" type="check" title="Right Player Difficulty" bezelStyle="regularSquare" imagePosition="left" inset="2" id="F05-cA-66S">
<behavior key="behavior" changeContents="YES" doesNotDimImage="YES" lightByContents="YES"/>
<font key="font" metaFont="system"/>
@ -63,7 +63,7 @@
</connections>
</button>
<button verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="nt7-8K-xY9">
<rect key="frame" x="100" y="73" width="86" height="32"/>
<rect key="frame" x="99" y="74" width="88" height="32"/>
<buttonCell key="cell" type="push" title="Select" bezelStyle="rounded" alignment="center" borderStyle="border" imageScaling="proportionallyDown" inset="2" id="8Na-Z1-EXS">
<behavior key="behavior" pushIn="YES" lightByBackground="YES" lightByGray="YES"/>
<font key="font" metaFont="system"/>

View File

@ -36,6 +36,7 @@ typedef NS_ENUM(NSInteger, CSMachineKeyboardInputMode) {
// Deliberately low; to ensure CSMachine has been declared as an @class already.
#import "CSAtari2600.h"
#import "CSZX8081.h"
#import "CSAppleII.h"
@interface CSMachine : NSObject
@ -103,5 +104,6 @@ typedef NS_ENUM(NSInteger, CSMachineKeyboardInputMode) {
// Special-case accessors; undefined behaviour if accessed for a machine not of the corresponding type.
@property (nonatomic, readonly, nullable) CSAtari2600 *atari2600;
@property (nonatomic, readonly, nullable) CSZX8081 *zx8081;
@property (nonatomic, readonly, nullable) CSAppleII *appleII;
@end

View File

@ -577,6 +577,10 @@ struct ActivityObserver: public Activity::Observer {
return [[CSZX8081 alloc] initWithZX8081:_machine->raw_pointer() owner:self];
}
- (CSAppleII *)appleII {
return [[CSAppleII alloc] initWithAppleII:_machine->raw_pointer() owner:self];
}
#pragma mark - Input device queries
- (BOOL)hasJoystick {

View File

@ -0,0 +1,18 @@
//
// CSAppleII.h
// Clock Signal
//
// Created by Thomas Harte on 07/06/2021.
// Copyright © 2021 Thomas Harte. All rights reserved.
//
@class CSAppleII;
#import "CSMachine.h"
@interface CSAppleII : NSObject
- (instancetype)initWithAppleII:(void *)appleII owner:(CSMachine *)machine;
@property (nonatomic, assign) BOOL useSquarePixels;
@end

View File

@ -0,0 +1,57 @@
//
// CSAppleII.m
// Clock Signal
//
// Created by Thomas Harte on 07/06/2021.
// Copyright © 2021 Thomas Harte. All rights reserved.
//
#import "CSAppleII.h"
#include "AppleII.hpp"
@implementation CSAppleII {
Apple::II::Machine *_appleII;
__weak CSMachine *_machine;
}
- (instancetype)initWithAppleII:(void *)appleII owner:(CSMachine *)machine {
self = [super init];
if(self) {
_appleII = (Apple::II::Machine *)appleII;
_machine = machine;
}
return self;
}
#pragma mark - Options
- (void)setUseSquarePixels:(BOOL)useSquarePixels {
Configurable::Device *const configurable = dynamic_cast<Configurable::Device *>(_appleII);
#ifndef NDEBUG
assert(configurable);
#endif
@synchronized(_machine) {
auto options = configurable->get_options();
#ifndef NDEBUG
assert(dynamic_cast<Apple::II::Machine::Options *>(options.get()));
#endif
auto appleii_configurable = static_cast<Apple::II::Machine::Options *>(options.get());
appleii_configurable->use_square_pixels = useSquarePixels;
configurable->set_options(options);
}
}
- (BOOL)useSquarePixels {
Configurable::Device *const configurable = dynamic_cast<Configurable::Device *>(_appleII);
@synchronized(_machine) {
auto options = configurable->get_options();
auto appleii_configurable = dynamic_cast<Apple::II::Machine::Options *>(options.get());
return appleii_configurable->use_square_pixels ? YES : NO;
}
}
@end

View File

@ -403,7 +403,7 @@ void MainWindow::launchMachine() {
break;
case Analyser::Machine::AppleII:
addDisplayMenu(settingsPrefix, "Colour", "Monochrome", "", "");
addAppleIIMenu();
break;
case Analyser::Machine::Atari2600:
@ -671,6 +671,41 @@ void MainWindow::toggleAtari2600Switch(Atari2600Switch toggleSwitch) {
});
}
void MainWindow::addAppleIIMenu() {
// Add the standard display settings.
addDisplayMenu("appleII", "Colour", "Monochrome", "", "");
// Add an additional tick box, for square pixels.
QAction *const squarePixelsAction = new QAction(tr("Square Pixels"));
squarePixelsAction->setCheckable(true);
connect(squarePixelsAction, &QAction::triggered, this, [=] {
std::lock_guard lock_guard(machineMutex);
// Apply the new setting to the machine.
setAppleIISquarePixels(squarePixelsAction->isChecked());
// Also store it.
Settings settings;
settings.setValue("appleII.squarePixels", squarePixelsAction->isChecked());
});
displayMenu->addAction(squarePixelsAction);
// Establish initial selection.
Settings settings;
const bool useSquarePixels = settings.value("appleII.squarePixels").toBool();
squarePixelsAction->setChecked(useSquarePixels);
setAppleIISquarePixels(useSquarePixels);
}
void MainWindow::setAppleIISquarePixels(bool squarePixels) {
Configurable::Device *const configurable = machine->configurable_device();
auto options = configurable->get_options();
auto appleii_options = static_cast<Apple::II::Machine::Options *>(options.get());
appleii_options->use_square_pixels = squarePixels;
configurable->set_options(options);
}
void MainWindow::speaker_did_complete_samples(Outputs::Speaker::Speaker *, const std::vector<int16_t> &buffer) {
audioBuffer.write(buffer);
}

View File

@ -20,8 +20,9 @@
#include "../../Activity/Observer.hpp"
// There are machine-specific controls for the following:
#include "../../Machines/Sinclair/ZX8081/ZX8081.hpp"
#include "../../Machines/Apple/AppleII/AppleII.hpp"
#include "../../Machines/Atari/2600/Atari2600.hpp"
#include "../../Machines/Sinclair/ZX8081/ZX8081.hpp"
QT_BEGIN_NAMESPACE
namespace Ui { class MainWindow; }
@ -137,6 +138,9 @@ class MainWindow : public QMainWindow, public Outputs::Speaker::Speaker::Delegat
void addAtari2600Menu();
void toggleAtari2600Switch(Atari2600Switch toggleSwitch);
void addAppleIIMenu();
void setAppleIISquarePixels(bool);
void setWindowTitle();
bool mouseIsCaptured = false;