├── UxniOS
├── UxniOS-Bridging-Header.h
├── roms
│ ├── hello.rom
│ ├── life.rom
│ ├── piano.rom
│ ├── polycat.rom
│ ├── screen.rom
│ └── bifurcan.rom
├── Assets.xcassets
│ ├── Contents.json
│ ├── AccentColor.colorset
│ │ └── Contents.json
│ └── AppIcon.appiconset
│ │ └── Contents.json
├── AppDelegate.swift
├── UxnBridge.h
├── Info.plist
├── Base.lproj
│ ├── LaunchScreen.storyboard
│ └── Main.storyboard
├── ViewController.swift
└── UxnBridge.m
├── .gitmodules
├── UxniOS.xcodeproj
├── project.xcworkspace
│ ├── contents.xcworkspacedata
│ └── xcshareddata
│ │ └── IDEWorkspaceChecks.plist
└── project.pbxproj
├── UxniOSTests
├── Info.plist
└── UxniOSTests.swift
├── UxniOSUITests
├── Info.plist
└── UxniOSUITests.swift
├── LICENSE
├── README.md
└── .gitignore
/UxniOS/UxniOS-Bridging-Header.h:
--------------------------------------------------------------------------------
1 | #import "UxnBridge.h"
2 |
--------------------------------------------------------------------------------
/.gitmodules:
--------------------------------------------------------------------------------
1 | [submodule "uxn"]
2 | path = uxn
3 | url = https://git.sr.ht/~rabbits/uxn
4 |
--------------------------------------------------------------------------------
/UxniOS/roms/hello.rom:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kylestew/UxniOS/HEAD/UxniOS/roms/hello.rom
--------------------------------------------------------------------------------
/UxniOS/roms/life.rom:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kylestew/UxniOS/HEAD/UxniOS/roms/life.rom
--------------------------------------------------------------------------------
/UxniOS/roms/piano.rom:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kylestew/UxniOS/HEAD/UxniOS/roms/piano.rom
--------------------------------------------------------------------------------
/UxniOS/roms/polycat.rom:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kylestew/UxniOS/HEAD/UxniOS/roms/polycat.rom
--------------------------------------------------------------------------------
/UxniOS/roms/screen.rom:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kylestew/UxniOS/HEAD/UxniOS/roms/screen.rom
--------------------------------------------------------------------------------
/UxniOS/roms/bifurcan.rom:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kylestew/UxniOS/HEAD/UxniOS/roms/bifurcan.rom
--------------------------------------------------------------------------------
/UxniOS/Assets.xcassets/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "info" : {
3 | "author" : "xcode",
4 | "version" : 1
5 | }
6 | }
7 |
--------------------------------------------------------------------------------
/UxniOS.xcodeproj/project.xcworkspace/contents.xcworkspacedata:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/UxniOS/Assets.xcassets/AccentColor.colorset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "colors" : [
3 | {
4 | "idiom" : "universal"
5 | }
6 | ],
7 | "info" : {
8 | "author" : "xcode",
9 | "version" : 1
10 | }
11 | }
12 |
--------------------------------------------------------------------------------
/UxniOS.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | IDEDidComputeMac32BitWarning
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/UxniOS/AppDelegate.swift:
--------------------------------------------------------------------------------
1 | import UIKit
2 |
3 | @main
4 | class AppDelegate: UIResponder, UIApplicationDelegate {
5 |
6 | var window: UIWindow?
7 |
8 | func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
9 | // Override point for customization after application launch.
10 | return true
11 | }
12 |
13 | }
14 |
15 |
--------------------------------------------------------------------------------
/UxniOS/UxnBridge.h:
--------------------------------------------------------------------------------
1 | #import
2 |
3 | NS_ASSUME_NONNULL_BEGIN
4 |
5 | @interface UxnBridge : NSObject
6 |
7 | @property (nonatomic, assign) CGImageRef bgImageRef;
8 | @property (nonatomic, assign) CGImageRef fgImageRef;
9 |
10 | - (BOOL)load:(NSString *)romFile;
11 |
12 | - (CGSize)screenSize;
13 | - (void)redraw;
14 |
15 | - (void)domouse:(CGPoint)position taps:(int)taps state:(int)state;
16 |
17 | @end
18 |
19 | NS_ASSUME_NONNULL_END
20 |
--------------------------------------------------------------------------------
/UxniOSTests/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | $(DEVELOPMENT_LANGUAGE)
7 | CFBundleExecutable
8 | $(EXECUTABLE_NAME)
9 | CFBundleIdentifier
10 | $(PRODUCT_BUNDLE_IDENTIFIER)
11 | CFBundleInfoDictionaryVersion
12 | 6.0
13 | CFBundleName
14 | $(PRODUCT_NAME)
15 | CFBundlePackageType
16 | $(PRODUCT_BUNDLE_PACKAGE_TYPE)
17 | CFBundleShortVersionString
18 | 1.0
19 | CFBundleVersion
20 | 1
21 |
22 |
23 |
--------------------------------------------------------------------------------
/UxniOSUITests/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | $(DEVELOPMENT_LANGUAGE)
7 | CFBundleExecutable
8 | $(EXECUTABLE_NAME)
9 | CFBundleIdentifier
10 | $(PRODUCT_BUNDLE_IDENTIFIER)
11 | CFBundleInfoDictionaryVersion
12 | 6.0
13 | CFBundleName
14 | $(PRODUCT_NAME)
15 | CFBundlePackageType
16 | $(PRODUCT_BUNDLE_PACKAGE_TYPE)
17 | CFBundleShortVersionString
18 | 1.0
19 | CFBundleVersion
20 | 1
21 |
22 |
23 |
--------------------------------------------------------------------------------
/UxniOSTests/UxniOSTests.swift:
--------------------------------------------------------------------------------
1 | //
2 | // UxniOSTests.swift
3 | // UxniOSTests
4 | //
5 | // Created by Kyle Stewart on 7/13/21.
6 | //
7 |
8 | import XCTest
9 | @testable import UxniOS
10 |
11 | class UxniOSTests: XCTestCase {
12 |
13 | override func setUpWithError() throws {
14 | // Put setup code here. This method is called before the invocation of each test method in the class.
15 | }
16 |
17 | override func tearDownWithError() throws {
18 | // Put teardown code here. This method is called after the invocation of each test method in the class.
19 | }
20 |
21 | func testExample() throws {
22 | // This is an example of a functional test case.
23 | // Use XCTAssert and related functions to verify your tests produce the correct results.
24 | }
25 |
26 | func testPerformanceExample() throws {
27 | // This is an example of a performance test case.
28 | self.measure {
29 | // Put the code you want to measure the time of here.
30 | }
31 | }
32 |
33 | }
34 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) Devine Lu Linvega
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
--------------------------------------------------------------------------------
/UxniOSUITests/UxniOSUITests.swift:
--------------------------------------------------------------------------------
1 | //
2 | // UxniOSUITests.swift
3 | // UxniOSUITests
4 | //
5 | // Created by Kyle Stewart on 7/13/21.
6 | //
7 |
8 | import XCTest
9 |
10 | class UxniOSUITests: XCTestCase {
11 |
12 | override func setUpWithError() throws {
13 | // Put setup code here. This method is called before the invocation of each test method in the class.
14 |
15 | // In UI tests it is usually best to stop immediately when a failure occurs.
16 | continueAfterFailure = false
17 |
18 | // In UI tests it’s important to set the initial state - such as interface orientation - required for your tests before they run. The setUp method is a good place to do this.
19 | }
20 |
21 | override func tearDownWithError() throws {
22 | // Put teardown code here. This method is called after the invocation of each test method in the class.
23 | }
24 |
25 | func testExample() throws {
26 | // UI tests must launch the application that they test.
27 | let app = XCUIApplication()
28 | app.launch()
29 |
30 | // Use recording to get started writing UI tests.
31 | // Use XCTAssert and related functions to verify your tests produce the correct results.
32 | }
33 |
34 | func testLaunchPerformance() throws {
35 | if #available(macOS 10.15, iOS 13.0, tvOS 13.0, watchOS 7.0, *) {
36 | // This measures how long it takes to launch your application.
37 | measure(metrics: [XCTApplicationLaunchMetric()]) {
38 | XCUIApplication().launch()
39 | }
40 | }
41 | }
42 | }
43 |
--------------------------------------------------------------------------------
/UxniOS/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | $(DEVELOPMENT_LANGUAGE)
7 | CFBundleExecutable
8 | $(EXECUTABLE_NAME)
9 | CFBundleIdentifier
10 | $(PRODUCT_BUNDLE_IDENTIFIER)
11 | CFBundleInfoDictionaryVersion
12 | 6.0
13 | CFBundleName
14 | $(PRODUCT_NAME)
15 | CFBundlePackageType
16 | $(PRODUCT_BUNDLE_PACKAGE_TYPE)
17 | CFBundleShortVersionString
18 | 1.0
19 | CFBundleVersion
20 | 1
21 | LSRequiresIPhoneOS
22 |
23 | UIApplicationSupportsIndirectInputEvents
24 |
25 | UILaunchStoryboardName
26 | LaunchScreen
27 | UIMainStoryboardFile
28 | Main
29 | UIRequiredDeviceCapabilities
30 |
31 | armv7
32 |
33 | UISupportedInterfaceOrientations
34 |
35 | UIInterfaceOrientationLandscapeLeft
36 | UIInterfaceOrientationLandscapeRight
37 |
38 | UISupportedInterfaceOrientations~ipad
39 |
40 | UIInterfaceOrientationPortrait
41 | UIInterfaceOrientationPortraitUpsideDown
42 | UIInterfaceOrientationLandscapeLeft
43 | UIInterfaceOrientationLandscapeRight
44 |
45 |
46 |
47 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # UxniOS
2 |
3 | ___A Uxn emulator for iOS___
4 |
5 | Learn more about Uxn [here](https://wiki.xxiivv.com/site/uxn.html).
6 |
7 | ## Supported Devices
8 |
9 | | | Device | Support |
10 | | ----- | ------------- | ------------------------------------- |
11 | | 0x00 | System | **complete** |
12 | | 0x10 | Console | incomplete: no console in |
13 | | 0x20 | Screen | **complete** |
14 | | 0x30 | Audio | incomplete |
15 | | 0x40 | Audio | incomplete |
16 | | 0x50 | Audio | incomplete |
17 | | 0x60 | Audio | incomplete |
18 | | 0x90 | --- | |
19 | | 0x80 | Controller | incomplete: is this the keyboard? 🤔 |
20 | | 0x90 | Mouse | _limited: touch screen approximation_ |
21 | | 0xA0 | file | incomplete |
22 | | 0xB0 | datetime | **complete** |
23 | | 0xC0 | --- | |
24 | | 0xD0 | --- | |
25 | | 0xE0 | --- | |
26 | | 0xF0 | --- | |
27 |
28 | ## In Progress
29 |
30 | - [ ] Sound output
31 | - [ ] Keyboard input
32 | - [ ] Device rotation, better display scaling
33 | - [ ] ROM loading, pausing/restoring state
34 | - [ ] Full mouse support - GUI elements for mouse input
35 |
36 | ## License Info
37 |
38 | ___MIT License___
39 |
40 | Major portions of the emulator and the base Uxn code are (c) Devine Lu Linvega. The MIT license applies to the extended code I've added in this repo.
41 |
--------------------------------------------------------------------------------
/UxniOS/Assets.xcassets/AppIcon.appiconset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "iphone",
5 | "scale" : "2x",
6 | "size" : "20x20"
7 | },
8 | {
9 | "idiom" : "iphone",
10 | "scale" : "3x",
11 | "size" : "20x20"
12 | },
13 | {
14 | "idiom" : "iphone",
15 | "scale" : "2x",
16 | "size" : "29x29"
17 | },
18 | {
19 | "idiom" : "iphone",
20 | "scale" : "3x",
21 | "size" : "29x29"
22 | },
23 | {
24 | "idiom" : "iphone",
25 | "scale" : "2x",
26 | "size" : "40x40"
27 | },
28 | {
29 | "idiom" : "iphone",
30 | "scale" : "3x",
31 | "size" : "40x40"
32 | },
33 | {
34 | "idiom" : "iphone",
35 | "scale" : "2x",
36 | "size" : "60x60"
37 | },
38 | {
39 | "idiom" : "iphone",
40 | "scale" : "3x",
41 | "size" : "60x60"
42 | },
43 | {
44 | "idiom" : "ipad",
45 | "scale" : "1x",
46 | "size" : "20x20"
47 | },
48 | {
49 | "idiom" : "ipad",
50 | "scale" : "2x",
51 | "size" : "20x20"
52 | },
53 | {
54 | "idiom" : "ipad",
55 | "scale" : "1x",
56 | "size" : "29x29"
57 | },
58 | {
59 | "idiom" : "ipad",
60 | "scale" : "2x",
61 | "size" : "29x29"
62 | },
63 | {
64 | "idiom" : "ipad",
65 | "scale" : "1x",
66 | "size" : "40x40"
67 | },
68 | {
69 | "idiom" : "ipad",
70 | "scale" : "2x",
71 | "size" : "40x40"
72 | },
73 | {
74 | "idiom" : "ipad",
75 | "scale" : "1x",
76 | "size" : "76x76"
77 | },
78 | {
79 | "idiom" : "ipad",
80 | "scale" : "2x",
81 | "size" : "76x76"
82 | },
83 | {
84 | "idiom" : "ipad",
85 | "scale" : "2x",
86 | "size" : "83.5x83.5"
87 | },
88 | {
89 | "idiom" : "ios-marketing",
90 | "scale" : "1x",
91 | "size" : "1024x1024"
92 | }
93 | ],
94 | "info" : {
95 | "author" : "xcode",
96 | "version" : 1
97 | }
98 | }
99 |
--------------------------------------------------------------------------------
/UxniOS/Base.lproj/LaunchScreen.storyboard:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | .DS_Store
2 |
3 | # Xcode
4 | #
5 | # gitignore contributors: remember to update Global/Xcode.gitignore, Objective-C.gitignore & Swift.gitignore
6 |
7 | ## User settings
8 | xcuserdata/
9 |
10 | ## compatibility with Xcode 8 and earlier (ignoring not required starting Xcode 9)
11 | *.xcscmblueprint
12 | *.xccheckout
13 |
14 | ## compatibility with Xcode 3 and earlier (ignoring not required starting Xcode 4)
15 | build/
16 | DerivedData/
17 | *.moved-aside
18 | *.pbxuser
19 | !default.pbxuser
20 | *.mode1v3
21 | !default.mode1v3
22 | *.mode2v3
23 | !default.mode2v3
24 | *.perspectivev3
25 | !default.perspectivev3
26 |
27 | ## Obj-C/Swift specific
28 | *.hmap
29 |
30 | ## App packaging
31 | *.ipa
32 | *.dSYM.zip
33 | *.dSYM
34 |
35 | ## Playgrounds
36 | timeline.xctimeline
37 | playground.xcworkspace
38 |
39 | # Swift Package Manager
40 | #
41 | # Add this line if you want to avoid checking in source code from Swift Package Manager dependencies.
42 | # Packages/
43 | # Package.pins
44 | # Package.resolved
45 | # *.xcodeproj
46 | #
47 | # Xcode automatically generates this directory with a .xcworkspacedata file and xcuserdata
48 | # hence it is not needed unless you have added a package configuration file to your project
49 | # .swiftpm
50 |
51 | .build/
52 |
53 | # CocoaPods
54 | #
55 | # We recommend against adding the Pods directory to your .gitignore. However
56 | # you should judge for yourself, the pros and cons are mentioned at:
57 | # https://guides.cocoapods.org/using/using-cocoapods.html#should-i-check-the-pods-directory-into-source-control
58 | #
59 | # Pods/
60 | #
61 | # Add this line if you want to avoid checking in source code from the Xcode workspace
62 | # *.xcworkspace
63 |
64 | # Carthage
65 | #
66 | # Add this line if you want to avoid checking in source code from Carthage dependencies.
67 | # Carthage/Checkouts
68 |
69 | Carthage/Build/
70 |
71 | # Accio dependency management
72 | Dependencies/
73 | .accio/
74 |
75 | # fastlane
76 | #
77 | # It is recommended to not store the screenshots in the git repo.
78 | # Instead, use fastlane to re-generate the screenshots whenever they are needed.
79 | # For more information about the recommended setup visit:
80 | # https://docs.fastlane.tools/best-practices/source-control/#source-control
81 |
82 | fastlane/report.xml
83 | fastlane/Preview.html
84 | fastlane/screenshots/**/*.png
85 | fastlane/test_output
86 |
87 | # Code Injection
88 | #
89 | # After new code Injection tools there's a generated folder /iOSInjectionProject
90 | # https://github.com/johnno1962/injectionforxcode
91 |
92 | iOSInjectionProject/
93 |
--------------------------------------------------------------------------------
/UxniOS/ViewController.swift:
--------------------------------------------------------------------------------
1 | import UIKit
2 |
3 | class ViewController: UIViewController {
4 |
5 | @IBOutlet weak var bgRenderView: UIView!
6 | @IBOutlet weak var fgRenderView: UIView!
7 |
8 | var uxn: UxnBridge = UxnBridge()
9 |
10 | override func viewDidLoad() {
11 | super.viewDidLoad()
12 |
13 | let tapGesture = UILongPressGestureRecognizer(target: self, action: #selector(self.handleTap(_:)))
14 | tapGesture.minimumPressDuration = 0
15 | fgRenderView.addGestureRecognizer(tapGesture)
16 | }
17 |
18 | override func viewDidAppear(_ animated: Bool) {
19 | super.viewDidAppear(animated)
20 |
21 | // wait to load app UI before executing ROM
22 | let rom = Bundle.main.path(forResource: "polycat", ofType: "rom")!
23 |
24 | uxn.load(rom)
25 |
26 | startRenderLoop()
27 |
28 | // currently the screen size is hardwired in position and landscape orientation
29 | // let size = uxn.screenSize()
30 | // print(bgRenderView.frame, bgRenderView.layer.frame, size)
31 | // bgRenderView.layer.bounds = CGRect(origin: .zero, size: size)
32 | // fgRenderView.layer.bounds = CGRect(origin: .zero, size: size)
33 | }
34 |
35 | deinit {
36 | stopRenderLoop()
37 | }
38 |
39 | // MARK: - Render Loop
40 |
41 | var displayLink: CADisplayLink?
42 |
43 | func startRenderLoop() {
44 | let displaylink = CADisplayLink(target: self, selector: #selector(renderLoopDidFire))
45 | displaylink.add(to: .current, forMode: RunLoop.Mode.default)
46 | self.displayLink = displaylink
47 | }
48 |
49 | func stopRenderLoop() {
50 | displayLink?.invalidate()
51 | displayLink = nil
52 | }
53 |
54 | @objc func renderLoopDidFire(_ displayLink: CADisplayLink) {
55 | uxn.redraw()
56 |
57 | bgRenderView.layer.contents = uxn.bgImageRef
58 | fgRenderView.layer.contents = uxn.fgImageRef
59 | }
60 |
61 | // MARK: - Input
62 |
63 | @objc func handleTap(_ sender: UITapGestureRecognizer) {
64 | guard sender.view != nil else { return }
65 |
66 | let point = sender.location(in: sender.view)
67 | let taps = Int32(sender.numberOfTouches)
68 |
69 | switch sender.state {
70 | case .began:
71 | uxn.domouse(point, taps: taps, state: 0)
72 | case .ended:
73 | uxn.domouse(point, taps: taps, state: 1)
74 | case .changed:
75 | uxn.domouse(point, taps: taps, state: -1)
76 | break
77 | default: break
78 | }
79 | }
80 |
81 | }
82 |
--------------------------------------------------------------------------------
/UxniOS/Base.lproj/Main.storyboard:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
--------------------------------------------------------------------------------
/UxniOS/UxnBridge.m:
--------------------------------------------------------------------------------
1 | #import
2 | #import "UxnBridge.h"
3 | #import "uxn.h"
4 | #import "ppu.h"
5 |
6 | @implementation UxnBridge {
7 | }
8 |
9 | static Uxn uxn;
10 | static Ppu ppu;
11 | static Device *devscreen, *devmouse;
12 |
13 | static Uint8 zoom = 0, debug = 0, reqdraw = 0;
14 |
15 | - (instancetype)init {
16 | if (self == [super init]) {
17 | if(!initppu(&ppu, 64, 40))
18 | assert(false);
19 | // return error("PPU", "Init failure");
20 | }
21 | return self;
22 | }
23 |
24 | - (void)dealloc {
25 | }
26 |
27 | #pragma mark - Helpers
28 |
29 | static int clamp(int val, int min, int max) {
30 | return (val >= min) ? (val <= max) ? val : max : min;
31 | }
32 |
33 | #pragma mark - Graphics
34 |
35 | - (CGSize)screenSize {
36 | CGFloat width = ppu.hor * 8;
37 | CGFloat height = ppu.ver * 8;
38 | return CGSizeMake(width, height);
39 | }
40 |
41 | - (void)redraw {
42 | // determine if screen needs refresh
43 | evaluxn(&uxn, mempeek16(devscreen->dat, 0));
44 |
45 | if (!reqdraw) return;
46 | reqdraw = 0;
47 |
48 | int width = ppu.width;
49 | int height = ppu.height;
50 | int length = width * height * sizeof(UInt32);
51 |
52 | CFDataRef bridgedDataBG;
53 | CFDataRef bridgedDataFG;
54 | CGDataProviderRef dataProviderBG;
55 | CGDataProviderRef dataProviderFG;
56 | CGColorSpaceRef colorSpace;
57 | CGBitmapInfo infoFlags = (CGBitmapInfo)kCGImageAlphaFirst | kCGBitmapByteOrder32Little; // ARGB
58 |
59 | colorSpace = CGColorSpaceCreateWithName(kCGColorSpaceGenericRGB);
60 |
61 | NSData* bgImageData = [[NSData alloc] initWithBytes: ppu.bg.pixels length: length];
62 | NSData* fgImageData = [[NSData alloc] initWithBytes: ppu.fg.pixels length: length];
63 |
64 | bridgedDataBG = (__bridge CFDataRef)bgImageData;
65 | bridgedDataFG = (__bridge CFDataRef)fgImageData;
66 |
67 | dataProviderBG = CGDataProviderCreateWithCFData(bridgedDataBG);
68 | dataProviderFG = CGDataProviderCreateWithCFData(bridgedDataFG);
69 |
70 | _bgImageRef = CGImageCreate(
71 | width, height, /* bpc */ 8, /* bpp */ 32, /* pitch */ width * 4,
72 | colorSpace, infoFlags,
73 | dataProviderBG, /* decode array */ NULL, /* interpolate? */ TRUE,
74 | kCGRenderingIntentDefault /* adjust intent according to use */
75 | );
76 | _fgImageRef = CGImageCreate(
77 | width, height, /* bpc */ 8, /* bpp */ 32, /* pitch */ width * 4,
78 | colorSpace, infoFlags,
79 | dataProviderFG, /* decode array */ NULL, /* interpolate? */ TRUE,
80 | kCGRenderingIntentDefault /* adjust intent according to use */
81 | );
82 |
83 | // Release things the image took ownership of.
84 | CGDataProviderRelease(dataProviderBG);
85 | CGDataProviderRelease(dataProviderFG);
86 | CGColorSpaceRelease(colorSpace);
87 | }
88 |
89 | #pragma mark - Input
90 |
91 | /* == Mouse ==
92 | * 0x00 - vector
93 | * 0x20 - x
94 | * 0x40 - y
95 | * 0x60 - state [mouse button]
96 | * 0x70 - wheel (not implemented)
97 | */
98 | - (void)domouse:(CGPoint)position taps:(int)taps state:(int)state {
99 | Uint16 x = clamp(position.x, 0, ppu.hor * 8 - 1);
100 | Uint16 y = clamp(position.y, 0, ppu.ver * 8 - 1);
101 |
102 | mempoke16(devmouse->dat, 0x2, x);
103 | mempoke16(devmouse->dat, 0x4, y);
104 |
105 | Uint8 flag = 0x00;
106 | if (taps == 1) {
107 | // tap - left click
108 | flag = 0x01;
109 | } else if (taps == 2) {
110 | // two finger tap - right click
111 | flag = 0x10;
112 | }
113 | if (state == 0) {
114 | // touches began
115 | devmouse->dat[6] |= flag;
116 | } else if (state == 1) {
117 | // touches ended
118 | devmouse->dat[6] &= (~flag);
119 | }
120 |
121 | // fire vector
122 | evaluxn(&uxn, mempeek16(devmouse->dat, 0));
123 | }
124 |
125 | #pragma mark - Devices
126 |
127 | static void system_talk(Device *d, Uint8 b0, Uint8 w) {
128 | if(!w) {
129 | d->dat[0x2] = d->u->wst.ptr;
130 | d->dat[0x3] = d->u->rst.ptr;
131 | } else {
132 | putcolors(&ppu, &d->dat[0x8]);
133 | reqdraw = 1;
134 | }
135 | (void)b0;
136 | }
137 |
138 | static void console_talk(Device *d, Uint8 b0, Uint8 w) {
139 | if(w && b0 > 0x7)
140 | write(b0 - 0x7, (char *)&d->dat[b0], 1);
141 | }
142 |
143 | static void screen_talk(Device *d, Uint8 b0, Uint8 w) {
144 | if(w && b0 == 0xe) {
145 | Uint16 x = mempeek16(d->dat, 0x8);
146 | Uint16 y = mempeek16(d->dat, 0xa);
147 | Uint8 *addr = &d->mem[mempeek16(d->dat, 0xc)];
148 | Layer *layer = d->dat[0xe] >> 4 & 0x1 ? &ppu.fg : &ppu.bg;
149 | Uint8 mode = d->dat[0xe] >> 5;
150 | if(!mode)
151 | putpixel(&ppu, layer, x, y, d->dat[0xe] & 0x3);
152 | else if(mode-- & 0x1)
153 | puticn(&ppu, layer, x, y, addr, d->dat[0xe] & 0xf, mode & 0x2, mode & 0x4);
154 | else
155 | putchr(&ppu, layer, x, y, addr, d->dat[0xe] & 0xf, mode & 0x2, mode & 0x4);
156 | reqdraw = 1;
157 | }
158 | }
159 |
160 | static void datetime_talk(Device *d, Uint8 b0, Uint8 w) {
161 | time_t seconds = time(NULL);
162 | struct tm *t = localtime(&seconds);
163 | t->tm_year += 1900;
164 | mempoke16(d->dat, 0x0, t->tm_year);
165 | d->dat[0x2] = t->tm_mon;
166 | d->dat[0x3] = t->tm_mday;
167 | d->dat[0x4] = t->tm_hour;
168 | d->dat[0x5] = t->tm_min;
169 | d->dat[0x6] = t->tm_sec;
170 | d->dat[0x7] = t->tm_wday;
171 | mempoke16(d->dat, 0x08, t->tm_yday);
172 | d->dat[0xa] = t->tm_isdst;
173 | (void)b0;
174 | (void)w;
175 | }
176 |
177 | static void nil_talk(Device *d, Uint8 b0, Uint8 w) {
178 | (void)d;
179 | (void)b0;
180 | (void)w;
181 | }
182 |
183 | #pragma mark - Load & Setup
184 |
185 | - (BOOL)load:(NSString *)romFile {
186 | if (!bootuxn(&uxn))
187 | return NO;
188 | if (!loaduxn(&uxn, [romFile UTF8String]))
189 | return NO;
190 |
191 | portuxn(&uxn, 0x0, "system", system_talk);
192 | portuxn(&uxn, 0x1, "console", console_talk);
193 | devscreen = portuxn(&uxn, 0x2, "screen", screen_talk);
194 | // 0x3 - audio0
195 | // 0x4 - audio1
196 | // 0x5 - audio2
197 | // 0x6 - audio3
198 | // 0x7 ----
199 | // 0x8 - controller
200 | devmouse = portuxn(&uxn, 0x9, "mouse", nil_talk);
201 | // 0xa - file
202 | portuxn(&uxn, 0xb, "datetime", datetime_talk);
203 | // 0xc ----
204 | // 0xd ----
205 | // 0xe ----
206 | // 0xf ----
207 |
208 | /* Write screen size to dev/screen */
209 | mempoke16(devscreen->dat, 2, ppu.hor * 8);
210 | mempoke16(devscreen->dat, 4, ppu.ver * 8);
211 |
212 | evaluxn(&uxn, 0x0100);
213 |
214 | return YES;
215 | }
216 |
217 | @end
218 |
--------------------------------------------------------------------------------
/UxniOS.xcodeproj/project.pbxproj:
--------------------------------------------------------------------------------
1 | // !$*UTF8*$!
2 | {
3 | archiveVersion = 1;
4 | classes = {
5 | };
6 | objectVersion = 50;
7 | objects = {
8 |
9 | /* Begin PBXBuildFile section */
10 | FF35118E269E30DB00F852B2 /* UxnBridge.m in Sources */ = {isa = PBXBuildFile; fileRef = FF35118D269E30DB00F852B2 /* UxnBridge.m */; };
11 | FF351190269E339E00F852B2 /* hello.rom in Resources */ = {isa = PBXBuildFile; fileRef = FF35118F269E339E00F852B2 /* hello.rom */; };
12 | FF4C072F269E237A0040F453 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = FF4C072E269E237A0040F453 /* AppDelegate.swift */; };
13 | FF4C0733269E237A0040F453 /* ViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = FF4C0732269E237A0040F453 /* ViewController.swift */; };
14 | FF4C0736269E237A0040F453 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = FF4C0734269E237A0040F453 /* Main.storyboard */; };
15 | FF4C0738269E23800040F453 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = FF4C0737269E23800040F453 /* Assets.xcassets */; };
16 | FF4C073B269E23800040F453 /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = FF4C0739269E23800040F453 /* LaunchScreen.storyboard */; };
17 | FF4C0746269E23800040F453 /* UxniOSTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = FF4C0745269E23800040F453 /* UxniOSTests.swift */; };
18 | FF4C0751269E23800040F453 /* UxniOSUITests.swift in Sources */ = {isa = PBXBuildFile; fileRef = FF4C0750269E23800040F453 /* UxniOSUITests.swift */; };
19 | FF6831D1269E8B1C007A84F2 /* screen.rom in Resources */ = {isa = PBXBuildFile; fileRef = FF6831D0269E8B1C007A84F2 /* screen.rom */; };
20 | FF6831D3269E8DB2007A84F2 /* piano.rom in Resources */ = {isa = PBXBuildFile; fileRef = FF6831D2269E8DB2007A84F2 /* piano.rom */; };
21 | FFD2DDAC26A1C28E00AD30FC /* polycat.rom in Resources */ = {isa = PBXBuildFile; fileRef = FFD2DDAB26A1C28E00AD30FC /* polycat.rom */; };
22 | FFD2DDAE26A1C48300AD30FC /* life.rom in Resources */ = {isa = PBXBuildFile; fileRef = FFD2DDAD26A1C48300AD30FC /* life.rom */; };
23 | FFD2DDB026A1C6C400AD30FC /* bifurcan.rom in Resources */ = {isa = PBXBuildFile; fileRef = FFD2DDAF26A1C6C400AD30FC /* bifurcan.rom */; };
24 | FFF34708269EB827006F6EA4 /* uxn.c in Sources */ = {isa = PBXBuildFile; fileRef = FFF34707269EB827006F6EA4 /* uxn.c */; };
25 | FFF3470E269EB848006F6EA4 /* apu.c in Sources */ = {isa = PBXBuildFile; fileRef = FFF3470B269EB848006F6EA4 /* apu.c */; };
26 | FFF3470F269EB848006F6EA4 /* ppu.c in Sources */ = {isa = PBXBuildFile; fileRef = FFF3470C269EB848006F6EA4 /* ppu.c */; };
27 | /* End PBXBuildFile section */
28 |
29 | /* Begin PBXContainerItemProxy section */
30 | FF4C0742269E23800040F453 /* PBXContainerItemProxy */ = {
31 | isa = PBXContainerItemProxy;
32 | containerPortal = FF4C0723269E237A0040F453 /* Project object */;
33 | proxyType = 1;
34 | remoteGlobalIDString = FF4C072A269E237A0040F453;
35 | remoteInfo = UxniOS;
36 | };
37 | FF4C074D269E23800040F453 /* PBXContainerItemProxy */ = {
38 | isa = PBXContainerItemProxy;
39 | containerPortal = FF4C0723269E237A0040F453 /* Project object */;
40 | proxyType = 1;
41 | remoteGlobalIDString = FF4C072A269E237A0040F453;
42 | remoteInfo = UxniOS;
43 | };
44 | /* End PBXContainerItemProxy section */
45 |
46 | /* Begin PBXFileReference section */
47 | FF1CC29E269E26D400444B1A /* UxniOS-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "UxniOS-Bridging-Header.h"; sourceTree = ""; };
48 | FF35118C269E302300F852B2 /* UxnBridge.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = UxnBridge.h; sourceTree = ""; };
49 | FF35118D269E30DB00F852B2 /* UxnBridge.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = UxnBridge.m; sourceTree = ""; };
50 | FF35118F269E339E00F852B2 /* hello.rom */ = {isa = PBXFileReference; lastKnownFileType = file; path = hello.rom; sourceTree = ""; };
51 | FF4C072B269E237A0040F453 /* UxniOS.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = UxniOS.app; sourceTree = BUILT_PRODUCTS_DIR; };
52 | FF4C072E269E237A0040F453 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; };
53 | FF4C0732269E237A0040F453 /* ViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ViewController.swift; sourceTree = ""; };
54 | FF4C0735269E237A0040F453 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; };
55 | FF4C0737269E23800040F453 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; };
56 | FF4C073A269E23800040F453 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; };
57 | FF4C073C269E23800040F453 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; };
58 | FF4C0741269E23800040F453 /* UxniOSTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = UxniOSTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
59 | FF4C0745269E23800040F453 /* UxniOSTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UxniOSTests.swift; sourceTree = ""; };
60 | FF4C0747269E23800040F453 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; };
61 | FF4C074C269E23800040F453 /* UxniOSUITests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = UxniOSUITests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
62 | FF4C0750269E23800040F453 /* UxniOSUITests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UxniOSUITests.swift; sourceTree = ""; };
63 | FF4C0752269E23800040F453 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; };
64 | FF6831D0269E8B1C007A84F2 /* screen.rom */ = {isa = PBXFileReference; lastKnownFileType = file; path = screen.rom; sourceTree = ""; };
65 | FF6831D2269E8DB2007A84F2 /* piano.rom */ = {isa = PBXFileReference; lastKnownFileType = file; path = piano.rom; sourceTree = ""; };
66 | FFD2DDAB26A1C28E00AD30FC /* polycat.rom */ = {isa = PBXFileReference; lastKnownFileType = file; path = polycat.rom; sourceTree = ""; };
67 | FFD2DDAD26A1C48300AD30FC /* life.rom */ = {isa = PBXFileReference; lastKnownFileType = file; path = life.rom; sourceTree = ""; };
68 | FFD2DDAF26A1C6C400AD30FC /* bifurcan.rom */ = {isa = PBXFileReference; lastKnownFileType = file; path = bifurcan.rom; sourceTree = ""; };
69 | FFF34706269EB827006F6EA4 /* uxn.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = uxn.h; path = uxn/src/uxn.h; sourceTree = SOURCE_ROOT; };
70 | FFF34707269EB827006F6EA4 /* uxn.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = uxn.c; path = uxn/src/uxn.c; sourceTree = SOURCE_ROOT; };
71 | FFF3470A269EB848006F6EA4 /* ppu.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ppu.h; path = uxn/src/devices/ppu.h; sourceTree = SOURCE_ROOT; };
72 | FFF3470B269EB848006F6EA4 /* apu.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = apu.c; path = uxn/src/devices/apu.c; sourceTree = SOURCE_ROOT; };
73 | FFF3470C269EB848006F6EA4 /* ppu.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = ppu.c; path = uxn/src/devices/ppu.c; sourceTree = SOURCE_ROOT; };
74 | FFF3470D269EB848006F6EA4 /* apu.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = apu.h; path = uxn/src/devices/apu.h; sourceTree = SOURCE_ROOT; };
75 | /* End PBXFileReference section */
76 |
77 | /* Begin PBXFrameworksBuildPhase section */
78 | FF4C0728269E237A0040F453 /* Frameworks */ = {
79 | isa = PBXFrameworksBuildPhase;
80 | buildActionMask = 2147483647;
81 | files = (
82 | );
83 | runOnlyForDeploymentPostprocessing = 0;
84 | };
85 | FF4C073E269E23800040F453 /* Frameworks */ = {
86 | isa = PBXFrameworksBuildPhase;
87 | buildActionMask = 2147483647;
88 | files = (
89 | );
90 | runOnlyForDeploymentPostprocessing = 0;
91 | };
92 | FF4C0749269E23800040F453 /* Frameworks */ = {
93 | isa = PBXFrameworksBuildPhase;
94 | buildActionMask = 2147483647;
95 | files = (
96 | );
97 | runOnlyForDeploymentPostprocessing = 0;
98 | };
99 | /* End PBXFrameworksBuildPhase section */
100 |
101 | /* Begin PBXGroup section */
102 | FF4C0722269E237A0040F453 = {
103 | isa = PBXGroup;
104 | children = (
105 | FF4C072D269E237A0040F453 /* UxniOS */,
106 | FF4C0744269E23800040F453 /* UxniOSTests */,
107 | FF4C074F269E23800040F453 /* UxniOSUITests */,
108 | FF4C072C269E237A0040F453 /* Products */,
109 | );
110 | sourceTree = "";
111 | };
112 | FF4C072C269E237A0040F453 /* Products */ = {
113 | isa = PBXGroup;
114 | children = (
115 | FF4C072B269E237A0040F453 /* UxniOS.app */,
116 | FF4C0741269E23800040F453 /* UxniOSTests.xctest */,
117 | FF4C074C269E23800040F453 /* UxniOSUITests.xctest */,
118 | );
119 | name = Products;
120 | sourceTree = "";
121 | };
122 | FF4C072D269E237A0040F453 /* UxniOS */ = {
123 | isa = PBXGroup;
124 | children = (
125 | FFF34705269EB817006F6EA4 /* uxn */,
126 | FFF346FD269EB6DE006F6EA4 /* roms */,
127 | FF1CC29E269E26D400444B1A /* UxniOS-Bridging-Header.h */,
128 | FF35118C269E302300F852B2 /* UxnBridge.h */,
129 | FF35118D269E30DB00F852B2 /* UxnBridge.m */,
130 | FF4C0732269E237A0040F453 /* ViewController.swift */,
131 | FF4C072E269E237A0040F453 /* AppDelegate.swift */,
132 | FF4C0734269E237A0040F453 /* Main.storyboard */,
133 | FF4C0737269E23800040F453 /* Assets.xcassets */,
134 | FF4C0739269E23800040F453 /* LaunchScreen.storyboard */,
135 | FF4C073C269E23800040F453 /* Info.plist */,
136 | );
137 | path = UxniOS;
138 | sourceTree = "";
139 | };
140 | FF4C0744269E23800040F453 /* UxniOSTests */ = {
141 | isa = PBXGroup;
142 | children = (
143 | FF4C0745269E23800040F453 /* UxniOSTests.swift */,
144 | FF4C0747269E23800040F453 /* Info.plist */,
145 | );
146 | path = UxniOSTests;
147 | sourceTree = "";
148 | };
149 | FF4C074F269E23800040F453 /* UxniOSUITests */ = {
150 | isa = PBXGroup;
151 | children = (
152 | FF4C0750269E23800040F453 /* UxniOSUITests.swift */,
153 | FF4C0752269E23800040F453 /* Info.plist */,
154 | );
155 | path = UxniOSUITests;
156 | sourceTree = "";
157 | };
158 | FFF346FD269EB6DE006F6EA4 /* roms */ = {
159 | isa = PBXGroup;
160 | children = (
161 | FFD2DDAF26A1C6C400AD30FC /* bifurcan.rom */,
162 | FFD2DDAD26A1C48300AD30FC /* life.rom */,
163 | FFD2DDAB26A1C28E00AD30FC /* polycat.rom */,
164 | FF6831D2269E8DB2007A84F2 /* piano.rom */,
165 | FF6831D0269E8B1C007A84F2 /* screen.rom */,
166 | FF35118F269E339E00F852B2 /* hello.rom */,
167 | );
168 | path = roms;
169 | sourceTree = "";
170 | };
171 | FFF34705269EB817006F6EA4 /* uxn */ = {
172 | isa = PBXGroup;
173 | children = (
174 | FFF34709269EB83B006F6EA4 /* devices */,
175 | FFF34707269EB827006F6EA4 /* uxn.c */,
176 | FFF34706269EB827006F6EA4 /* uxn.h */,
177 | );
178 | path = uxn;
179 | sourceTree = "";
180 | };
181 | FFF34709269EB83B006F6EA4 /* devices */ = {
182 | isa = PBXGroup;
183 | children = (
184 | FFF3470B269EB848006F6EA4 /* apu.c */,
185 | FFF3470D269EB848006F6EA4 /* apu.h */,
186 | FFF3470C269EB848006F6EA4 /* ppu.c */,
187 | FFF3470A269EB848006F6EA4 /* ppu.h */,
188 | );
189 | path = devices;
190 | sourceTree = "";
191 | };
192 | /* End PBXGroup section */
193 |
194 | /* Begin PBXNativeTarget section */
195 | FF4C072A269E237A0040F453 /* UxniOS */ = {
196 | isa = PBXNativeTarget;
197 | buildConfigurationList = FF4C0755269E23800040F453 /* Build configuration list for PBXNativeTarget "UxniOS" */;
198 | buildPhases = (
199 | FF4C0727269E237A0040F453 /* Sources */,
200 | FF4C0728269E237A0040F453 /* Frameworks */,
201 | FF4C0729269E237A0040F453 /* Resources */,
202 | );
203 | buildRules = (
204 | );
205 | dependencies = (
206 | );
207 | name = UxniOS;
208 | productName = UxniOS;
209 | productReference = FF4C072B269E237A0040F453 /* UxniOS.app */;
210 | productType = "com.apple.product-type.application";
211 | };
212 | FF4C0740269E23800040F453 /* UxniOSTests */ = {
213 | isa = PBXNativeTarget;
214 | buildConfigurationList = FF4C0758269E23800040F453 /* Build configuration list for PBXNativeTarget "UxniOSTests" */;
215 | buildPhases = (
216 | FF4C073D269E23800040F453 /* Sources */,
217 | FF4C073E269E23800040F453 /* Frameworks */,
218 | FF4C073F269E23800040F453 /* Resources */,
219 | );
220 | buildRules = (
221 | );
222 | dependencies = (
223 | FF4C0743269E23800040F453 /* PBXTargetDependency */,
224 | );
225 | name = UxniOSTests;
226 | productName = UxniOSTests;
227 | productReference = FF4C0741269E23800040F453 /* UxniOSTests.xctest */;
228 | productType = "com.apple.product-type.bundle.unit-test";
229 | };
230 | FF4C074B269E23800040F453 /* UxniOSUITests */ = {
231 | isa = PBXNativeTarget;
232 | buildConfigurationList = FF4C075B269E23800040F453 /* Build configuration list for PBXNativeTarget "UxniOSUITests" */;
233 | buildPhases = (
234 | FF4C0748269E23800040F453 /* Sources */,
235 | FF4C0749269E23800040F453 /* Frameworks */,
236 | FF4C074A269E23800040F453 /* Resources */,
237 | );
238 | buildRules = (
239 | );
240 | dependencies = (
241 | FF4C074E269E23800040F453 /* PBXTargetDependency */,
242 | );
243 | name = UxniOSUITests;
244 | productName = UxniOSUITests;
245 | productReference = FF4C074C269E23800040F453 /* UxniOSUITests.xctest */;
246 | productType = "com.apple.product-type.bundle.ui-testing";
247 | };
248 | /* End PBXNativeTarget section */
249 |
250 | /* Begin PBXProject section */
251 | FF4C0723269E237A0040F453 /* Project object */ = {
252 | isa = PBXProject;
253 | attributes = {
254 | LastSwiftUpdateCheck = 1250;
255 | LastUpgradeCheck = 1250;
256 | TargetAttributes = {
257 | FF4C072A269E237A0040F453 = {
258 | CreatedOnToolsVersion = 12.5.1;
259 | LastSwiftMigration = 1250;
260 | };
261 | FF4C0740269E23800040F453 = {
262 | CreatedOnToolsVersion = 12.5.1;
263 | TestTargetID = FF4C072A269E237A0040F453;
264 | };
265 | FF4C074B269E23800040F453 = {
266 | CreatedOnToolsVersion = 12.5.1;
267 | TestTargetID = FF4C072A269E237A0040F453;
268 | };
269 | };
270 | };
271 | buildConfigurationList = FF4C0726269E237A0040F453 /* Build configuration list for PBXProject "UxniOS" */;
272 | compatibilityVersion = "Xcode 9.3";
273 | developmentRegion = en;
274 | hasScannedForEncodings = 0;
275 | knownRegions = (
276 | en,
277 | Base,
278 | );
279 | mainGroup = FF4C0722269E237A0040F453;
280 | productRefGroup = FF4C072C269E237A0040F453 /* Products */;
281 | projectDirPath = "";
282 | projectRoot = "";
283 | targets = (
284 | FF4C072A269E237A0040F453 /* UxniOS */,
285 | FF4C0740269E23800040F453 /* UxniOSTests */,
286 | FF4C074B269E23800040F453 /* UxniOSUITests */,
287 | );
288 | };
289 | /* End PBXProject section */
290 |
291 | /* Begin PBXResourcesBuildPhase section */
292 | FF4C0729269E237A0040F453 /* Resources */ = {
293 | isa = PBXResourcesBuildPhase;
294 | buildActionMask = 2147483647;
295 | files = (
296 | FF4C073B269E23800040F453 /* LaunchScreen.storyboard in Resources */,
297 | FF6831D1269E8B1C007A84F2 /* screen.rom in Resources */,
298 | FF6831D3269E8DB2007A84F2 /* piano.rom in Resources */,
299 | FFD2DDAC26A1C28E00AD30FC /* polycat.rom in Resources */,
300 | FFD2DDB026A1C6C400AD30FC /* bifurcan.rom in Resources */,
301 | FFD2DDAE26A1C48300AD30FC /* life.rom in Resources */,
302 | FF351190269E339E00F852B2 /* hello.rom in Resources */,
303 | FF4C0738269E23800040F453 /* Assets.xcassets in Resources */,
304 | FF4C0736269E237A0040F453 /* Main.storyboard in Resources */,
305 | );
306 | runOnlyForDeploymentPostprocessing = 0;
307 | };
308 | FF4C073F269E23800040F453 /* Resources */ = {
309 | isa = PBXResourcesBuildPhase;
310 | buildActionMask = 2147483647;
311 | files = (
312 | );
313 | runOnlyForDeploymentPostprocessing = 0;
314 | };
315 | FF4C074A269E23800040F453 /* Resources */ = {
316 | isa = PBXResourcesBuildPhase;
317 | buildActionMask = 2147483647;
318 | files = (
319 | );
320 | runOnlyForDeploymentPostprocessing = 0;
321 | };
322 | /* End PBXResourcesBuildPhase section */
323 |
324 | /* Begin PBXSourcesBuildPhase section */
325 | FF4C0727269E237A0040F453 /* Sources */ = {
326 | isa = PBXSourcesBuildPhase;
327 | buildActionMask = 2147483647;
328 | files = (
329 | FF4C0733269E237A0040F453 /* ViewController.swift in Sources */,
330 | FFF3470E269EB848006F6EA4 /* apu.c in Sources */,
331 | FFF34708269EB827006F6EA4 /* uxn.c in Sources */,
332 | FFF3470F269EB848006F6EA4 /* ppu.c in Sources */,
333 | FF35118E269E30DB00F852B2 /* UxnBridge.m in Sources */,
334 | FF4C072F269E237A0040F453 /* AppDelegate.swift in Sources */,
335 | );
336 | runOnlyForDeploymentPostprocessing = 0;
337 | };
338 | FF4C073D269E23800040F453 /* Sources */ = {
339 | isa = PBXSourcesBuildPhase;
340 | buildActionMask = 2147483647;
341 | files = (
342 | FF4C0746269E23800040F453 /* UxniOSTests.swift in Sources */,
343 | );
344 | runOnlyForDeploymentPostprocessing = 0;
345 | };
346 | FF4C0748269E23800040F453 /* Sources */ = {
347 | isa = PBXSourcesBuildPhase;
348 | buildActionMask = 2147483647;
349 | files = (
350 | FF4C0751269E23800040F453 /* UxniOSUITests.swift in Sources */,
351 | );
352 | runOnlyForDeploymentPostprocessing = 0;
353 | };
354 | /* End PBXSourcesBuildPhase section */
355 |
356 | /* Begin PBXTargetDependency section */
357 | FF4C0743269E23800040F453 /* PBXTargetDependency */ = {
358 | isa = PBXTargetDependency;
359 | target = FF4C072A269E237A0040F453 /* UxniOS */;
360 | targetProxy = FF4C0742269E23800040F453 /* PBXContainerItemProxy */;
361 | };
362 | FF4C074E269E23800040F453 /* PBXTargetDependency */ = {
363 | isa = PBXTargetDependency;
364 | target = FF4C072A269E237A0040F453 /* UxniOS */;
365 | targetProxy = FF4C074D269E23800040F453 /* PBXContainerItemProxy */;
366 | };
367 | /* End PBXTargetDependency section */
368 |
369 | /* Begin PBXVariantGroup section */
370 | FF4C0734269E237A0040F453 /* Main.storyboard */ = {
371 | isa = PBXVariantGroup;
372 | children = (
373 | FF4C0735269E237A0040F453 /* Base */,
374 | );
375 | name = Main.storyboard;
376 | sourceTree = "";
377 | };
378 | FF4C0739269E23800040F453 /* LaunchScreen.storyboard */ = {
379 | isa = PBXVariantGroup;
380 | children = (
381 | FF4C073A269E23800040F453 /* Base */,
382 | );
383 | name = LaunchScreen.storyboard;
384 | sourceTree = "";
385 | };
386 | /* End PBXVariantGroup section */
387 |
388 | /* Begin XCBuildConfiguration section */
389 | FF4C0753269E23800040F453 /* Debug */ = {
390 | isa = XCBuildConfiguration;
391 | buildSettings = {
392 | ALWAYS_SEARCH_USER_PATHS = NO;
393 | CLANG_ANALYZER_NONNULL = YES;
394 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
395 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
396 | CLANG_CXX_LIBRARY = "libc++";
397 | CLANG_ENABLE_MODULES = YES;
398 | CLANG_ENABLE_OBJC_ARC = YES;
399 | CLANG_ENABLE_OBJC_WEAK = YES;
400 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
401 | CLANG_WARN_BOOL_CONVERSION = YES;
402 | CLANG_WARN_COMMA = YES;
403 | CLANG_WARN_CONSTANT_CONVERSION = YES;
404 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
405 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
406 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
407 | CLANG_WARN_EMPTY_BODY = YES;
408 | CLANG_WARN_ENUM_CONVERSION = YES;
409 | CLANG_WARN_INFINITE_RECURSION = YES;
410 | CLANG_WARN_INT_CONVERSION = YES;
411 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
412 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
413 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
414 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
415 | CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;
416 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
417 | CLANG_WARN_STRICT_PROTOTYPES = YES;
418 | CLANG_WARN_SUSPICIOUS_MOVE = YES;
419 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
420 | CLANG_WARN_UNREACHABLE_CODE = YES;
421 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
422 | COPY_PHASE_STRIP = NO;
423 | DEBUG_INFORMATION_FORMAT = dwarf;
424 | ENABLE_STRICT_OBJC_MSGSEND = YES;
425 | ENABLE_TESTABILITY = YES;
426 | GCC_C_LANGUAGE_STANDARD = gnu11;
427 | GCC_DYNAMIC_NO_PIC = NO;
428 | GCC_NO_COMMON_BLOCKS = YES;
429 | GCC_OPTIMIZATION_LEVEL = 0;
430 | GCC_PREPROCESSOR_DEFINITIONS = (
431 | "DEBUG=1",
432 | "$(inherited)",
433 | );
434 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
435 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
436 | GCC_WARN_UNDECLARED_SELECTOR = YES;
437 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
438 | GCC_WARN_UNUSED_FUNCTION = YES;
439 | GCC_WARN_UNUSED_VARIABLE = YES;
440 | IPHONEOS_DEPLOYMENT_TARGET = 14.5;
441 | MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE;
442 | MTL_FAST_MATH = YES;
443 | ONLY_ACTIVE_ARCH = YES;
444 | SDKROOT = iphoneos;
445 | SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG;
446 | SWIFT_OPTIMIZATION_LEVEL = "-Onone";
447 | };
448 | name = Debug;
449 | };
450 | FF4C0754269E23800040F453 /* Release */ = {
451 | isa = XCBuildConfiguration;
452 | buildSettings = {
453 | ALWAYS_SEARCH_USER_PATHS = NO;
454 | CLANG_ANALYZER_NONNULL = YES;
455 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
456 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
457 | CLANG_CXX_LIBRARY = "libc++";
458 | CLANG_ENABLE_MODULES = YES;
459 | CLANG_ENABLE_OBJC_ARC = YES;
460 | CLANG_ENABLE_OBJC_WEAK = YES;
461 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
462 | CLANG_WARN_BOOL_CONVERSION = YES;
463 | CLANG_WARN_COMMA = YES;
464 | CLANG_WARN_CONSTANT_CONVERSION = YES;
465 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
466 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
467 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
468 | CLANG_WARN_EMPTY_BODY = YES;
469 | CLANG_WARN_ENUM_CONVERSION = YES;
470 | CLANG_WARN_INFINITE_RECURSION = YES;
471 | CLANG_WARN_INT_CONVERSION = YES;
472 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
473 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
474 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
475 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
476 | CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;
477 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
478 | CLANG_WARN_STRICT_PROTOTYPES = YES;
479 | CLANG_WARN_SUSPICIOUS_MOVE = YES;
480 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
481 | CLANG_WARN_UNREACHABLE_CODE = YES;
482 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
483 | COPY_PHASE_STRIP = NO;
484 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
485 | ENABLE_NS_ASSERTIONS = NO;
486 | ENABLE_STRICT_OBJC_MSGSEND = YES;
487 | GCC_C_LANGUAGE_STANDARD = gnu11;
488 | GCC_NO_COMMON_BLOCKS = YES;
489 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
490 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
491 | GCC_WARN_UNDECLARED_SELECTOR = YES;
492 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
493 | GCC_WARN_UNUSED_FUNCTION = YES;
494 | GCC_WARN_UNUSED_VARIABLE = YES;
495 | IPHONEOS_DEPLOYMENT_TARGET = 14.5;
496 | MTL_ENABLE_DEBUG_INFO = NO;
497 | MTL_FAST_MATH = YES;
498 | SDKROOT = iphoneos;
499 | SWIFT_COMPILATION_MODE = wholemodule;
500 | SWIFT_OPTIMIZATION_LEVEL = "-O";
501 | VALIDATE_PRODUCT = YES;
502 | };
503 | name = Release;
504 | };
505 | FF4C0756269E23800040F453 /* Debug */ = {
506 | isa = XCBuildConfiguration;
507 | buildSettings = {
508 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
509 | ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
510 | CLANG_ENABLE_MODULES = YES;
511 | CODE_SIGN_STYLE = Automatic;
512 | DEVELOPMENT_TEAM = M5B635R5MU;
513 | INFOPLIST_FILE = UxniOS/Info.plist;
514 | IPHONEOS_DEPLOYMENT_TARGET = 10.0;
515 | LD_RUNPATH_SEARCH_PATHS = (
516 | "$(inherited)",
517 | "@executable_path/Frameworks",
518 | );
519 | PRODUCT_BUNDLE_IDENTIFIER = co.kylestewart.UxniOS;
520 | PRODUCT_NAME = "$(TARGET_NAME)";
521 | SWIFT_OBJC_BRIDGING_HEADER = "UxniOS/UxniOS-Bridging-Header.h";
522 | SWIFT_OPTIMIZATION_LEVEL = "-Onone";
523 | SWIFT_VERSION = 5.0;
524 | TARGETED_DEVICE_FAMILY = "1,2";
525 | };
526 | name = Debug;
527 | };
528 | FF4C0757269E23800040F453 /* Release */ = {
529 | isa = XCBuildConfiguration;
530 | buildSettings = {
531 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
532 | ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
533 | CLANG_ENABLE_MODULES = YES;
534 | CODE_SIGN_STYLE = Automatic;
535 | DEVELOPMENT_TEAM = M5B635R5MU;
536 | INFOPLIST_FILE = UxniOS/Info.plist;
537 | IPHONEOS_DEPLOYMENT_TARGET = 10.0;
538 | LD_RUNPATH_SEARCH_PATHS = (
539 | "$(inherited)",
540 | "@executable_path/Frameworks",
541 | );
542 | PRODUCT_BUNDLE_IDENTIFIER = co.kylestewart.UxniOS;
543 | PRODUCT_NAME = "$(TARGET_NAME)";
544 | SWIFT_OBJC_BRIDGING_HEADER = "UxniOS/UxniOS-Bridging-Header.h";
545 | SWIFT_VERSION = 5.0;
546 | TARGETED_DEVICE_FAMILY = "1,2";
547 | };
548 | name = Release;
549 | };
550 | FF4C0759269E23800040F453 /* Debug */ = {
551 | isa = XCBuildConfiguration;
552 | buildSettings = {
553 | ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES;
554 | BUNDLE_LOADER = "$(TEST_HOST)";
555 | CODE_SIGN_STYLE = Automatic;
556 | DEVELOPMENT_TEAM = M5B635R5MU;
557 | INFOPLIST_FILE = UxniOSTests/Info.plist;
558 | IPHONEOS_DEPLOYMENT_TARGET = 14.5;
559 | LD_RUNPATH_SEARCH_PATHS = (
560 | "$(inherited)",
561 | "@executable_path/Frameworks",
562 | "@loader_path/Frameworks",
563 | );
564 | PRODUCT_BUNDLE_IDENTIFIER = co.kylestewart.UxniOSTests;
565 | PRODUCT_NAME = "$(TARGET_NAME)";
566 | SWIFT_VERSION = 5.0;
567 | TARGETED_DEVICE_FAMILY = "1,2";
568 | TEST_HOST = "$(BUILT_PRODUCTS_DIR)/UxniOS.app/UxniOS";
569 | };
570 | name = Debug;
571 | };
572 | FF4C075A269E23800040F453 /* Release */ = {
573 | isa = XCBuildConfiguration;
574 | buildSettings = {
575 | ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES;
576 | BUNDLE_LOADER = "$(TEST_HOST)";
577 | CODE_SIGN_STYLE = Automatic;
578 | DEVELOPMENT_TEAM = M5B635R5MU;
579 | INFOPLIST_FILE = UxniOSTests/Info.plist;
580 | IPHONEOS_DEPLOYMENT_TARGET = 14.5;
581 | LD_RUNPATH_SEARCH_PATHS = (
582 | "$(inherited)",
583 | "@executable_path/Frameworks",
584 | "@loader_path/Frameworks",
585 | );
586 | PRODUCT_BUNDLE_IDENTIFIER = co.kylestewart.UxniOSTests;
587 | PRODUCT_NAME = "$(TARGET_NAME)";
588 | SWIFT_VERSION = 5.0;
589 | TARGETED_DEVICE_FAMILY = "1,2";
590 | TEST_HOST = "$(BUILT_PRODUCTS_DIR)/UxniOS.app/UxniOS";
591 | };
592 | name = Release;
593 | };
594 | FF4C075C269E23800040F453 /* Debug */ = {
595 | isa = XCBuildConfiguration;
596 | buildSettings = {
597 | ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES;
598 | CODE_SIGN_STYLE = Automatic;
599 | DEVELOPMENT_TEAM = M5B635R5MU;
600 | INFOPLIST_FILE = UxniOSUITests/Info.plist;
601 | LD_RUNPATH_SEARCH_PATHS = (
602 | "$(inherited)",
603 | "@executable_path/Frameworks",
604 | "@loader_path/Frameworks",
605 | );
606 | PRODUCT_BUNDLE_IDENTIFIER = co.kylestewart.UxniOSUITests;
607 | PRODUCT_NAME = "$(TARGET_NAME)";
608 | SWIFT_VERSION = 5.0;
609 | TARGETED_DEVICE_FAMILY = "1,2";
610 | TEST_TARGET_NAME = UxniOS;
611 | };
612 | name = Debug;
613 | };
614 | FF4C075D269E23800040F453 /* Release */ = {
615 | isa = XCBuildConfiguration;
616 | buildSettings = {
617 | ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES;
618 | CODE_SIGN_STYLE = Automatic;
619 | DEVELOPMENT_TEAM = M5B635R5MU;
620 | INFOPLIST_FILE = UxniOSUITests/Info.plist;
621 | LD_RUNPATH_SEARCH_PATHS = (
622 | "$(inherited)",
623 | "@executable_path/Frameworks",
624 | "@loader_path/Frameworks",
625 | );
626 | PRODUCT_BUNDLE_IDENTIFIER = co.kylestewart.UxniOSUITests;
627 | PRODUCT_NAME = "$(TARGET_NAME)";
628 | SWIFT_VERSION = 5.0;
629 | TARGETED_DEVICE_FAMILY = "1,2";
630 | TEST_TARGET_NAME = UxniOS;
631 | };
632 | name = Release;
633 | };
634 | /* End XCBuildConfiguration section */
635 |
636 | /* Begin XCConfigurationList section */
637 | FF4C0726269E237A0040F453 /* Build configuration list for PBXProject "UxniOS" */ = {
638 | isa = XCConfigurationList;
639 | buildConfigurations = (
640 | FF4C0753269E23800040F453 /* Debug */,
641 | FF4C0754269E23800040F453 /* Release */,
642 | );
643 | defaultConfigurationIsVisible = 0;
644 | defaultConfigurationName = Release;
645 | };
646 | FF4C0755269E23800040F453 /* Build configuration list for PBXNativeTarget "UxniOS" */ = {
647 | isa = XCConfigurationList;
648 | buildConfigurations = (
649 | FF4C0756269E23800040F453 /* Debug */,
650 | FF4C0757269E23800040F453 /* Release */,
651 | );
652 | defaultConfigurationIsVisible = 0;
653 | defaultConfigurationName = Release;
654 | };
655 | FF4C0758269E23800040F453 /* Build configuration list for PBXNativeTarget "UxniOSTests" */ = {
656 | isa = XCConfigurationList;
657 | buildConfigurations = (
658 | FF4C0759269E23800040F453 /* Debug */,
659 | FF4C075A269E23800040F453 /* Release */,
660 | );
661 | defaultConfigurationIsVisible = 0;
662 | defaultConfigurationName = Release;
663 | };
664 | FF4C075B269E23800040F453 /* Build configuration list for PBXNativeTarget "UxniOSUITests" */ = {
665 | isa = XCConfigurationList;
666 | buildConfigurations = (
667 | FF4C075C269E23800040F453 /* Debug */,
668 | FF4C075D269E23800040F453 /* Release */,
669 | );
670 | defaultConfigurationIsVisible = 0;
671 | defaultConfigurationName = Release;
672 | };
673 | /* End XCConfigurationList section */
674 | };
675 | rootObject = FF4C0723269E237A0040F453 /* Project object */;
676 | }
677 |
--------------------------------------------------------------------------------