diff --git a/README.md b/README.md index 54cee36..299dd40 100644 --- a/README.md +++ b/README.md @@ -191,8 +191,6 @@ Only valid on SDL mode cpu speed in Mhz, use 0 for full speed. Use F5 to toggle. (default 1.0227142857142857) -model string set base model. Models available 2plus, 2e, 2enh, base64a (default "2enh") - -mono - emulate a green phosphor monitor instead of a NTSC color TV. Use F6 to toggle. -nsc int add a DS1216 No-Slot-Clock on the main ROM (use 0) or a slot ROM. -1 for none (default -1) -panicSS diff --git a/apple2.go b/apple2.go index 01673c6..541276a 100644 --- a/apple2.go +++ b/apple2.go @@ -18,7 +18,6 @@ type Apple2 struct { isApple2e bool commandChannel chan int cycleDurationNs float64 // Current speed. Inverse of the cpu clock in Ghz - isColor bool fastMode bool fastRequestsCounter int profile bool @@ -126,8 +125,6 @@ const ( CommandToggleSpeed = iota + 1 // CommandShowSpeed toggles printinf the current freq in Mhz CommandShowSpeed - // CommandToggleColor toggles between NTSC color TV and Green phospor monitor - CommandToggleColor // CommandDumpDebugInfo dumps useful info CommandDumpDebugInfo // CommandNextCharGenPage cycles the CharGen page if several @@ -159,8 +156,6 @@ func (a *Apple2) executeCommand(command int) { } case CommandShowSpeed: a.showSpeed = !a.showSpeed - case CommandToggleColor: - a.isColor = !a.isColor case CommandDumpDebugInfo: a.dumpDebugInfo() case CommandNextCharGenPage: diff --git a/apple2Setup.go b/apple2Setup.go index 2085d48..683a3eb 100644 --- a/apple2Setup.go +++ b/apple2Setup.go @@ -15,9 +15,8 @@ func newApple2() *Apple2 { return &a } -func (a *Apple2) setup(isColor bool, clockMhz float64, fastMode bool, traceMLI bool) { +func (a *Apple2) setup(clockMhz float64, fastMode bool, traceMLI bool) { a.commandChannel = make(chan int, 100) - a.isColor = isColor a.fastMode = fastMode if traceMLI { a.traceMLI = newTraceProDOS(a) diff --git a/apple2main.go b/apple2main.go index 19743de..ed16b04 100644 --- a/apple2main.go +++ b/apple2main.go @@ -81,10 +81,6 @@ func MainApple() *Apple2 { "nsc", -1, "add a DS1216 No-Slot-Clock on the main ROM (use 0) or a slot ROM. -1 for none") - mono := flag.Bool( - "mono", - false, - "emulate a green phosphor monitor instead of a NTSC color TV. Use F6 to toggle.") rgbCard := flag.Bool( "rgb", true, @@ -155,7 +151,7 @@ func MainApple() *Apple2 { } a := newApple2() - a.setup(!*mono, *cpuClock, *fastDisk, *traceMLI) + a.setup(*cpuClock, *fastDisk, *traceMLI) a.io.setTrace(*traceSS) a.io.setTraceRegistrations(*traceSSReg) a.io.setPanicNotImplemented(*panicSS) diff --git a/izapple2sdl/main.go b/izapple2sdl/main.go index d5575d2..15923f6 100644 --- a/izapple2sdl/main.go +++ b/izapple2sdl/main.go @@ -88,7 +88,7 @@ func sdlRun(a *izapple2.Apple2) { img = a.SnapshotParts() window.SetTitle(fmt.Sprintf("%v %v %vx%v", a.Name, a.VideoModeName(), img.Rect.Dx()/2, img.Rect.Dy()/2)) } else { - img = a.Snapshot() + img = a.Snapshot(izapple2.ScreenModeNTSC) } if img != nil { surface, err := sdl.CreateRGBSurfaceFrom(unsafe.Pointer(&img.Pix[0]), diff --git a/izapple2sdl/sdlKeyboard.go b/izapple2sdl/sdlKeyboard.go index edd071e..b2116ca 100644 --- a/izapple2sdl/sdlKeyboard.go +++ b/izapple2sdl/sdlKeyboard.go @@ -94,8 +94,6 @@ func (k *sdlKeyboard) putKey(keyEvent *sdl.KeyboardEvent) { } else { k.a.SendCommand(izapple2.CommandToggleSpeed) } - case sdl.K_F6: - k.a.SendCommand(izapple2.CommandToggleColor) case sdl.K_F7: k.showPages = !k.showPages case sdl.K_F9: @@ -106,7 +104,7 @@ func (k *sdlKeyboard) putKey(keyEvent *sdl.KeyboardEvent) { k.a.SendCommand(izapple2.CommandToggleCPUTrace) case sdl.K_F12: case sdl.K_PRINTSCREEN: - err := izapple2.SaveSnapshot(k.a, "snapshot.png") + err := izapple2.SaveSnapshot(k.a, izapple2.ScreenModeNTSC, "snapshot.png") if err != nil { fmt.Printf("Error saving snapshoot: %v.\n.", err) } else { diff --git a/screen.go b/screen.go index bca01e7..9998d1f 100644 --- a/screen.go +++ b/screen.go @@ -40,6 +40,15 @@ const ( videoSecondPage uint16 = 0x1000 ) +const ( + // ScreenModeGreen to render as a green phosphor monitor + ScreenModeGreen = iota + // ScreenModePlain to render in color with filled areas + ScreenModePlain + //ScreenModeNTSC shows spaces between pixels + ScreenModeNTSC +) + func getCurrentVideoMode(a *Apple2) uint16 { isTextMode := a.io.isSoftSwitchActive(ioFlagText) isHiResMode := a.io.isSoftSwitchActive(ioFlagHiRes) @@ -106,22 +115,19 @@ func getCurrentVideoMode(a *Apple2) uint16 { return mode } -func snapshotByMode(a *Apple2, videoMode uint16) *image.RGBA { +func snapshotByMode(a *Apple2, videoMode uint16, screenMode int) *image.RGBA { videoBase := videoMode & videoBaseMask mixMode := videoMode & videoMixTextMask isSecondPage := (videoMode & videoSecondPage) != 0 - var lightColor color.Color - if a.isColor { - lightColor = color.White - } else { + var lightColor color.Color = color.White + if screenMode == ScreenModeGreen { // 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} - } - applyNTSCFilter := a.isColor + applyNTSCFilter := screenMode != ScreenModeGreen var snap *image.RGBA var ntscMask *image.Alpha switch videoBase { @@ -155,12 +161,12 @@ func snapshotByMode(a *Apple2, videoMode uint16) *image.RGBA { } if applyNTSCFilter { - snap = filterNTSCColor(snap, ntscMask) + snap = filterNTSCColor(snap, ntscMask, screenMode) } if mixMode != 0 { var bottom *image.RGBA - applyNTSCFilter := a.isColor + applyNTSCFilter := screenMode != ScreenModeGreen switch mixMode { case videoMixText40: bottom = snapshotText40Mode(a, isSecondPage, lightColor) @@ -171,7 +177,7 @@ func snapshotByMode(a *Apple2, videoMode uint16) *image.RGBA { applyNTSCFilter = false } if applyNTSCFilter { - bottom = filterNTSCColor(bottom, ntscMask) + bottom = filterNTSCColor(bottom, ntscMask, screenMode) } snap = mixSnapshots(snap, bottom) } @@ -180,11 +186,11 @@ func snapshotByMode(a *Apple2, videoMode uint16) *image.RGBA { } // Snapshot the currently visible screen -func (a *Apple2) Snapshot() *image.RGBA { +func (a *Apple2) Snapshot(screenMode int) *image.RGBA { videoMode := getCurrentVideoMode(a) - snap := snapshotByMode(a, videoMode) + snap := snapshotByMode(a, videoMode, screenMode) - if snap.Bounds().Dy() == hiResHeight { + if screenMode == ScreenModeNTSC && snap.Bounds().Dy() == hiResHeight { // Apply the filter to regular CRT snapshots with 192 lines. Not to SHR snap = linesSeparatedFilter(snap) } @@ -207,8 +213,8 @@ func mixSnapshots(top, bottom *image.RGBA) *image.RGBA { } // SaveSnapshot saves a snapshot of the screen to a png file -func SaveSnapshot(a *Apple2, filename string) error { - img := a.Snapshot() +func SaveSnapshot(a *Apple2, screenMode int, filename string) error { + img := a.Snapshot(screenMode) img = squarishPixelsFilter(img) f, err := os.Create(filename) diff --git a/screenDebugParts.go b/screenDebugParts.go index 2838c63..3874500 100644 --- a/screenDebugParts.go +++ b/screenDebugParts.go @@ -12,9 +12,9 @@ func (a *Apple2) SnapshotParts() *image.RGBA { mixMode := videoMode & videoMixTextMask modifiers := videoMode & videoModifiersMask - snapScreen := snapshotByMode(a, videoMode) - snapPage1 := snapshotByMode(a, videoMode&^videoSecondPage) - snapPage2 := snapshotByMode(a, videoMode|videoSecondPage) + snapScreen := snapshotByMode(a, videoMode, ScreenModePlain) + snapPage1 := snapshotByMode(a, videoMode&^videoSecondPage, ScreenModePlain) + snapPage2 := snapshotByMode(a, videoMode|videoSecondPage, ScreenModePlain) var snapAux *image.RGBA /* @@ -28,11 +28,11 @@ func (a *Apple2) SnapshotParts() *image.RGBA { } else { switch mixMode { case videoMixText80: - snapAux = snapshotByMode(a, videoText80|modifiers) + snapAux = snapshotByMode(a, videoText80|modifiers, ScreenModePlain) case videoMixText40RGB: - snapAux = snapshotByMode(a, videoText40RGB|modifiers) + snapAux = snapshotByMode(a, videoText40RGB|modifiers, ScreenModePlain) default: - snapAux = snapshotByMode(a, videoText40|modifiers) + snapAux = snapshotByMode(a, videoText40|modifiers, ScreenModePlain) } } @@ -46,18 +46,14 @@ func (a *Apple2) VideoModeName() string { mixMode := videoMode & videoMixTextMask var name string - applyNTSCFilter := a.isColor switch videoBase { case videoText40: name = "TEXT40COL" - applyNTSCFilter = false case videoText80: name = "TEXT80COL" - applyNTSCFilter = false case videoText40RGB: name = "TEXT40COLRGB" - applyNTSCFilter = false case videoGR: name = "GR" case videoDGR: @@ -68,14 +64,12 @@ func (a *Apple2) VideoModeName() string { name = "DHGR" case videoMono560: name = "Mono560" - applyNTSCFilter = false case videoRGBMix: name = "RGMMIX" case videoRGB160: name = "RGB160" case videoSHR: name = "SHR" - applyNTSCFilter = false default: name = "Unknown video mode" } @@ -93,9 +87,6 @@ func (a *Apple2) VideoModeName() string { name += "-MIX40RGB" } - if applyNTSCFilter { - name += "-NTSC" - } return name } diff --git a/screenNtscFilter.go b/screenNtscFilter.go index 5144d1a..56c9512 100644 --- a/screenNtscFilter.go +++ b/screenNtscFilter.go @@ -49,14 +49,16 @@ var rgbColorMap = [16]color.Color{ color.RGBA{255, 255, 255, 255}, // White } -func filterNTSCColor(in *image.RGBA, mask *image.Alpha) *image.RGBA { +func filterNTSCColor(in *image.RGBA, mask *image.Alpha, screenMode int) *image.RGBA { colorMap := ntscColorMap // or rgbColorMap - attenuatedColorMap := make([]color.Color, 16, 16) - for i := 0; i < len(colorMap); i++ { - r, g, b, _ := colorMap[i].RGBA() - attenuatedColorMap[i] = color.RGBA64{ - uint16(r / 2), uint16(g / 2), uint16(b / 2), - 65535, + attenuatedColorMap := ntscColorMap + if screenMode == ScreenModeNTSC { + for i := 0; i < len(colorMap); i++ { + r, g, b, _ := colorMap[i].RGBA() + attenuatedColorMap[i] = color.RGBA64{ + uint16(r / 2), uint16(g / 2), uint16(b / 2), + 65535, + } } }