From ccc468ab0bf18b80bd3a48791b788022cffa42d1 Mon Sep 17 00:00:00 2001 From: tudnai Date: Sat, 9 May 2020 03:39:55 -0700 Subject: [PATCH] - Splash screen - HiRes pixel rendering improvements --- A2Mac.xcodeproj/project.pbxproj | 6 +++ A2Mac/Base.lproj/Main.storyboard | 21 +++++--- A2Mac/HiRes.swift | 81 +++++++++++++++---------------- A2Mac/ViewController.swift | 29 +++++++++-- Resources/apple-rainbow.jpg | Bin 0 -> 26112 bytes 5 files changed, 82 insertions(+), 55 deletions(-) create mode 100644 Resources/apple-rainbow.jpg diff --git a/A2Mac.xcodeproj/project.pbxproj b/A2Mac.xcodeproj/project.pbxproj index c0385a3..40fd6da 100644 --- a/A2Mac.xcodeproj/project.pbxproj +++ b/A2Mac.xcodeproj/project.pbxproj @@ -68,6 +68,8 @@ 325EB6AC2401118300C6B4A4 /* Xonix.woz in Resources */ = {isa = PBXBuildFile; fileRef = 325EB69B2401118300C6B4A4 /* Xonix.woz */; }; 3262F37623E169F8008BDB95 /* spk_dn.wav in Resources */ = {isa = PBXBuildFile; fileRef = 3262F37423E169F8008BDB95 /* spk_dn.wav */; }; 3262F37723E169F8008BDB95 /* spk_up.wav in Resources */ = {isa = PBXBuildFile; fileRef = 3262F37523E169F8008BDB95 /* spk_up.wav */; }; + 32A9F72C24668D26004902A1 /* apple-rainbow.jpg in Resources */ = {isa = PBXBuildFile; fileRef = 32A9F72B24668D26004902A1 /* apple-rainbow.jpg */; }; + 32A9F72D24668D26004902A1 /* apple-rainbow.jpg in Resources */ = {isa = PBXBuildFile; fileRef = 32A9F72B24668D26004902A1 /* apple-rainbow.jpg */; }; 32BFFB5B22EACC630003B53F /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 32BFFB5A22EACC630003B53F /* AppDelegate.swift */; }; 32BFFB5D22EACC630003B53F /* ViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 32BFFB5C22EACC630003B53F /* ViewController.swift */; }; 32BFFB5F22EACC660003B53F /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 32BFFB5E22EACC660003B53F /* Assets.xcassets */; }; @@ -186,6 +188,7 @@ 3264261023284F6F008B615F /* Apple2_mmio_8bit_ioaddr.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Apple2_mmio_8bit_ioaddr.h; sourceTree = ""; }; 326426112328ADF4008B615F /* Apple_II_ROM.s */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.asm; path = Apple_II_ROM.s; sourceTree = ""; }; 326ED2EE232D7A0000A41337 /* 6502_functional_test.bin */ = {isa = PBXFileReference; lastKnownFileType = archive.macbinary; path = 6502_functional_test.bin; sourceTree = SOURCE_ROOT; }; + 32A9F72B24668D26004902A1 /* apple-rainbow.jpg */ = {isa = PBXFileReference; lastKnownFileType = image.jpeg; path = "apple-rainbow.jpg"; sourceTree = ""; }; 32B18435233F10BC00DBB4AB /* Shaders.metal */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.metal; path = Shaders.metal; sourceTree = ""; }; 32B18438233FAB3900DBB4AB /* verticies.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = verticies.swift; sourceTree = ""; }; 32BFFB5722EACC630003B53F /* A2Mac.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = A2Mac.app; sourceTree = BUILT_PRODUCTS_DIR; }; @@ -390,6 +393,7 @@ 3262F37823E17013008BDB95 /* Resources */ = { isa = PBXGroup; children = ( + 32A9F72B24668D26004902A1 /* apple-rainbow.jpg */, 3262F37423E169F8008BDB95 /* spk_dn.wav */, 3262F37523E169F8008BDB95 /* spk_up.wav */, 325EB67B23FBD43800C6B4A4 /* PrintChar21.ttf */, @@ -713,6 +717,7 @@ 325EB68D23FDDFD200C6B4A4 /* Merlin-8 v2.48 (DOS 3.3).woz in Resources */, 325EB6A62401118300C6B4A4 /* ProDOS_312.woz in Resources */, 325EB6AC2401118300C6B4A4 /* Xonix.woz in Resources */, + 32A9F72D24668D26004902A1 /* apple-rainbow.jpg in Resources */, 323E2DCF245531E600156805 /* Apple2e_Enhanced.rom in Resources */, 325EB67D23FBD43800C6B4A4 /* PrintChar21.ttf in Resources */, 325EB6A42401118300C6B4A4 /* Qbit.woz in Resources */, @@ -749,6 +754,7 @@ 3262F37723E169F8008BDB95 /* spk_up.wav in Resources */, 32089E4824556DBD0036E667 /* PRNumber3.ttf in Resources */, 325EB6A92401118300C6B4A4 /* Sneakers.woz in Resources */, + 32A9F72C24668D26004902A1 /* apple-rainbow.jpg in Resources */, 325EB6A72401118300C6B4A4 /* ProDOS_402_System.woz in Resources */, 325EB69023FE028800C6B4A4 /* Donkey Kong.woz in Resources */, 325EB68923FDDF6200C6B4A4 /* Hard Hat Mack - Disk 1, Side A.woz in Resources */, diff --git a/A2Mac/Base.lproj/Main.storyboard b/A2Mac/Base.lproj/Main.storyboard index 266337a..6a9b6df 100644 --- a/A2Mac/Base.lproj/Main.storyboard +++ b/A2Mac/Base.lproj/Main.storyboard @@ -789,7 +789,7 @@ - + @@ -804,7 +804,7 @@ - + @@ -837,16 +837,22 @@ @@@@@@@@@@@@@@@@@@22@@@@@@@@@@@@@@@@@@@@ @@@@@@@@@@@@@@@@@@23@@@@@@@@@@@@@@@@@@@@ @@@@@@@@@@@@@@@@@@24@@@@@@@@@@@@@@@@@@@@ - + - + - @@ -1074,6 +1081,6 @@ - + diff --git a/A2Mac/HiRes.swift b/A2Mac/HiRes.swift index 611a56a..2ad416f 100644 --- a/A2Mac/HiRes.swift +++ b/A2Mac/HiRes.swift @@ -400,7 +400,7 @@ class HiRes: NSView { static let ScreenBitmapSize = (PixelWidth * PixelHeight * 4) static let context = createBitmapContext(pixelsWide: PixelWidth, PixelHeight) static let pixels = UnsafeMutableRawBufferPointer(start: context?.data, count: ScreenBitmapSize) - static var typedPointer = pixels.bindMemory(to: UInt32.self) + static var pixelsRGBA = pixels.bindMemory(to: UInt32.self) #endif let R = 2 @@ -499,24 +499,21 @@ class HiRes: NSView { break case 0x01: // purple (bits are in reverse!) - HiRes.typedPointer[colorAddr] = color_purple; -// HiRes.typedPointer[colorAddr + 1] = color_black; + HiRes.pixelsRGBA[colorAddr] = color_purple; + if (prev != 0x03) && (prev != 0x07) && (prev != 0x00) && (prev != 0x04) { + HiRes.pixelsRGBA[colorAddr - 1] = color_purple; + } case 0x02: // green // reducing color bleeding - if (prev == 0x01) || - (prev == 0x05) - { -// HiRes.typedPointer[colorAddr + 1] = color_black; - } - else { - HiRes.typedPointer[colorAddr] = color_green; - HiRes.typedPointer[colorAddr + 1] = color_green; + if (colorAddr > 0) && (HiRes.pixelsRGBA[colorAddr - 1] != color_black) { + HiRes.pixelsRGBA[colorAddr] = color_green; } + HiRes.pixelsRGBA[colorAddr + 1] = color_green; case 0x03: // white - HiRes.typedPointer[colorAddr] = color_white; - HiRes.typedPointer[colorAddr + 1] = color_white; + HiRes.pixelsRGBA[colorAddr] = color_white; + HiRes.pixelsRGBA[colorAddr + 1] = color_white; case 0x04: // black 2 // HiRes.typedPointer[colorAddr] = color_black; @@ -524,24 +521,21 @@ class HiRes: NSView { break case 0x05: // blue - HiRes.typedPointer[colorAddr] = color_blue; -// HiRes.typedPointer[colorAddr + 1] = color_black; + HiRes.pixelsRGBA[colorAddr] = color_blue; + if (prev != 0x03) && (prev != 0x07) && (prev != 0x00) && (prev != 0x04) { + HiRes.pixelsRGBA[colorAddr - 1] = color_blue; + } case 0x06: // orange // reducing color bleeding - if (prev == 0x01) || - (prev == 0x05) - { -// HiRes.typedPointer[colorAddr + 1] = color_black; + if (colorAddr > 0) && (HiRes.pixelsRGBA[colorAddr - 1] != color_black) { + HiRes.pixelsRGBA[colorAddr] = color_orange; } - else { - HiRes.typedPointer[colorAddr] = color_orange; - HiRes.typedPointer[colorAddr + 1] = color_orange; - } - + HiRes.pixelsRGBA[colorAddr + 1] = color_orange; + case 0x07: // white 2 - HiRes.typedPointer[colorAddr] = color_white; - HiRes.typedPointer[colorAddr + 1] = color_white; + HiRes.pixelsRGBA[colorAddr] = color_white; + HiRes.pixelsRGBA[colorAddr + 1] = color_white; default: // HiRes.typedPointer[colorAddr] = color_black; @@ -551,40 +545,39 @@ class HiRes: NSView { // white adjustment if ( (prev & 2) == 2 ) && ( (pixel & 1) == 1 ) { - HiRes.typedPointer[colorAddr] = color_white; - HiRes.typedPointer[colorAddr - 1] = color_white; + HiRes.pixelsRGBA[colorAddr] = color_white; + HiRes.pixelsRGBA[colorAddr - 1] = color_white; // TODO: Need better check if extra green was created if (HiRes.pixels[pixelAddr - 8 + G] == 0xA2 ) { - HiRes.typedPointer[colorAddr - 2] = color_black; + HiRes.pixelsRGBA[colorAddr - 2] = color_black; } } // purple adjustment -- followed by white else if (prev == 0x01) && ( (pixel == 0x01) || - (pixel == 0x03) || (pixel == 0x07) || // white - (pixel == 0x00) || (pixel == 0x04) // black + (pixel == 0x03) || (pixel == 0x07) // white +// (pixel == 0x00) || (pixel == 0x04) // black ) { // was the previous purple pixel promoted to white or is it still purple? - if ( HiRes.pixels[pixelAddr - 8 + R] == 0xBB ) { - HiRes.typedPointer[colorAddr - 1] = color_purple; + if ( HiRes.pixelsRGBA[colorAddr - 2] == color_purple ) { + HiRes.pixelsRGBA[colorAddr - 1] = color_purple; } } // blue adjustment -- followed by white else if (prev == 0x05) && ( (pixel == 0x05) || - (pixel == 0x03) || (pixel == 0x07) || // white - (pixel == 0x00) || (pixel == 0x04) // black + (pixel == 0x03) || (pixel == 0x07) // white +// (pixel == 0x00) || (pixel == 0x04) // black ) { - // was the previous purple pixel promoted to white or is it still purple? - if ( HiRes.pixels[pixelAddr - 8 + R] == 0x11 ) { - HiRes.typedPointer[colorAddr - 1] = color_blue; + // was the previous blue pixel promoted to white or is it still blue? + if ( HiRes.pixelsRGBA[colorAddr - 2] == color_blue ) { + HiRes.pixelsRGBA[colorAddr - 1] = color_blue; } } - } @@ -669,6 +662,8 @@ class HiRes: NSView { // refresh changed block only + let screenBlockMargin = 6 + let blockScreenWidth = Int(frame.width) / HiRes.blockCols * 2 let blockScreenHeigth = Int(frame.height) / HiRes.blockRows @@ -677,10 +672,10 @@ class HiRes: NSView { if blockChanged[ blockVertIdx * HiRes.blockCols / 2 + blockHorIdx ] { // refresh the entire screen let boundingBox = CGRect( - x: blockHorIdx * blockScreenWidth - 2, - y: Int(frame.height) - blockVertIdx * blockScreenHeigth - blockScreenHeigth - 2, - width: blockScreenWidth + 4, - height: blockScreenHeigth + 4) + x: blockHorIdx * blockScreenWidth - screenBlockMargin, + y: Int(frame.height) - blockVertIdx * blockScreenHeigth - blockScreenHeigth - screenBlockMargin, + width: blockScreenWidth + screenBlockMargin * 2, + height: blockScreenHeigth + screenBlockMargin * 2) self.setNeedsDisplay( boundingBox ) } diff --git a/A2Mac/ViewController.swift b/A2Mac/ViewController.swift index ebd7213..842aaf5 100644 --- a/A2Mac/ViewController.swift +++ b/A2Mac/ViewController.swift @@ -50,6 +50,7 @@ class ViewController: NSViewController { @IBOutlet weak var display: NSTextFieldCell! @IBOutlet weak var speedometer: NSTextFieldCell! @IBOutlet weak var hires: HiRes! + @IBOutlet weak var splashScreen: NSImageView! // static let charConvStr : String = @@ -101,6 +102,28 @@ class ViewController: NSViewController { var workItem : DispatchWorkItem? = nil; @IBAction func Power(_ sender: Any) { + + //------------------------------------------------------------ + // Animated Splash Screen fade out and (Text) Monitor fade in + + displayField.alphaValue = 0 + displayField.isHidden = false + splashScreen.alphaValue = 1 + splashScreen.isHidden = false + + DispatchQueue.main.asyncAfter(deadline: .now() + 1) { + NSAnimationContext.runAnimationGroup({ (context) in + context.duration = 1.0 + // Use the value you want to animate to (NOT the starting value) + self.displayField.animator().alphaValue = 1 + self.splashScreen.animator().alphaValue = 0 + }, + completionHandler:{ () -> Void in + self.displayField.alphaValue = 1 + self.splashScreen.isHidden = true + }) + } + //------------------------------------------------------------ #if SPEEDTEST if ( workItem != nil ) { @@ -624,11 +647,7 @@ class ViewController: NSViewController { override func viewDidLoad() { super.viewDidLoad() -// for y in 0 ... textLines - 1 { -// txtClear[ y * (textCols + lineEndChars) + textCols * 2 + 1 ] = "\n" -// } - - hires.needsDisplay = true; + hires.clearScreen(); woz_loadFile( Bundle.main.resourcePath, "Apple DOS 3.3 January 1983.woz" ) diff --git a/Resources/apple-rainbow.jpg b/Resources/apple-rainbow.jpg new file mode 100644 index 0000000000000000000000000000000000000000..ead56f772c75124e1f8ad2ddc13e5201fcd5ad80 GIT binary patch literal 26112 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