diff --git a/apple2/apple2.go b/apple2/apple2.go index 6c3c3fd..891eebf 100644 --- a/apple2/apple2.go +++ b/apple2/apple2.go @@ -20,6 +20,7 @@ type Apple2 struct { activeSlot int // Slot that has the addressing 0xc800 to 0ccfff commandChannel chan int cycleDurationNs float64 // Inverse of the cpu clock in Ghz + isColor bool } const ( @@ -29,7 +30,7 @@ const ( ) // NewApple2 instantiates an apple2 -func NewApple2(romFile string, charRomFile string, clockMhz float64, panicSS bool) *Apple2 { +func NewApple2(romFile string, charRomFile string, clockMhz float64, isColor bool, panicSS bool) *Apple2 { var a Apple2 a.mmu = newMemoryManager(&a) a.cpu = core6502.NewNMOS6502(a.mmu) @@ -39,6 +40,7 @@ func NewApple2(romFile string, charRomFile string, clockMhz float64, panicSS boo } a.mmu.resetRomPaging() a.commandChannel = make(chan int, 100) + a.isColor = isColor a.panicSS = panicSS if clockMhz <= 0 { @@ -91,6 +93,8 @@ func (a *Apple2) SetKeyboardProvider(kb KeyboardProvider) { const ( // CommandToggleSpeed toggles cpu speed between full speed and actual Apple II speed CommandToggleSpeed = iota + 1 + // CommandToggleColor toggles between NTSC color TV and Green phospor monitor + CommandToggleColor ) // SendCommand enqueues a command to the emulator thread @@ -108,6 +112,8 @@ func (a *Apple2) executeCommand(command int) { fmt.Println("Fast") a.cycleDurationNs = 0 } + case CommandToggleColor: + a.isColor = !a.isColor } } diff --git a/apple2/screen.go b/apple2/screen.go index 970671d..48e8685 100644 --- a/apple2/screen.go +++ b/apple2/screen.go @@ -17,6 +17,7 @@ References: // Snapshot the currently visible screen func Snapshot(a *Apple2) *image.RGBA { + isColor := a.isColor isTextMode := a.io.isSoftSwitchActive(ioFlagText) isHiResMode := a.io.isSoftSwitchActive(ioFlagHiRes) isMixMode := a.io.isSoftSwitchActive(ioFlagMixed) @@ -26,32 +27,36 @@ func Snapshot(a *Apple2) *image.RGBA { pageIndex = 1 } + var lightColor color.Color + if isColor { + lightColor = color.White + } else { + // Color for typical Apple ][ period green P1 phosphor monitors + // See: https://superuser.com/questions/361297/what-colour-is-the-dark-green-on-old-fashioned-green-screen-computer-displays + lightColor = color.RGBA{65, 255, 0, 255} + + } + var snap *image.RGBA if isTextMode { - // Color for typical Apple ][ period green phosphor monitors - // See: https://superuser.com/questions/361297/what-colour-is-the-dark-green-on-old-fashioned-green-screen-computer-displays - p1GreenPhosphorColor := color.RGBA{65, 255, 0, 255} - - snap = snapshotTextMode(a, pageIndex, false, p1GreenPhosphorColor) - snap = linesSeparatedFilter(snap) + snap = snapshotTextMode(a, pageIndex, false, lightColor) } else { if isHiResMode { - //snap = snapshotHiResModeReferenceMono(a, pageIndex, isMixMode) - //snap = snapshotHiResModeReferenceColor(a, pageIndex, isMixMode) - //snap = snapshotHiResModeReferenceColorSolid(a, pageIndex, isMixMode) - snap = snapshotHiResModeMonoShift(a, pageIndex, isMixMode) + snap = snapshotHiResModeMonoShift(a, pageIndex, isMixMode, lightColor) } else { // Lo res mode not supported return nil } if isMixMode { - snapText := snapshotTextMode(a, pageIndex, isHiResMode, color.White) + snapText := snapshotTextMode(a, pageIndex, isHiResMode, lightColor) snap = mixSnapshots(snap, snapText) } - //snap = filterNTSCColorStatic(snap) - snap = filterNTSCColorMoving(false /*blacker*/, snap) - snap = linesSeparatedFilter(snap) + if isColor { + snap = filterNTSCColor(false /*blacker*/, snap) + } } + + snap = linesSeparatedFilter(snap) return snap } diff --git a/apple2/screenHgr.go b/apple2/screenHgr.go index 6460d4c..ad44c5f 100644 --- a/apple2/screenHgr.go +++ b/apple2/screenHgr.go @@ -37,37 +37,7 @@ func getGraphLine(a *Apple2, line int, page int) []uint8 { return memPage[lo : lo+40] } -func snapshotHiResModeReferenceMono(a *Apple2, page int, mixedMode bool) *image.RGBA { - // As defined on "Apple II Reference Manual", page 19 - - height := graphHeight - if mixedMode { - height = graphHeightMixed - } - - size := image.Rect(0, 0, graphWidth, height) - img := image.NewRGBA(size) - - for y := 0; y < height; y++ { - bytes := getGraphLine(a, y, page) - x := 0 - for _, b := range bytes { - for j := uint(0); j < 7; j++ { - bit := (b >> j) & 1 - colour := color.Black - if bit == 1 { - colour = color.White - } - img.Set(x, y, colour) - x++ - } - } - } - - return img -} - -func snapshotHiResModeMonoShift(a *Apple2, page int, mixedMode bool) *image.RGBA { +func snapshotHiResModeMonoShift(a *Apple2, page int, mixedMode bool, light color.Color) *image.RGBA { // As described in "Undertanding the Apple II", with half pixel shifts height := graphHeight @@ -81,14 +51,14 @@ func snapshotHiResModeMonoShift(a *Apple2, page int, mixedMode bool) *image.RGBA for y := 0; y < height; y++ { bytes := getGraphLine(a, y, page) x := 0 - previousColour := color.Black + var previousColour color.Color = color.Black for _, b := range bytes { shifted := b>>7 == 1 for j := uint(0); j < 7; j++ { bit := (b >> j) & 1 - colour := color.Black - if bit == 1 { - colour = color.White + colour := light + if bit == 0 { + colour = color.Black } if shifted { diff --git a/apple2/screenNtscFilter.go b/apple2/screenNtscFilter.go index d4e56de..488d7d8 100644 --- a/apple2/screenNtscFilter.go +++ b/apple2/screenNtscFilter.go @@ -53,31 +53,7 @@ func getNTSCColorMap() []color.Color { return colorMap } -func filterNTSCColorStatic(in *image.RGBA) *image.RGBA { - colorMap := getNTSCColorMap() - - b := in.Bounds() - size := image.Rect(0, 0, b.Dx()/4, b.Dy()) - out := image.NewRGBA(size) - for y := b.Min.Y; y < b.Max.Y; y++ { - for x := b.Min.X; x < b.Max.X; x += 4 { - v := 0 - for i := 0; i < 4; i++ { - cIn := in.At(x+i, y) - r, _, _, _ := cIn.RGBA() - v = v << 1 - if r != 0 { - v++ - } - } - cOut := colorMap[v] - out.Set(x/4, y, cOut) - } - } - return out -} - -func filterNTSCColorMoving(blacker bool, in *image.RGBA) *image.RGBA { +func filterNTSCColor(blacker bool, in *image.RGBA) *image.RGBA { colorMap := getNTSCColorMap() b := in.Bounds() diff --git a/apple2sdl/sdlKeyboard.go b/apple2sdl/sdlKeyboard.go index 8b65cad..534d284 100644 --- a/apple2sdl/sdlKeyboard.go +++ b/apple2sdl/sdlKeyboard.go @@ -91,6 +91,8 @@ func (k *sdlKeyboard) putKey(keyEvent *sdl.KeyboardEvent) { // Control of the emulator case sdl.K_F5: k.a.SendCommand(apple2.CommandToggleSpeed) + case sdl.K_F6: + k.a.SendCommand(apple2.CommandToggleColor) } // Missing values 91 to 95. Usually control for [\]^_ diff --git a/main.go b/main.go index 4a43c7e..ec785f1 100644 --- a/main.go +++ b/main.go @@ -22,7 +22,7 @@ func main() { cpuClock := flag.Float64( "mhz", apple2.CpuClockMhz, - "cpu speed in Mhz, use 0 for full speed") + "cpu speed in Mhz, use 0 for full speed. Use F5 to toggle.") charRomFile := flag.String( "charRom", "apple2/romdumps/Apple2rev7CharGen.rom", @@ -35,6 +35,11 @@ func main() { "stdout", false, "show the text screen on the standard output") + mono := flag.Bool( + "mono", + false, + "emulate a green phosphor monitor instead of a NTSC color TV. Use F6 to toggle.", + ) panicSS := flag.Bool( "panicss", false, @@ -53,7 +58,7 @@ func main() { } log := false - a := apple2.NewApple2(*romFile, *charRomFile, *cpuClock, *panicSS) + a := apple2.NewApple2(*romFile, *charRomFile, *cpuClock, !*mono, *panicSS) a.AddDisk2(*disk2RomFile, *diskImage) if *useSdl { a.ConfigureStdConsole(false, *stdoutScreen)