- Removed some unused code

- Color / Mono selector
- Mono HiRes
This commit is contained in:
tudnai 2020-06-20 18:46:26 -07:00
parent c467b8223c
commit ac36139d0d
4 changed files with 123 additions and 627 deletions

View File

@ -1414,7 +1414,7 @@
"-D_NO_INTERRUPT_CHECK_PER_STEP",
"-D_NO_CLK_ABSOLUTE_PRECISE",
);
OTHER_SWIFT_FLAGS = "-DHIRES -DMETAL_NO -DHIRESDRAW -D_NO_HIRESLOW -DHIRESLOWCOLOR";
OTHER_SWIFT_FLAGS = "-DHIRES -D_NO_METAL -D_NO_HIRESDRAW -DHIRESLOW -DHIRESLOWCOLOR";
PRODUCT_BUNDLE_IDENTIFIER = com.gamealloy.A2Mac;
PRODUCT_NAME = "$(TARGET_NAME)";
SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG;
@ -1451,7 +1451,7 @@
"-D_NO_INTERRUPT_CHECK_PER_STEP",
"-D_NO_CLK_ABSOLUTE_PRECISE",
);
OTHER_SWIFT_FLAGS = "-DHIRES -DMETAL_NO -DHIRESDRAW -D_NO_HIRESLOW -DHIRESLOWCOLOR";
OTHER_SWIFT_FLAGS = "-DHIRES -D_NO_METAL -D_NO_HIRESDRAW -DHIRESLOW -DHIRESLOWCOLOR";
PRODUCT_BUNDLE_IDENTIFIER = com.gamealloy.A2Mac;
PRODUCT_NAME = "$(TARGET_NAME)";
SWIFT_OBJC_BRIDGING_HEADER = "A2Mac/A2Mac-Bridging-Header.h";

View File

@ -1388,13 +1388,13 @@
</customSpacing>
</stackView>
<stackView distribution="fill" orientation="vertical" alignment="leading" horizontalStackHuggingPriority="249.99998474121094" verticalStackHuggingPriority="249.99998474121094" detachesHiddenViews="YES" translatesAutoresizingMaskIntoConstraints="NO" id="lVP-FP-u6x" userLabel="CPU Speed Selection">
<rect key="frame" x="8" y="8" width="104" height="500"/>
<rect key="frame" x="8" y="8" width="104" height="522"/>
<subviews>
<box verticalHuggingPriority="750" boxType="separator" translatesAutoresizingMaskIntoConstraints="NO" id="7yw-J0-Fmj">
<rect key="frame" x="0.0" y="497" width="96" height="5"/>
<rect key="frame" x="0.0" y="519" width="96" height="5"/>
</box>
<button verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="isd-yh-gCV">
<rect key="frame" x="-2" y="475" width="98" height="18"/>
<rect key="frame" x="-2" y="497" width="98" height="18"/>
<buttonCell key="cell" type="check" title="CRT Monitor" bezelStyle="regularSquare" imagePosition="left" inset="2" id="UQ8-Nn-Kt7">
<behavior key="behavior" changeContents="YES" doesNotDimImage="YES" lightByContents="YES"/>
<font key="font" metaFont="system"/>
@ -1403,6 +1403,16 @@
<action selector="CRTMonitorOnOff:" target="XfG-lQ-9wD" id="2V4-GI-erE"/>
</connections>
</button>
<button verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="WzH-g6-yxF">
<rect key="frame" x="-2" y="475" width="105" height="18"/>
<buttonCell key="cell" type="check" title="Color Monitor" bezelStyle="regularSquare" imagePosition="left" state="on" inset="2" id="jLh-hF-6Z2">
<behavior key="behavior" changeContents="YES" doesNotDimImage="YES" lightByContents="YES"/>
<font key="font" metaFont="system"/>
</buttonCell>
<connections>
<action selector="ColorMonitorOnOff:" target="XfG-lQ-9wD" id="Aea-ZM-p6Q"/>
</connections>
</button>
<box verticalHuggingPriority="750" boxType="separator" translatesAutoresizingMaskIntoConstraints="NO" id="t35-xh-L18">
<rect key="frame" x="0.0" y="466" width="96" height="5"/>
</box>
@ -1463,7 +1473,7 @@
<rect key="frame" x="0.0" y="338" width="96" height="5"/>
</box>
<splitView hidden="YES" dividerStyle="thin" vertical="YES" translatesAutoresizingMaskIntoConstraints="NO" id="Ge3-qD-JO6">
<rect key="frame" x="0.0" y="477" width="104" height="23"/>
<rect key="frame" x="0.0" y="499" width="104" height="23"/>
<subviews>
<textField verticalHuggingPriority="750" fixedFrame="YES" id="SNE-lV-JXn" userLabel="SoundGap">
<rect key="frame" x="0.0" y="0.0" width="90" height="23"/>
@ -1666,6 +1676,7 @@
<integer value="1000"/>
<integer value="1000"/>
<integer value="1000"/>
<integer value="1000"/>
</visibilityPriorities>
<customSpacing>
<real value="3.4028234663852886e+38"/>
@ -1695,6 +1706,7 @@
<real value="3.4028234663852886e+38"/>
<real value="3.4028234663852886e+38"/>
<real value="3.4028234663852886e+38"/>
<real value="3.4028234663852886e+38"/>
</customSpacing>
</stackView>
</subviews>

View File

@ -31,26 +31,6 @@ class HiRes: NSView {
let HiResRawPointer = UnsafeRawPointer(RAM + Page1Addr)
#if METAL_YES
var device: MTLDevice!
var metalLayer: CAMetalLayer!
var vertexBuffer: MTLBuffer!
var renderPipelineState: MTLRenderPipelineState!
var computePipelineState: MTLComputePipelineState!
var commandQueue: MTLCommandQueue!
// var timer: CADisplayLink! // iOS only!
var timer: CVDisplayLink! // MacOS only!
var defaultLibrary : MTLLibrary!
var addFunction : MTLFunction!
var mtlBufferA : MTLBuffer!
var mtlBufferB : MTLBuffer!
var mtlBufferC : MTLBuffer!
let vertexData: [Float] = [
0.0, 1.0, 0.0, -1.0, -1.0, 0.0, 1.0, -1.0, 0.0
]
#endif // METAL_YES
// holds the starting addresses for each lines minus the screen page starting address
var HiResLineAddrTbl = [Int](repeating: 0, count: PixelHeight)
@ -66,56 +46,6 @@ class HiRes: NSView {
}
}
#if METAL_YES
func initMetal() {
device = MTLCreateSystemDefaultDevice()
metalLayer = CAMetalLayer() // 1
metalLayer.device = device // 2
metalLayer.pixelFormat = .bgra8Unorm // 3
metalLayer.framebufferOnly = true // 4
metalLayer.frame = frame // 5
// hires.layer = metalLayer // 6
// let dataSize = vertexData.count * MemoryLayout.size(ofValue: vertexData[0]) // 1
// vertexBuffer = device.makeBuffer(bytes: vertexData, length: dataSize, options: []) // 2
// 1
defaultLibrary = device.makeDefaultLibrary()!
addFunction = defaultLibrary.makeFunction(name: "add_arrays")
computePipelineState = try! device.makeComputePipelineState(function: addFunction)
// let fragmentProgram = defaultLibrary.makeFunction(name: "basic_fragment")
// let vertexProgram = defaultLibrary.makeFunction(name: "basic_vertex")
// 2
// let pipelineState
// let pipelineStateDescriptor = MTLRenderPipelineDescriptor()
// pipelineStateDescriptor.vertexFunction = vertexProgram
// pipelineStateDescriptor.fragmentFunction = fragmentProgram
// pipelineStateDescriptor.colorAttachments[0].pixelFormat = .bgra8Unorm
// 3
// pipelineState = try! device.makeRenderPipelineState(descriptor: pipelineStateDescriptor)
commandQueue = device.makeCommandQueue()
mtlBufferA = device.makeBuffer(bytes: HiResRawPointer, length: HiRes.PageSize, options: .storageModeShared)
mtlBufferB = device.makeBuffer(bytes: HiResRawPointer, length: HiRes.PageSize, options: .storageModeShared)
mtlBufferC = device.makeBuffer(length: HiRes.PageSize * 4, options: .storageModeShared)
var displayLink : CVDisplayLink!
let displayID = CGMainDisplayID()
let error = CVDisplayLinkCreateWithCGDisplay(displayID, &displayLink)
// timer = CVDisplayLink( (target: self, selector: #selector(gameloop))
// timer.add(to: RunLoop.main, forMode: .default)
// CVDisplayLinkSetOutputCallback(displayLink!, renderCallback as? CVDisplayLinkOutputCallback, UnsafeMutableRawPointer( Unmanaged.passUnretained(self).toOpaque() ))
// CVDisplayLinkStart(displayLink!)
}
#endif // METAL_YES
var HiResSubView = [[NSView]]()
@ -155,188 +85,13 @@ class HiRes: NSView {
// create smaller box views for draw optimization
createHiRes()
#if METAL_YES
initMetal()
#endif
}
override init(frame: CGRect) {
super.init(frame: frame)
}
#if METAL_YES
func compute() {
let commandBuffer = commandQueue.makeCommandBuffer()!
let computeEncoder = commandBuffer.makeComputeCommandEncoder()
computeEncoder?.setComputePipelineState(computePipelineState)
computeEncoder?.setBuffer(mtlBufferA, offset: 0, index: 0)
computeEncoder?.setBuffer(mtlBufferA, offset: 0, index: 1)
computeEncoder?.setBuffer(mtlBufferC, offset: 0, index: 2)
let gridSize = MTLSizeMake(HiRes.PageSize, 1, 1)
let threadGroupSize = min( computePipelineState.maxTotalThreadsPerThreadgroup, HiRes.PageSize )
let threadgroupSize = MTLSizeMake(threadGroupSize, 1, 1)
// Encode the Compute Command to Execute the Threads
computeEncoder?.dispatchThreadgroups(gridSize, threadsPerThreadgroup: threadgroupSize)
// no more compute passes
computeEncoder?.endEncoding()
// Commit the Command Buffer to Execute Its Commands
commandBuffer.commit()
// Wait for the Calculation to Complete
commandBuffer.waitUntilCompleted()
// Alternatively, to be notified when Metal has processed all of the commands,
// add a completion handler to the command buffer (addCompletedHandler(_:)),
// or check the status of a command buffer by reading its status property
let result = UnsafeRawBufferPointer(start: mtlBufferC.contents(), count: HiRes.PageSize)
}
func render() {
guard let drawable = metalLayer?.nextDrawable() else { return }
let renderPassDescriptor = MTLRenderPassDescriptor()
renderPassDescriptor.colorAttachments[0].texture = drawable.texture
renderPassDescriptor.colorAttachments[0].loadAction = .clear
renderPassDescriptor.colorAttachments[0].clearColor = MTLClearColor(
red: 0.0,
green: 104.0/255.0,
blue: 55.0/255.0,
alpha: 1.0)
let commandBuffer = commandQueue.makeCommandBuffer()!
let renderEncoder = commandBuffer.makeRenderCommandEncoder(descriptor: renderPassDescriptor)!
renderEncoder.setRenderPipelineState(renderPipelineState)
renderEncoder.setVertexBuffer(vertexBuffer, offset: 0, index: 0)
renderEncoder.drawPrimitives(type: .triangle, vertexStart: 0, vertexCount: 3, instanceCount: 1)
renderEncoder.endEncoding()
// committing buffer
commandBuffer.present(drawable)
commandBuffer.commit()
}
#endif // METAL_YES
// @objc func gameloop() {
// autoreleasepool {
// self.render()
// }
// }
func renderCallback(displayLink : CVDisplayLink,
const inNow : UnsafePointer<CVTimeStamp>,
const inOutputTime : UnsafePointer<CVTimeStamp>,
flagsIn : CVOptionFlags,
flagsOut : UnsafeMutablePointer<CVOptionFlags>,
displayLinkContext : UnsafeMutableRawPointer) -> CVReturn
{
/* It's prudent to also have a brief discussion about the CVTimeStamp.
CVTimeStamp has five properties. Three of the five are very useful
for keeping track of the current time, calculating delta time, the
frame number, and the number of frames per second. The utility of
each property is not terribly obvious from just reading the names
or the descriptions in the Developer dcumentation and has been a
mystery to many a developer. Thankfully, CaptainRedmuff on
StackOverflow asked a question that provided the equation that
calculates frames per second. From that equation, we can
extrapolate the value of each field.
@hostTime = current time in Units of the "root". Yeah, I don't know.
The key to this field is to understand that it is in nanoseconds
(e.g. 1/1_000_000_000 of a second) not units. To convert it to
seconds divide by 1_000_000_000. Dividing by videoRefreshPeriod
and videoTimeScale in a calculation for frames per second yields
the appropriate number of frames. This works as a result of
proportionality--dividing seconds by seconds. Note that dividing
by videoTimeScale to get the time in seconds does not work like it
does for videoTime.
framesPerSecond:
(videoTime / videoRefreshPeriod) / (videoTime / videoTimeScale) = 59
and
(hostTime / videoRefreshPeriod) / (hostTime / videoTimeScale) = 59
but
hostTime * videoTimeScale seconds, but Units = seconds * (Units / seconds) = Units
@rateScalar = ratio of "rate of device in CVTimeStamp/unitOfTime" to
the "Nominal Rate". I think the "Nominal Rate" is
videoRefreshPeriod, but unfortunately, the documentation doesn't
just say videoRefreshPeriod is the Nominal rate and then define
what that means. Regardless, because this is a ratio, and the fact
that we know the value of one of the parts (e.g. Units/frame), we
then know that the "rate of the device" is frame/Units (the units of
measure need to cancel out for the ratio to be a ratio). This
makes sense in that rateScalar's definition tells us the rate is
"measured by timeStamps". Since there is a frame for every
timeStamp, the rate of the device equals CVTimeStamp/Unit or
frame/Unit. Thus,
rateScalar = frame/Units : Units/frame
@videoTime = the time the frame was created since computer started up.
If you turn your computer off and then turn it back on, this timer
returns to zero. The timer is paused when you put your computer to
sleep. This value is in Units not seconds. To get the number of
seconds this value represents, you have to apply videoTimeScale.
@videoRefreshPeriod = the number of Units per frame (i.e. Units/frame)
This is useful in calculating the frame number or frames per second.
The documentation calls this the "nominal update period" and I am
pretty sure that is quivalent to the aforementioned "nominal rate".
Unfortunately, the documetation mixes naming conventions and this
inconsistency creates confusion.
frame = videoTime / videoRefreshPeriod
@videoTimeScale = Units/second, used to convert videoTime into seconds
and may also be used with videoRefreshPeriod to calculate the expected
framesPerSecond. I say expected, because videoTimeScale and
videoRefreshPeriod don't change while videoTime does change. Thus,
to calculate fps in the case of system slow down, one would need to
use videoTime with videoTimeScale to calculate the actual fps value.
seconds = videoTime / videoTimeScale
framesPerSecondConstant = videoTimeScale / videoRefreshPeriod (this value does not change if their is system slowdown)
USE CASE 1: Time in DD:HH:mm:ss using hostTime
let rootTotalSeconds = inNow.pointee.hostTime
let rootDays = inNow.pointee.hostTime / (1_000_000_000 * 60 * 60 * 24) % 365
let rootHours = inNow.pointee.hostTime / (1_000_000_000 * 60 * 60) % 24
let rootMinutes = inNow.pointee.hostTime / (1_000_000_000 * 60) % 60
let rootSeconds = inNow.pointee.hostTime / 1_000_000_000 % 60
Swift.print("rootTotalSeconds: \(rootTotalSeconds) rootDays: \(rootDays) rootHours: \(rootHours) rootMinutes: \(rootMinutes) rootSeconds: \(rootSeconds)")
USE CASE 2: Time in DD:HH:mm:ss using videoTime
let totalSeconds = inNow.pointee.videoTime / Int64(inNow.pointee.videoTimeScale)
let days = (totalSeconds / (60 * 60 * 24)) % 365
let hours = (totalSeconds / (60 * 60)) % 24
let minutes = (totalSeconds / 60) % 60
let seconds = totalSeconds % 60
Swift.print("totalSeconds: \(totalSeconds) Days: \(days) Hours: \(hours) Minutes: \(minutes) Seconds: \(seconds)")
Swift.print("fps: \(Double(inNow.pointee.videoTimeScale) / Double(inNow.pointee.videoRefreshPeriod)) seconds: \(Double(inNow.pointee.videoTime) / Double(inNow.pointee.videoTimeScale))")
*/
/* The displayLinkContext in CVDisplayLinkOutputCallback's parameter list is the
view being driven by the CVDisplayLink. In order to use the context as an
instance of SwiftOpenGLView (which has our drawView() method) we need to use
unsafeBitCast() to cast this context to a SwiftOpenGLView.
*/
// let view = unsafeBitCast(displayLinkContext, to: SwiftOpenGLView.self)
// // Capture the current time in the currentTime property.
// view.currentTime = inNow.pointee.videoTime / Int64(inNow.pointee.videoTimeScale)
// view.drawView()
// self.render()
return kCVReturnSuccess
}
static func createBitmapContext(pixelsWide: Int, _ pixelsHigh: Int) -> CGContext? {
let bytesPerPixel = 4
let bytesPerRow = bytesPerPixel * pixelsWide
@ -363,26 +118,6 @@ class HiRes: NSView {
return context
}
// override func draw(_ rect: CGRect) {
// let width = 200
// let height = 300
// let boundingBox = CGRect(x: 0, y: 0, width: CGFloat(width), height: CGFloat(height))
// let context = createBitmapContext(pixelsWide: width, height)
//
// let data = context?.data
// var currentPixel: [UInt32] = unsafeBitCast(data, to: [UInt32].self)
//
// var n = 0
// for _ in 0..<height {
// for _ in 0..<width {
// currentPixel[n] = 0
// n += 1
// }
// }
//
// guard let image = context?.makeImage() else { return }
// context?.draw(image, in: boundingBox)
// }
private var currentContext : CGContext? {
get {
@ -397,99 +132,29 @@ class HiRes: NSView {
}
}
#if HIRESLOW || HIRESLOWCOLOR
static let ScreenBitmapSize = (PixelWidth * PixelHeight * 4)
static let context = createBitmapContext(pixelsWide: PixelWidth, PixelHeight)
static let pixels = UnsafeMutableRawBufferPointer(start: context?.data, count: ScreenBitmapSize)
static var pixelsSRGB = pixels.bindMemory(to: UInt32.self)
#endif
let R = 2
let G = 1
let B = 0
let A = 3
var blockChanged = [Bool](repeating: false, count: HiRes.blockRows * HiRes.blockCols / 2)
var blockChanged = [Bool](repeating: false, count: HiRes.blockRows * HiRes.blockCols)
var shadowScreen = [Int](repeating: 0, count: PageSize)
var was = 0;
#if HIRESLOW
override func draw(_ rect: CGRect) {
// print("HIRESSLOW\n")
// if was > 100 {
// return
// }
// was += 1
var pixelAddr = 0
var minX = 9999
var minY = 9999
var maxX = 0
var maxY = 0
var x = 0
var y = 0
for lineAddr in HiResLineAddrTbl {
for blockAddr in 0..<HiRes.blockCols {
let block = Int(HiResBufferPointer[ Int(lineAddr + blockAddr) ])
let screenIdx = y * HiRes.blockCols + x
if ( shadowScreen[ screenIdx ] != block ) {
shadowScreen[ screenIdx ] = block
for bit in stride(from: 0, through: 6, by: 1) {
let bitMask = 1 << bit
if (block & bitMask) == 0 {
HiRes.pixels[pixelAddr + R] = 0x00;
HiRes.pixels[pixelAddr + G] = 0x00;
HiRes.pixels[pixelAddr + B] = 0x00;
HiRes.pixels[pixelAddr + A] = 0x00;
}
else { // 28CD41
HiRes.pixels[pixelAddr + R] = 0x08;
HiRes.pixels[pixelAddr + G] = 0xA2;
HiRes.pixels[pixelAddr + B] = 0x12;
HiRes.pixels[pixelAddr + A] = 0xFF;
}
if ( minX > x ) { minX = x }
if ( minY > y ) { minY = y }
if ( maxX < x ) { maxX = x }
if ( maxY < y ) { maxY = y }
pixelAddr += 4
x += 1
}
}
else {
pixelAddr += 4 * 7
x += 7
}
}
y += 1
x = 0
}
guard let image = HiRes.context?.makeImage() else { return }
let boundingBox = CGRect(x: 0, y: 0, width: CGFloat(HiRes.PixelWidth), height: CGFloat(HiRes.PixelHeight))
currentContext!.draw (image, in: boundingBox)
}
#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;
// 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 = 0xFFEEEEEE;
@ -497,57 +162,117 @@ class HiRes: NSView {
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;
func refreshChanged( blockSize : Int ) {
// refresh changed block only
let screenBlockMargin = 12 / blockSize
let blockScreenWidth = Int(frame.width) / HiRes.blockCols * blockSize
let blockScreenHeigth = Int(frame.height) / HiRes.blockRows
for blockVertIdx in 0 ..< HiRes.blockRows {
for blockHorIdx in 0 ..< HiRes.blockCols / blockSize {
if blockChanged[ blockVertIdx * HiRes.blockCols / blockSize + blockHorIdx ] {
// refresh the entire screen
let boundingBox = CGRect(
x: blockHorIdx * blockScreenWidth - screenBlockMargin,
y: Int(frame.height) - blockVertIdx * blockScreenHeigth - blockScreenHeigth - screenBlockMargin,
width: blockScreenWidth + screenBlockMargin * blockSize,
height: blockScreenHeigth + screenBlockMargin * blockSize)
self.setNeedsDisplay( boundingBox )
}
}
}
}
func UpdateMono() {
blockChanged = [Bool](repeating: false, count: HiRes.blockRows * HiRes.blockCols)
var pixelAddr = 0
var y = 0
for lineAddr in HiResLineAddrTbl {
let blockVertIdx = y / HiRes.blockHeight * HiRes.blockCols
for blockHorIdx in 0..<HiRes.blockCols {
let block = Int(HiResBufferPointer[ Int(lineAddr + blockHorIdx) ])
let screenIdx = y * HiRes.blockCols + blockHorIdx
// get all changed blocks
blockChanged[ blockVertIdx + blockHorIdx ] = blockChanged[ blockVertIdx + blockHorIdx ] || shadowScreen[ screenIdx ] != block
shadowScreen[ screenIdx ] = block
for bit in stride(from: 0, through: 6, by: 1) {
let bitMask = 1 << bit
if (block & bitMask) != 0 {
HiRes.pixelsSRGB[pixelAddr] = color_green;
}
else {
HiRes.pixelsSRGB[pixelAddr] = color_black;
}
pixelAddr += 1
}
}
y += 1
}
refreshChanged(blockSize: 1)
}
func colorPixel ( pixelAddr : Int, pixel : Int, prev : Int ) {
let colorAddr = pixelAddr / 4
switch ( pixel ) {
case 0x01: // purple (bits are in reverse!)
case 1: // purple (bits are in reverse!)
HiRes.pixelsSRGB[colorAddr] = color_purple;
// HiRes.pixelsSRGB[colorAddr + 1] = color_purple
if (colorAddr >= 1) && (prev != 0x03) && (prev != 0x07) && (prev != 0x00) && (prev != 0x04) {
HiRes.pixelsSRGB[colorAddr - 1] = color_purple
}
case 0x02: // green
case 2: // green
// reducing color bleeding
if (colorAddr > 0) && (HiRes.pixelsSRGB[colorAddr - 1] != color_black) {
HiRes.pixelsSRGB[colorAddr] = color_green
}
HiRes.pixelsSRGB[colorAddr + 1] = color_green
case 0x03: // white 1
case 3: // white 1
// if ( colorAddr >= 2 ) && ( HiRes.pixelsSRGB[colorAddr - 2] != color_black ) {
// HiRes.pixelsSRGB[colorAddr - 1] = HiRes.pixelsSRGB[colorAddr - 2]
// }
// if (colorAddr >= 1) {
// HiRes.pixelsSRGB[colorAddr - 1] = color_white
// HiRes.pixelsSRGB[colorAddr - 1] = color_yellow
// }
HiRes.pixelsSRGB[colorAddr] = color_white
HiRes.pixelsSRGB[colorAddr + 1] = color_white
case 0x05: // blue
case 5: // blue
HiRes.pixelsSRGB[colorAddr] = color_blue
if (colorAddr >= 1) && (prev != 0x00) && (prev != 0x04) {
HiRes.pixelsSRGB[colorAddr - 1] = color_blue
}
case 0x06: // orange
case 6: // orange
// reducing color bleeding
if (colorAddr > 0) && (HiRes.pixelsSRGB[colorAddr - 1] != color_black) {
HiRes.pixelsSRGB[colorAddr] = color_orange
}
HiRes.pixelsSRGB[colorAddr + 1] = color_orange
case 0x07: // white 2
// if ( colorAddr >= 1 ) {
// HiRes.pixelsSRGB[colorAddr - 1] = color_yellow
// }
case 7: // white 2
HiRes.pixelsSRGB[colorAddr] = color_white
HiRes.pixelsSRGB[colorAddr + 1] = color_white
@ -599,7 +324,7 @@ class HiRes: NSView {
}
func Update() {
func UpdateColor() {
var height = HiRes.PixelHeight
// do not even render it...
@ -623,7 +348,6 @@ class HiRes: NSView {
var y = 0
blockChanged = [Bool](repeating: false, count: HiRes.blockRows * HiRes.blockCols / 2)
HiRes.context?.clear( CGRect(x: 0, y: 0, width: frame.width, height: frame.height) )
for lineAddr in HiResLineAddrTbl {
@ -633,7 +357,7 @@ class HiRes: NSView {
}
height -= 1
let blockVertIdx = y / 8 * HiRes.blockCols / 2
let blockVertIdx = y / HiRes.blockHeight * HiRes.blockCols / 2
var prev = 0
for blockHorIdx in 0 ..< HiRes.blockCols / 2 {
@ -679,30 +403,26 @@ 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
for blockVertIdx in 0 ..< HiRes.blockRows {
for blockHorIdx in 0 ..< HiRes.blockCols / 2 {
if blockChanged[ blockVertIdx * HiRes.blockCols / 2 + blockHorIdx ] {
// refresh the entire screen
let boundingBox = CGRect(
x: blockHorIdx * blockScreenWidth - screenBlockMargin,
y: Int(frame.height) - blockVertIdx * blockScreenHeigth - blockScreenHeigth - screenBlockMargin,
width: blockScreenWidth + screenBlockMargin * 2,
height: blockScreenHeigth + screenBlockMargin * 2)
self.setNeedsDisplay( boundingBox )
}
}
}
refreshChanged(blockSize: 2)
// needsDisplay = true // refresh the entire screen
}
func Update() {
if ( ViewController.current?.ColorMonitor ?? true ) {
UpdateColor()
}
else {
UpdateMono()
}
}
func fullUpdate() {
needsDisplay = true
Update()
}
override func draw(_ rect: CGRect) {
guard let image = HiRes.context?.makeImage() else { return }
@ -719,249 +439,6 @@ class HiRes: NSView {
currentContext?.draw(image, in: boundingBox)
}
#elseif HIRESDRAWCOLOR
let colorPalette : [NSColor] = [
NSColor(calibratedRed: 0.0000, green: 0.000, blue: 0.000, alpha: 0.0), // black
NSColor(calibratedRed: 0.0314, green: 0.635, blue: 0.071, alpha: 1.0), // green
NSColor(calibratedRed: 0.0314, green: 0.635, blue: 0.071, alpha: 1.0), // purple
NSColor(calibratedRed: 1.0000, green: 1.000, blue: 1.000, alpha: 1.0), // white
NSColor(calibratedRed: 0.0000, green: 0.000, blue: 0.000, alpha: 0.0), // black
NSColor(calibratedRed: 0.0314, green: 0.635, blue: 0.071, alpha: 1.0), // orange
NSColor(calibratedRed: 0.0314, green: 0.635, blue: 0.071, alpha: 1.0), // blue
NSColor(calibratedRed: 1.0000, green: 1.000, blue: 1.000, alpha: 1.0), // white
]
let path = NSBezierPath()
override func draw(_ rect: CGRect) {
// NSColor.green.setFill()
NSColor(calibratedRed: 0.0314, green: 0.635, blue: 0.071, alpha: 1.0).setStroke()
path.removeAllPoints()
path.lineWidth = 0.7
path.move(to: NSPoint(x: 0, y: 0))
// path.appendRect(NSRect(x: 0, y: 0, width: 10, height: 10))
for y in 0 ..< HiRes.PixelHeight {
var color : UInt = 0
var lastColor : UInt = 0
path.move(to: NSPoint(x: 0, y: y))
// for color screen we need to process blocks in a pair
for blockX in 0 ..< HiRes.blockCols / 2 {
let lineAddr = HiResLineAddrTbl[y]
var x = blockX * HiRes.blockWidth * 2
var block0 = UInt(HiResBufferPointer[ Int(lineAddr + blockX * 2) + 0 ])
var block1 = UInt(HiResBufferPointer[ Int(lineAddr + blockX * 2) + 1 ])
let b70 : UInt = (block0 & 0x80) >> 5
let b71 : UInt = (block1 & 0x80) >> 5
var block7 : [UInt] = [0,0,0,0,0,0,0]
var i = 0
for _ in 0 ... 2 {
block7[i] = b70
block7[i] |= block0 & 3
block0 >>= 2
i += 1
}
block7[i] = b70
block7[i] |= ((block0 & 1) << 1) | (block1 & 1)
block1 >>= 1
i += 1
for _ in 0 ... 2 {
block7[i] = b71
block7[i] |= block1 & 3
block1 >>= 2
i += 1
}
for px in 0 ... 6 { // stride(from: 0, through: 6, by: 1) {
color = block7[px]
if (color != lastColor) {
colorPalette[Int(color)].setStroke()
path.line(to: NSPoint(x: x, y: y))
path.stroke()
path.removeAllPoints()
lastColor = color
}
x += 1
}
} // x
// make sure we close the path at the end of the horizontal line
if (color != lastColor) {
path.line(to: NSPoint(x: 279, y: y))
lastColor = color
}
}
// path.fill()
path.stroke()
}
#elseif HIRESDRAW
let path = NSBezierPath()
override func draw(_ rect: CGRect) {
let pixelWidth = bounds.width / CGFloat(HiRes.PixelWidth)
let pixelHeight = bounds.height / CGFloat(HiRes.PixelHeight)
// self.hidden = videoMode.text == 1
// NSColor.green.setFill()
// NSColor(calibratedRed: 0.0314, green: 0.635, blue: 0.071, alpha: 1.0).setStroke()
// NSColor(calibratedRed: 0.05, green: 0.7, blue: 0.1, alpha: 1.0).setStroke()
NSColor.systemGreen.setStroke()
path.removeAllPoints()
path.lineWidth = 0.7 * pixelHeight
path.move(to: NSPoint(x: 0, y: 0))
// path.appendRect(NSRect(x: 0, y: 0, width: 10, height: 10))
var height = HiRes.PixelHeight
// do not even render it...
if videoMode.text == 1 {
return
}
else {
if videoMode.mixed == 1 {
height = HiRes.MixedHeight
}
if videoMode.page == 1 {
HiResBufferPointer = HiResBuffer2
}
else {
HiResBufferPointer = HiResBuffer1
}
}
for y in 0 ..< height {
var inX = false
path.move(to: NSPoint(x: 0, y: y))
for blockX in 0 ..< HiRes.blockCols {
let lineAddr = HiResLineAddrTbl[y]
let block = UInt(HiResBufferPointer[ Int(lineAddr + blockX) ])
// if( shadowScreen[ screenIdx ] != block ) {
// shadowScreen[ screenIdx ] = block
//
var x = blockX * HiRes.blockWidth
if block != 0 && block != 0x80 {
for bit in 0 ... 6 { // stride(from: 0, through: 6, by: 1) {
let bitMask : UInt = 1 << bit
if (block & bitMask) == 0 {
if inX {
inX = false
path.line(to: NSPoint(x: CGFloat(x) * pixelWidth, y: CGFloat(192 - y) * pixelHeight ))
}
}
else { // 28CD41
if ( inX == false ) {
inX = true
path.move(to: NSPoint(x: CGFloat(x) * pixelWidth, y: CGFloat(192 - y) * pixelHeight ))
}
}
x += 1
}
}
else {
// make sure we close the path if the next block is completely zero
if inX {
inX = false
path.line(to: NSPoint(x: CGFloat(x) * pixelWidth, y: CGFloat(192 - y) * pixelHeight ))
}
}
} // x
// make sure we close the path at the end of the horizontal line
if inX {
inX = false
path.line(to: NSPoint(x: 279 * pixelWidth, y: CGFloat(192 - y) * pixelHeight ))
}
}
// path.fill()
path.stroke()
}
#elseif HIRES
override func draw(_ rect: CGRect) {
// print("HIRESBLOCKS\n")
// if was > 100 {
// return
// }
// was += 1
for blockY in 0 ..< HiRes.blockRows {
for blockX in 0 ..< HiRes.blockCols {
let blockView = HiResSubView[blockY][blockX]
let bitmapSize = HiRes.blockWidth * HiRes.blockHeight * 4
let context = HiRes.createBitmapContext(pixelsWide: HiRes.blockWidth, HiRes.blockHeight)
let pixels = UnsafeMutableRawBufferPointer(start: context?.data, count: bitmapSize) // UnsafeMutablePointer<CUnsignedChar>.allocate(capacity: byteCount)
var blockNeedsDisplay = false
for line in 0 ... 7 {
let y = blockY + line
let screenIdx = y * HiRes.blockCols + blockX
let pixelAddr = line
let lineAddr = HiResLineAddrTbl[y]
let block = Int(HiResBufferPointer[ Int(lineAddr + blockX) ])
if( shadowScreen[ screenIdx ] != block ) {
shadowScreen[ screenIdx ] = block
blockNeedsDisplay = true
var x = blockX * HiRes.blockWidth
for bit in 0 ... 6 { // stride(from: 0, through: 6, by: 1) {
let bitMask = 1 << bit
if (block & bitMask) == 0 {
pixels[pixelAddr + R] = 0x00;
pixels[pixelAddr + G] = 0x00;
pixels[pixelAddr + B] = 0x00;
pixels[pixelAddr + A] = 0x00;
}
else { // 28CD41
pixels[pixelAddr + R] = 0x08;
pixels[pixelAddr + G] = 0xA2;
pixels[pixelAddr + B] = 0x12;
pixels[pixelAddr + A] = 0x7F;
}
x += 1
}
}
}
if blockNeedsDisplay {
blockView.needsDisplay = true
// print("block(\(blockX),\(blockY))")
guard let image = context?.makeImage() else { return }
let boundingBox = CGRect(x: 0, y: 0, width: CGFloat(HiRes.PixelWidth), height: CGFloat(HiRes.PixelHeight))
currentContext!.draw(image, in: boundingBox)
}
}
}
}
#endif
}

View File

@ -55,6 +55,7 @@ class ViewController: NSViewController {
@IBOutlet weak var scanLines: NSImageView!
var CRTMonitor = false
var ColorMonitor = true
var Keyboard2Joystick = true
var Mouse2Joystick = false
var MouseInterface = true
@ -689,7 +690,7 @@ class ViewController: NSViewController {
self.lores.isHidden = true
}
self.hires.Update()
hires.Update()
}
}
else if ( self.savedVideoMode.text == 0 ) {
@ -982,6 +983,12 @@ class ViewController: NSViewController {
@IBAction func CRTMonitorOnOff(_ sender: NSButton) {
CRTMonitor = sender.state == .on
scanLines.isHidden = !CRTMonitor
hires.fullUpdate()
}
@IBAction func ColorMonitorOnOff(_ sender: NSButton) {
ColorMonitor = sender.state == .on
hires.fullUpdate()
}
@IBAction func Keyboard2JoystickOnOff(_ sender: NSButton) {