mirror of
https://github.com/trudnai/Steve2.git
synced 2025-01-02 18:32:37 +00:00
- Removed some unused code
- Color / Mono selector - Mono HiRes
This commit is contained in:
parent
c467b8223c
commit
ac36139d0d
@ -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";
|
||||
|
@ -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>
|
||||
|
@ -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,9 +85,6 @@ class HiRes: NSView {
|
||||
// create smaller box views for draw optimization
|
||||
createHiRes()
|
||||
|
||||
#if METAL_YES
|
||||
initMetal()
|
||||
#endif
|
||||
}
|
||||
|
||||
override init(frame: CGRect) {
|
||||
@ -165,178 +92,6 @@ class HiRes: NSView {
|
||||
}
|
||||
|
||||
|
||||
#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,98 +132,28 @@ 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;
|
||||
@ -503,51 +168,111 @@ class HiRes: NSView {
|
||||
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,31 +403,27 @@ 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
|
||||
|
||||
|
||||
}
|
||||
|
@ -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) {
|
||||
|
Loading…
Reference in New Issue
Block a user