- Moved to SRGB color space so colors will actually match with one used by StoryBoard and GIMP

- Render function from Update
This commit is contained in:
tudnai 2020-06-10 17:48:37 -07:00
parent 8dca81904a
commit bc2ab8512d
5 changed files with 143 additions and 124 deletions

View File

@ -1196,7 +1196,7 @@
<scene sceneID="hIz-AP-VOD">
<objects>
<viewController id="XfG-lQ-9wD" customClass="ViewController" customModule="A2Mac" customModuleProvider="target" sceneMemberID="viewController">
<view key="view" wantsLayer="YES" canDrawConcurrently="YES" id="m2S-Jp-Qdl" customClass="MonitorView" customModule="A2Mac" customModuleProvider="target">
<view key="view" canDrawConcurrently="YES" id="m2S-Jp-Qdl" customClass="MonitorView" customModule="A2Mac" customModuleProvider="target">
<rect key="frame" x="0.0" y="0.0" width="1288" height="800"/>
<autoresizingMask key="autoresizingMask" flexibleMinX="YES" flexibleMaxX="YES" flexibleMinY="YES" flexibleMaxY="YES"/>
<subviews>
@ -1218,15 +1218,6 @@
<constraint firstAttribute="width" constant="1120" id="uez-Mi-0Sh"/>
<constraint firstAttribute="height" constant="768" id="zl6-au-oZj"/>
</constraints>
<contentFilters>
<ciFilter name="CIBloom">
<configuration>
<null key="inputImage"/>
<real key="inputIntensity" value="1"/>
<real key="inputRadius" value="3"/>
</configuration>
</ciFilter>
</contentFilters>
<textFieldCell key="cell" scrollable="YES" lineBreakMode="clipping" refusesFirstResponder="YES" allowsUndo="NO" sendsActionOnEndEditing="YES" state="on" baseWritingDirection="leftToRight" id="pIk-RC-s5g">
<font key="font" size="32" name="PrintChar21"/>
<string key="title">1234567890123456789012345678901234567890
@ -1253,7 +1244,7 @@
@@@@@@@@@@@@@@@@@@22@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@23@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@24@@@@@@@@@@@@@@@@@@@@</string>
<color key="textColor" name="systemGreenColor" catalog="System" colorSpace="catalog"/>
<color key="textColor" red="0.93333333333333335" green="0.93333333333333335" blue="0.93333333333333335" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<color key="backgroundColor" name="textBackgroundColor" catalog="System" colorSpace="catalog"/>
</textFieldCell>
</textField>
@ -1263,7 +1254,7 @@
<customView hidden="YES" canDrawConcurrently="YES" translatesAutoresizingMaskIntoConstraints="NO" id="LlM-EV-ruZ" userLabel="HiRes" customClass="HiRes" customModule="A2Mac" customModuleProvider="target">
<rect key="frame" x="16" y="16" width="1120" height="768"/>
</customView>
<imageView canDrawConcurrently="YES" horizontalHuggingPriority="251" verticalHuggingPriority="251" translatesAutoresizingMaskIntoConstraints="NO" id="dGn-a4-c1t" userLabel="ScanLines">
<imageView hidden="YES" canDrawConcurrently="YES" horizontalHuggingPriority="251" verticalHuggingPriority="251" translatesAutoresizingMaskIntoConstraints="NO" id="dGn-a4-c1t" userLabel="ScanLines">
<rect key="frame" x="16" y="16" width="1120" height="768"/>
<imageCell key="cell" refusesFirstResponder="YES" alignment="left" imageScaling="proportionallyUpOrDown" image="scanlines" id="jJ6-qt-oZe"/>
</imageView>

View File

@ -344,7 +344,8 @@ class HiRes: NSView {
let byteCount = (bytesPerRow * pixelsHigh)
// guard let colorSpace = CGColorSpace(name: CGColorSpace.linearSRGB) else { return nil }
guard let colorSpace = CGColorSpace(name: CGColorSpace.genericRGBLinear) else { return nil }
// guard let colorSpace = CGColorSpace(name: CGColorSpace.genericRGBLinear) else { return nil }
guard let colorSpace = CGColorSpace(name: CGColorSpace.sRGB) else { return nil }
let pixels = UnsafeMutablePointer<CUnsignedChar>.allocate(capacity: byteCount)
@ -400,7 +401,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 pixelsRGBA = pixels.bindMemory(to: UInt32.self)
static var pixelsSRGB = pixels.bindMemory(to: UInt32.self)
#endif
let R = 2
@ -482,13 +483,21 @@ class HiRes: NSView {
#elseif HIRESLOWCOLOR
// let color_black : UInt32 = 0x00000000;
// let color_white : UInt32 = 0xEEEEEEEE;
// let color_purple : UInt32 = 0xFFBB11EE;
// let color_green : UInt32 = 0xFF0BBB11;
// let color_blue : UInt32 = 0xFF1155FF;
// let color_orange : UInt32 = 0xFFEE2211;
// HiRes Colors for the SRGB color space
let color_black : UInt32 = 0x00000000;
let color_white : UInt32 = 0xEEEEEEEE;
let color_purple : UInt32 = 0xFFBB11EE;
let color_green : UInt32 = 0xFF0BBB11;
let color_blue : UInt32 = 0xFF1155FF;
let color_orange : UInt32 = 0xFFEE2211;
let color_white : UInt32 = 0xFFEEEEEE;
let color_purple : UInt32 = 0xFFDD55FF;
let color_green : UInt32 = 0xFF2BD84A;
let color_blue : UInt32 = 0xFF5599FF;
let color_orange : UInt32 = 0xFFFF6302;
// for debugging only:
let color_turquis : UInt32 = 0xFF11BBBB;
let color_yellow : UInt32 = 0xFFBBBB11;
@ -499,73 +508,73 @@ class HiRes: NSView {
switch ( pixel ) {
case 0x01: // purple (bits are in reverse!)
HiRes.pixelsRGBA[colorAddr] = color_purple;
// HiRes.pixelsRGBA[colorAddr + 1] = color_purple
HiRes.pixelsSRGB[colorAddr] = color_purple;
// HiRes.pixelsSRGB[colorAddr + 1] = color_purple
if (colorAddr >= 1) && (prev != 0x03) && (prev != 0x07) && (prev != 0x00) && (prev != 0x04) {
HiRes.pixelsRGBA[colorAddr - 1] = color_purple
HiRes.pixelsSRGB[colorAddr - 1] = color_purple
}
case 0x02: // green
// reducing color bleeding
if (colorAddr > 0) && (HiRes.pixelsRGBA[colorAddr - 1] != color_black) {
HiRes.pixelsRGBA[colorAddr] = color_green
if (colorAddr > 0) && (HiRes.pixelsSRGB[colorAddr - 1] != color_black) {
HiRes.pixelsSRGB[colorAddr] = color_green
}
HiRes.pixelsRGBA[colorAddr + 1] = color_green
HiRes.pixelsSRGB[colorAddr + 1] = color_green
case 0x03: // white 1
// if ( colorAddr >= 2 ) && ( HiRes.pixelsRGBA[colorAddr - 2] != color_black ) {
// HiRes.pixelsRGBA[colorAddr - 1] = HiRes.pixelsRGBA[colorAddr - 2]
// if ( colorAddr >= 2 ) && ( HiRes.pixelsSRGB[colorAddr - 2] != color_black ) {
// HiRes.pixelsSRGB[colorAddr - 1] = HiRes.pixelsSRGB[colorAddr - 2]
// }
// if (colorAddr >= 1) {
// HiRes.pixelsRGBA[colorAddr - 1] = color_white
// HiRes.pixelsSRGB[colorAddr - 1] = color_white
// }
HiRes.pixelsRGBA[colorAddr] = color_white
HiRes.pixelsRGBA[colorAddr + 1] = color_white
HiRes.pixelsSRGB[colorAddr] = color_white
HiRes.pixelsSRGB[colorAddr + 1] = color_white
case 0x05: // blue
HiRes.pixelsRGBA[colorAddr] = color_blue
HiRes.pixelsSRGB[colorAddr] = color_blue
if (colorAddr >= 1) && (prev != 0x00) && (prev != 0x04) {
HiRes.pixelsRGBA[colorAddr - 1] = color_blue
HiRes.pixelsSRGB[colorAddr - 1] = color_blue
}
case 0x06: // orange
// reducing color bleeding
if (colorAddr > 0) && (HiRes.pixelsRGBA[colorAddr - 1] != color_black) {
HiRes.pixelsRGBA[colorAddr] = color_orange
if (colorAddr > 0) && (HiRes.pixelsSRGB[colorAddr - 1] != color_black) {
HiRes.pixelsSRGB[colorAddr] = color_orange
}
HiRes.pixelsRGBA[colorAddr + 1] = color_orange
HiRes.pixelsSRGB[colorAddr + 1] = color_orange
case 0x07: // white 2
// if ( colorAddr >= 1 ) {
// HiRes.pixelsRGBA[colorAddr - 1] = color_yellow
// HiRes.pixelsSRGB[colorAddr - 1] = color_yellow
// }
HiRes.pixelsRGBA[colorAddr] = color_white
HiRes.pixelsRGBA[colorAddr + 1] = color_white
HiRes.pixelsSRGB[colorAddr] = color_white
HiRes.pixelsSRGB[colorAddr + 1] = color_white
default: // 0x00 (black 1), 0x04 (black 2)
HiRes.pixelsRGBA[colorAddr] = color_black
HiRes.pixelsRGBA[colorAddr + 1] = color_black
HiRes.pixelsSRGB[colorAddr] = color_black
HiRes.pixelsSRGB[colorAddr + 1] = color_black
break
}
// white adjustment
if ( (prev & 2) == 2 ) && ( (pixel & 1) == 1 ) {
HiRes.pixelsRGBA[colorAddr] = color_white
HiRes.pixelsSRGB[colorAddr] = color_white
if (colorAddr >= 1) {
HiRes.pixelsRGBA[colorAddr - 1] = color_white
HiRes.pixelsSRGB[colorAddr - 1] = color_white
}
// TODO: Need better check if extra green was created
if (colorAddr >= 2) && (HiRes.pixelsRGBA[colorAddr - 2] == color_green ) {
if (colorAddr < 3) || (HiRes.pixelsRGBA[colorAddr - 3] != color_green) {
HiRes.pixelsRGBA[colorAddr - 2] = color_black
if (colorAddr >= 2) && (HiRes.pixelsSRGB[colorAddr - 2] == color_green ) {
if (colorAddr < 3) || (HiRes.pixelsSRGB[colorAddr - 3] != color_green) {
HiRes.pixelsSRGB[colorAddr - 2] = color_black
}
}
}
// // green adjustment -- followed by white
// if (colorAddr >= 1) && (prev == 0x03) && (HiRes.pixelsRGBA[colorAddr - 1] = color_green) {
// HiRes.pixelsRGBA[colorAddr - 1] = color_green
// if (colorAddr >= 1) && (prev == 0x03) && (HiRes.pixelsSRGB[colorAddr - 1] = color_green) {
// HiRes.pixelsSRGB[colorAddr - 1] = color_green
// }
// purple adjustment -- followed by white
@ -574,8 +583,8 @@ class HiRes: NSView {
(pixel == 0x03) || (pixel == 0x07) // white
) {
// was the previous purple pixel promoted to white or is it still purple?
if (colorAddr >= 2) && ( HiRes.pixelsRGBA[colorAddr - 2] == color_purple ) {
HiRes.pixelsRGBA[colorAddr - 1] = color_purple
if (colorAddr >= 2) && ( HiRes.pixelsSRGB[colorAddr - 2] == color_purple ) {
HiRes.pixelsSRGB[colorAddr - 1] = color_purple
}
}
@ -584,7 +593,7 @@ class HiRes: NSView {
(pixel == 0x05) ||
(pixel == 0x03) || (pixel == 0x07) // white
) {
HiRes.pixelsRGBA[colorAddr - 1] = color_blue
HiRes.pixelsSRGB[colorAddr - 1] = color_blue
}
}
@ -700,8 +709,8 @@ class HiRes: NSView {
// refresh the entire screen
let boundingBox = CGRect(x: 0, y: 0, width: frame.width, height: frame.height)
// currentContext?.interpolationQuality = .none
currentContext?.interpolationQuality = .high
currentContext?.interpolationQuality = .none
// currentContext?.interpolationQuality = .high // TODO: Make a switch that lets you turn on and off "old monitor effects"
currentContext?.draw(image, in: boundingBox)
}

View File

@ -210,7 +210,8 @@ class LoRes: NSView {
let byteCount = (bytesPerRow * pixelsHigh)
// guard let colorSpace = CGColorSpace(name: CGColorSpace.linearSRGB) else { return nil }
guard let colorSpace = CGColorSpace(name: CGColorSpace.genericRGBLinear) else { return nil }
// guard let colorSpace = CGColorSpace(name: CGColorSpace.genericRGBLinear) else { return nil }
guard let colorSpace = CGColorSpace(name: CGColorSpace.sRGB) else { return nil }
let pixels = UnsafeMutablePointer<CUnsignedChar>.allocate(capacity: byteCount)
@ -245,7 +246,7 @@ class LoRes: 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 pixelsRGBA = pixels.bindMemory(to: UInt32.self)
static var pixelsSRGB = pixels.bindMemory(to: UInt32.self)
let R = 2
let G = 1
@ -258,22 +259,40 @@ class LoRes: NSView {
var was = 0;
// static let color_black : UInt32 = 0x00000000; // 0
// static let color_magenta : UInt32 = 0xFF660022; // 1
// static let color_dark_blue : UInt32 = 0xFF000077; // 2
// static let color_purple : UInt32 = 0xFF9908DD; // 3
// static let color_dark_green : UInt32 = 0xFF005500; // 4
// static let color_dark_gray : UInt32 = 0xFF333333; // 5
// static let color_medium_blue : UInt32 = 0xFF0011BB; // 6
// static let color_light_blue : UInt32 = 0xFF4488FF; // 7
// static let color_brown : UInt32 = 0xFF552200; // 8
// static let color_orange : UInt32 = 0xFFFF6611; // 9
// static let color_gray : UInt32 = 0xFF888888; // 10
// static let color_pink : UInt32 = 0xFFFF8888; // 11
// static let color_green : UInt32 = 0xFF0BBB11; // 12
// static let color_yellow : UInt32 = 0xFFFFFF00; // 13
// static let color_aqua : UInt32 = 0xFF66CC99; // 14
// static let color_white : UInt32 = 0xFFEEEEEE; // 15
static let color_black : UInt32 = 0x00000000; // 0
static let color_magenta : UInt32 = 0xFF660022; // 1
static let color_dark_blue : UInt32 = 0xFF000077; // 2
static let color_purple : UInt32 = 0xFF9908DD; // 3
static let color_dark_green : UInt32 = 0xFF005500; // 4
static let color_dark_gray : UInt32 = 0xFF333333; // 5
static let color_medium_blue : UInt32 = 0xFF0011BB; // 6
static let color_light_blue : UInt32 = 0xFF4488FF; // 7
static let color_brown : UInt32 = 0xFF552200; // 8
static let color_orange : UInt32 = 0xFFFF6611; // 9
static let color_magenta : UInt32 = 0xFFDD0077; // 1
static let color_dark_blue : UInt32 = 0xFF0006F6; // 2
static let color_purple : UInt32 = 0xFFCC00FF; // 3
static let color_dark_green : UInt32 = 0xFF009800; // 4
static let color_dark_gray : UInt32 = 0xFF888888; // 5 // Darker only on //gs
static let color_medium_blue : UInt32 = 0xFF006FFD; // 6
static let color_light_blue : UInt32 = 0xFF5AA3F0; // 7
static let color_brown : UInt32 = 0xFF5C341F; // 8
static let color_orange : UInt32 = 0xFFFF6302; // 9
static let color_gray : UInt32 = 0xFF888888; // 10
static let color_pink : UInt32 = 0xFFFF8888; // 11
static let color_green : UInt32 = 0xFF0BBB11; // 12
static let color_yellow : UInt32 = 0xFFFFFF00; // 13
static let color_aqua : UInt32 = 0xFF66CC99; // 14
static let color_pink : UInt32 = 0xFFFF50B9; // 11
static let color_green : UInt32 = 0xFF2BD84A; // 12
static let color_yellow : UInt32 = 0xFFFFE700; // 13
static let color_aqua : UInt32 = 0xFF71EED6; // 14
static let color_white : UInt32 = 0xFFEEEEEE; // 15
let colorTable = [
color_black,
@ -300,7 +319,7 @@ class LoRes: NSView {
func colorPixel ( pixelAddr : Int, color : Int ) {
LoRes.pixelsRGBA[pixelAddr] = colorTable[color]
LoRes.pixelsSRGB[pixelAddr] = colorTable[color]
}

View File

@ -530,39 +530,17 @@ class ViewController: NSViewController {
var shadowTxt : String = ""
func Update() {
// clk_6502_per_frm_max = 0
clkCounter += Double(clkfrm)
// we start a new frame from here, so CPU is running even while rendering
clkfrm = 0
frameCounter += 1
if ( frameCounter % fps == 0 ) {
let currentTime = CACurrentMediaTime() as Double
let elpasedTime = currentTime - lastFrameTime
lastFrameTime = currentTime
mhz = Double( clkCounter ) / (elpasedTime * M);
clkCounter = 0
}
// render()
// hires.compute()
// HexDump()
// return
func Render() {
frameCnt += 1
if ( frameCnt == fpsHalf ) {
// flashingSpace = blockChar
// flashingSpace = blockChar
ViewController.charConvTbl = ViewController.charConvTblFlashOn
}
else if ( frameCnt >= fps ) {
// flashingSpace = spaceChar
// flashingSpace = spaceChar
ViewController.charConvTbl = ViewController.charConvTblFlashOff
frameCnt = 0
}
@ -572,10 +550,10 @@ class ViewController: NSViewController {
// 2. it is independent of the simulation, de that is running in the background thread while we are busy with rendering...
DispatchQueue.main.sync {
var txt : String = ""
var fromLines = 0
var toLines = self.textLines
if videoMode.text == 0 {
if videoMode.mixed == 1 {
fromLines = toLines - 4
@ -584,16 +562,16 @@ class ViewController: NSViewController {
toLines = 0
}
}
self.txtArr = self.txtClear
// render an empty space to eiminate displaying text portion of the screen covered by graphics
let charDisposition = videoMode.col80 == 0 ? 1 : 2
for y in 0 ..< fromLines {
self.txtArr[ y * (self.textCols * charDisposition + self.lineEndChars) + self.textCols * charDisposition] = "\n"
}
// 40 col
if videoMode.col80 == 0 {
if MEMcfg.txt_page_2 == 0 {
@ -615,7 +593,7 @@ class ViewController: NSViewController {
self.txtArr[ y * (self.textCols + self.lineEndChars) + self.textCols ] = "\n"
}
}
// 80 col
// 80 col
else {
let auxPage = ( MEMcfg.is_80STORE == 1 ) && ( MEMcfg.txt_page_2 == 1 )
@ -641,13 +619,13 @@ class ViewController: NSViewController {
self.txtArr[ y * (self.textCols * 2 + self.lineEndChars) + self.textCols * 2] = "\n"
}
}
txt = String(self.txtArr)
// TODO: Render text Screen in native C
// txt = String(bytesNoCopy: ViewController.textScreen!, length: 10, encoding: .ascii, freeWhenDone: false) ?? "HMM"
// txt = String(bytesNoCopy: ViewController.textScreen!, length: 10, encoding: .ascii, freeWhenDone: false) ?? "HMM"
if videoMode.col80 != self.currentVideoMode.col80 {
self.currentVideoMode.col80 = videoMode.col80
@ -665,40 +643,40 @@ class ViewController: NSViewController {
self.shadowTxt = txt
self.display.stringValue = txt
}
// self.display.stringValue = "testing\nit\nout"
// self.display.stringValue = "testing\nit\nout"
if ( (mhz < 1.5) && (mhz != floor(mhz)) ) {
self.speedometer.stringValue = String(format: "%0.3lf MHz", mhz);
}
else {
self.speedometer.stringValue = String(format: "%0.1lf MHz", mhz);
}
// else {
// self.speedometer.stringValue = String(format: "%.0lf MHz", mhz);
// }
// else {
// self.speedometer.stringValue = String(format: "%.0lf MHz", mhz);
// }
#if HIRES
// only refresh graphics view when needed (aka not in text mode)
if ( videoMode.text == 0 ) {
if ( videoMode.hires == 0 ) {
// when we change video mode, buffer needs to be cleared to avoid artifacts
if ( self.savedVideoMode.text == 1 )
|| ( self.savedVideoMode.mixed != videoMode.mixed )
|| ( self.savedVideoMode.hires != videoMode.hires )
|| ( self.savedVideoMode.mixed != videoMode.mixed )
|| ( self.savedVideoMode.hires != videoMode.hires )
{
self.lores.clearScreen()
self.lores.isHidden = false
self.hires.isHidden = true
}
self.lores.Update()
}
else {
// when we change video mode, buffer needs to be cleared to avoid artifacts
if ( self.savedVideoMode.text == 1 )
|| ( self.savedVideoMode.mixed != videoMode.mixed )
|| ( self.savedVideoMode.hires != videoMode.hires )
|| ( self.savedVideoMode.mixed != videoMode.mixed )
|| ( self.savedVideoMode.hires != videoMode.hires )
{
self.hires.clearScreen()
self.hires.isHidden = false
@ -713,15 +691,15 @@ class ViewController: NSViewController {
self.lores.isHidden = true
self.hires.isHidden = true
}
self.savedVideoMode = videoMode
#endif
// stream speaker from a separate thread from the simulation
// TODO: Do we need to do this from here?
// spkr_update()
// spkr_update()
// Mouse 2 JoyStick (Game Controller / Paddle)
mouseLocation = view.window!.mouseLocationOutsideOfEventStream
@ -745,6 +723,28 @@ class ViewController: NSViewController {
pdl_diffarr[3] = pdl_valarr[3] - pdl_prevarr[3]
}
}
}
func Update() {
clkCounter += Double(clkfrm)
// we start a new frame from here, so CPU is running even while rendering
clkfrm = 0
frameCounter += 1
if ( frameCounter % fps == 0 ) {
let currentTime = CACurrentMediaTime() as Double
let elpasedTime = currentTime - lastFrameTime
lastFrameTime = currentTime
mhz = Double( clkCounter ) / (elpasedTime * M);
clkCounter = 0
}
// if ( frameCounter % 5 == 0 ) {
Render()
// }
#if SPEEDTEST

View File

@ -69,7 +69,7 @@ ALuint spkr_buffers[BUFFER_COUNT];
const int spkr_fps = fps;
const int spkr_seconds = 1;
const unsigned spkr_sample_rate = 44100;
unsigned spkr_extra_buf = 800 / fps;
unsigned spkr_extra_buf = 800 / spkr_fps;
const unsigned spkr_buf_size = spkr_seconds * spkr_sample_rate * 2 / spkr_fps;
int16_t spkr_samples [ spkr_buf_size * spkr_fps * BUFFER_COUNT * 2]; // stereo
unsigned spkr_sample_idx = 0;