mirror of
https://github.com/ivanizag/izapple2.git
synced 2024-06-15 08:29:28 +00:00
UI to select screen modes
This commit is contained in:
parent
18bff5d3f4
commit
edc09aa9c6
|
@ -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)
|
cpu speed in Mhz, use 0 for full speed. Use F5 to toggle. (default 1.0227142857142857)
|
||||||
-model string
|
-model string
|
||||||
set base model. Models available 2plus, 2e, 2enh, base64a (default "2enh")
|
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
|
-nsc int
|
||||||
add a DS1216 No-Slot-Clock on the main ROM (use 0) or a slot ROM. -1 for none (default -1)
|
add a DS1216 No-Slot-Clock on the main ROM (use 0) or a slot ROM. -1 for none (default -1)
|
||||||
-panicSS
|
-panicSS
|
||||||
|
|
|
@ -18,7 +18,6 @@ type Apple2 struct {
|
||||||
isApple2e bool
|
isApple2e bool
|
||||||
commandChannel chan int
|
commandChannel chan int
|
||||||
cycleDurationNs float64 // Current speed. Inverse of the cpu clock in Ghz
|
cycleDurationNs float64 // Current speed. Inverse of the cpu clock in Ghz
|
||||||
isColor bool
|
|
||||||
fastMode bool
|
fastMode bool
|
||||||
fastRequestsCounter int
|
fastRequestsCounter int
|
||||||
profile bool
|
profile bool
|
||||||
|
@ -126,8 +125,6 @@ const (
|
||||||
CommandToggleSpeed = iota + 1
|
CommandToggleSpeed = iota + 1
|
||||||
// CommandShowSpeed toggles printinf the current freq in Mhz
|
// CommandShowSpeed toggles printinf the current freq in Mhz
|
||||||
CommandShowSpeed
|
CommandShowSpeed
|
||||||
// CommandToggleColor toggles between NTSC color TV and Green phospor monitor
|
|
||||||
CommandToggleColor
|
|
||||||
// CommandDumpDebugInfo dumps useful info
|
// CommandDumpDebugInfo dumps useful info
|
||||||
CommandDumpDebugInfo
|
CommandDumpDebugInfo
|
||||||
// CommandNextCharGenPage cycles the CharGen page if several
|
// CommandNextCharGenPage cycles the CharGen page if several
|
||||||
|
@ -159,8 +156,6 @@ func (a *Apple2) executeCommand(command int) {
|
||||||
}
|
}
|
||||||
case CommandShowSpeed:
|
case CommandShowSpeed:
|
||||||
a.showSpeed = !a.showSpeed
|
a.showSpeed = !a.showSpeed
|
||||||
case CommandToggleColor:
|
|
||||||
a.isColor = !a.isColor
|
|
||||||
case CommandDumpDebugInfo:
|
case CommandDumpDebugInfo:
|
||||||
a.dumpDebugInfo()
|
a.dumpDebugInfo()
|
||||||
case CommandNextCharGenPage:
|
case CommandNextCharGenPage:
|
||||||
|
|
|
@ -15,9 +15,8 @@ func newApple2() *Apple2 {
|
||||||
return &a
|
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.commandChannel = make(chan int, 100)
|
||||||
a.isColor = isColor
|
|
||||||
a.fastMode = fastMode
|
a.fastMode = fastMode
|
||||||
if traceMLI {
|
if traceMLI {
|
||||||
a.traceMLI = newTraceProDOS(a)
|
a.traceMLI = newTraceProDOS(a)
|
||||||
|
|
|
@ -81,10 +81,6 @@ func MainApple() *Apple2 {
|
||||||
"nsc",
|
"nsc",
|
||||||
-1,
|
-1,
|
||||||
"add a DS1216 No-Slot-Clock on the main ROM (use 0) or a slot ROM. -1 for none")
|
"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(
|
rgbCard := flag.Bool(
|
||||||
"rgb",
|
"rgb",
|
||||||
true,
|
true,
|
||||||
|
@ -155,7 +151,7 @@ func MainApple() *Apple2 {
|
||||||
}
|
}
|
||||||
|
|
||||||
a := newApple2()
|
a := newApple2()
|
||||||
a.setup(!*mono, *cpuClock, *fastDisk, *traceMLI)
|
a.setup(*cpuClock, *fastDisk, *traceMLI)
|
||||||
a.io.setTrace(*traceSS)
|
a.io.setTrace(*traceSS)
|
||||||
a.io.setTraceRegistrations(*traceSSReg)
|
a.io.setTraceRegistrations(*traceSSReg)
|
||||||
a.io.setPanicNotImplemented(*panicSS)
|
a.io.setPanicNotImplemented(*panicSS)
|
||||||
|
|
|
@ -88,7 +88,7 @@ func sdlRun(a *izapple2.Apple2) {
|
||||||
img = a.SnapshotParts()
|
img = a.SnapshotParts()
|
||||||
window.SetTitle(fmt.Sprintf("%v %v %vx%v", a.Name, a.VideoModeName(), img.Rect.Dx()/2, img.Rect.Dy()/2))
|
window.SetTitle(fmt.Sprintf("%v %v %vx%v", a.Name, a.VideoModeName(), img.Rect.Dx()/2, img.Rect.Dy()/2))
|
||||||
} else {
|
} else {
|
||||||
img = a.Snapshot()
|
img = a.Snapshot(izapple2.ScreenModeNTSC)
|
||||||
}
|
}
|
||||||
if img != nil {
|
if img != nil {
|
||||||
surface, err := sdl.CreateRGBSurfaceFrom(unsafe.Pointer(&img.Pix[0]),
|
surface, err := sdl.CreateRGBSurfaceFrom(unsafe.Pointer(&img.Pix[0]),
|
||||||
|
|
|
@ -94,8 +94,6 @@ func (k *sdlKeyboard) putKey(keyEvent *sdl.KeyboardEvent) {
|
||||||
} else {
|
} else {
|
||||||
k.a.SendCommand(izapple2.CommandToggleSpeed)
|
k.a.SendCommand(izapple2.CommandToggleSpeed)
|
||||||
}
|
}
|
||||||
case sdl.K_F6:
|
|
||||||
k.a.SendCommand(izapple2.CommandToggleColor)
|
|
||||||
case sdl.K_F7:
|
case sdl.K_F7:
|
||||||
k.showPages = !k.showPages
|
k.showPages = !k.showPages
|
||||||
case sdl.K_F9:
|
case sdl.K_F9:
|
||||||
|
@ -106,7 +104,7 @@ func (k *sdlKeyboard) putKey(keyEvent *sdl.KeyboardEvent) {
|
||||||
k.a.SendCommand(izapple2.CommandToggleCPUTrace)
|
k.a.SendCommand(izapple2.CommandToggleCPUTrace)
|
||||||
case sdl.K_F12:
|
case sdl.K_F12:
|
||||||
case sdl.K_PRINTSCREEN:
|
case sdl.K_PRINTSCREEN:
|
||||||
err := izapple2.SaveSnapshot(k.a, "snapshot.png")
|
err := izapple2.SaveSnapshot(k.a, izapple2.ScreenModeNTSC, "snapshot.png")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Printf("Error saving snapshoot: %v.\n.", err)
|
fmt.Printf("Error saving snapshoot: %v.\n.", err)
|
||||||
} else {
|
} else {
|
||||||
|
|
36
screen.go
36
screen.go
|
@ -40,6 +40,15 @@ const (
|
||||||
videoSecondPage uint16 = 0x1000
|
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 {
|
func getCurrentVideoMode(a *Apple2) uint16 {
|
||||||
isTextMode := a.io.isSoftSwitchActive(ioFlagText)
|
isTextMode := a.io.isSoftSwitchActive(ioFlagText)
|
||||||
isHiResMode := a.io.isSoftSwitchActive(ioFlagHiRes)
|
isHiResMode := a.io.isSoftSwitchActive(ioFlagHiRes)
|
||||||
|
@ -106,22 +115,19 @@ func getCurrentVideoMode(a *Apple2) uint16 {
|
||||||
return mode
|
return mode
|
||||||
}
|
}
|
||||||
|
|
||||||
func snapshotByMode(a *Apple2, videoMode uint16) *image.RGBA {
|
func snapshotByMode(a *Apple2, videoMode uint16, screenMode int) *image.RGBA {
|
||||||
videoBase := videoMode & videoBaseMask
|
videoBase := videoMode & videoBaseMask
|
||||||
mixMode := videoMode & videoMixTextMask
|
mixMode := videoMode & videoMixTextMask
|
||||||
isSecondPage := (videoMode & videoSecondPage) != 0
|
isSecondPage := (videoMode & videoSecondPage) != 0
|
||||||
|
|
||||||
var lightColor color.Color
|
var lightColor color.Color = color.White
|
||||||
if a.isColor {
|
if screenMode == ScreenModeGreen {
|
||||||
lightColor = color.White
|
|
||||||
} else {
|
|
||||||
// Color for typical Apple ][ period green P1 phosphor monitors
|
// 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
|
// 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}
|
lightColor = color.RGBA{65, 255, 0, 255}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
applyNTSCFilter := a.isColor
|
applyNTSCFilter := screenMode != ScreenModeGreen
|
||||||
var snap *image.RGBA
|
var snap *image.RGBA
|
||||||
var ntscMask *image.Alpha
|
var ntscMask *image.Alpha
|
||||||
switch videoBase {
|
switch videoBase {
|
||||||
|
@ -155,12 +161,12 @@ func snapshotByMode(a *Apple2, videoMode uint16) *image.RGBA {
|
||||||
}
|
}
|
||||||
|
|
||||||
if applyNTSCFilter {
|
if applyNTSCFilter {
|
||||||
snap = filterNTSCColor(snap, ntscMask)
|
snap = filterNTSCColor(snap, ntscMask, screenMode)
|
||||||
}
|
}
|
||||||
|
|
||||||
if mixMode != 0 {
|
if mixMode != 0 {
|
||||||
var bottom *image.RGBA
|
var bottom *image.RGBA
|
||||||
applyNTSCFilter := a.isColor
|
applyNTSCFilter := screenMode != ScreenModeGreen
|
||||||
switch mixMode {
|
switch mixMode {
|
||||||
case videoMixText40:
|
case videoMixText40:
|
||||||
bottom = snapshotText40Mode(a, isSecondPage, lightColor)
|
bottom = snapshotText40Mode(a, isSecondPage, lightColor)
|
||||||
|
@ -171,7 +177,7 @@ func snapshotByMode(a *Apple2, videoMode uint16) *image.RGBA {
|
||||||
applyNTSCFilter = false
|
applyNTSCFilter = false
|
||||||
}
|
}
|
||||||
if applyNTSCFilter {
|
if applyNTSCFilter {
|
||||||
bottom = filterNTSCColor(bottom, ntscMask)
|
bottom = filterNTSCColor(bottom, ntscMask, screenMode)
|
||||||
}
|
}
|
||||||
snap = mixSnapshots(snap, bottom)
|
snap = mixSnapshots(snap, bottom)
|
||||||
}
|
}
|
||||||
|
@ -180,11 +186,11 @@ func snapshotByMode(a *Apple2, videoMode uint16) *image.RGBA {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Snapshot the currently visible screen
|
// Snapshot the currently visible screen
|
||||||
func (a *Apple2) Snapshot() *image.RGBA {
|
func (a *Apple2) Snapshot(screenMode int) *image.RGBA {
|
||||||
videoMode := getCurrentVideoMode(a)
|
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
|
// Apply the filter to regular CRT snapshots with 192 lines. Not to SHR
|
||||||
snap = linesSeparatedFilter(snap)
|
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
|
// SaveSnapshot saves a snapshot of the screen to a png file
|
||||||
func SaveSnapshot(a *Apple2, filename string) error {
|
func SaveSnapshot(a *Apple2, screenMode int, filename string) error {
|
||||||
img := a.Snapshot()
|
img := a.Snapshot(screenMode)
|
||||||
img = squarishPixelsFilter(img)
|
img = squarishPixelsFilter(img)
|
||||||
|
|
||||||
f, err := os.Create(filename)
|
f, err := os.Create(filename)
|
||||||
|
|
|
@ -12,9 +12,9 @@ func (a *Apple2) SnapshotParts() *image.RGBA {
|
||||||
mixMode := videoMode & videoMixTextMask
|
mixMode := videoMode & videoMixTextMask
|
||||||
modifiers := videoMode & videoModifiersMask
|
modifiers := videoMode & videoModifiersMask
|
||||||
|
|
||||||
snapScreen := snapshotByMode(a, videoMode)
|
snapScreen := snapshotByMode(a, videoMode, ScreenModePlain)
|
||||||
snapPage1 := snapshotByMode(a, videoMode&^videoSecondPage)
|
snapPage1 := snapshotByMode(a, videoMode&^videoSecondPage, ScreenModePlain)
|
||||||
snapPage2 := snapshotByMode(a, videoMode|videoSecondPage)
|
snapPage2 := snapshotByMode(a, videoMode|videoSecondPage, ScreenModePlain)
|
||||||
var snapAux *image.RGBA
|
var snapAux *image.RGBA
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -28,11 +28,11 @@ func (a *Apple2) SnapshotParts() *image.RGBA {
|
||||||
} else {
|
} else {
|
||||||
switch mixMode {
|
switch mixMode {
|
||||||
case videoMixText80:
|
case videoMixText80:
|
||||||
snapAux = snapshotByMode(a, videoText80|modifiers)
|
snapAux = snapshotByMode(a, videoText80|modifiers, ScreenModePlain)
|
||||||
case videoMixText40RGB:
|
case videoMixText40RGB:
|
||||||
snapAux = snapshotByMode(a, videoText40RGB|modifiers)
|
snapAux = snapshotByMode(a, videoText40RGB|modifiers, ScreenModePlain)
|
||||||
default:
|
default:
|
||||||
snapAux = snapshotByMode(a, videoText40|modifiers)
|
snapAux = snapshotByMode(a, videoText40|modifiers, ScreenModePlain)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -46,18 +46,14 @@ func (a *Apple2) VideoModeName() string {
|
||||||
mixMode := videoMode & videoMixTextMask
|
mixMode := videoMode & videoMixTextMask
|
||||||
|
|
||||||
var name string
|
var name string
|
||||||
applyNTSCFilter := a.isColor
|
|
||||||
|
|
||||||
switch videoBase {
|
switch videoBase {
|
||||||
case videoText40:
|
case videoText40:
|
||||||
name = "TEXT40COL"
|
name = "TEXT40COL"
|
||||||
applyNTSCFilter = false
|
|
||||||
case videoText80:
|
case videoText80:
|
||||||
name = "TEXT80COL"
|
name = "TEXT80COL"
|
||||||
applyNTSCFilter = false
|
|
||||||
case videoText40RGB:
|
case videoText40RGB:
|
||||||
name = "TEXT40COLRGB"
|
name = "TEXT40COLRGB"
|
||||||
applyNTSCFilter = false
|
|
||||||
case videoGR:
|
case videoGR:
|
||||||
name = "GR"
|
name = "GR"
|
||||||
case videoDGR:
|
case videoDGR:
|
||||||
|
@ -68,14 +64,12 @@ func (a *Apple2) VideoModeName() string {
|
||||||
name = "DHGR"
|
name = "DHGR"
|
||||||
case videoMono560:
|
case videoMono560:
|
||||||
name = "Mono560"
|
name = "Mono560"
|
||||||
applyNTSCFilter = false
|
|
||||||
case videoRGBMix:
|
case videoRGBMix:
|
||||||
name = "RGMMIX"
|
name = "RGMMIX"
|
||||||
case videoRGB160:
|
case videoRGB160:
|
||||||
name = "RGB160"
|
name = "RGB160"
|
||||||
case videoSHR:
|
case videoSHR:
|
||||||
name = "SHR"
|
name = "SHR"
|
||||||
applyNTSCFilter = false
|
|
||||||
default:
|
default:
|
||||||
name = "Unknown video mode"
|
name = "Unknown video mode"
|
||||||
}
|
}
|
||||||
|
@ -93,9 +87,6 @@ func (a *Apple2) VideoModeName() string {
|
||||||
name += "-MIX40RGB"
|
name += "-MIX40RGB"
|
||||||
}
|
}
|
||||||
|
|
||||||
if applyNTSCFilter {
|
|
||||||
name += "-NTSC"
|
|
||||||
}
|
|
||||||
return name
|
return name
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -49,14 +49,16 @@ var rgbColorMap = [16]color.Color{
|
||||||
color.RGBA{255, 255, 255, 255}, // White
|
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
|
colorMap := ntscColorMap // or rgbColorMap
|
||||||
attenuatedColorMap := make([]color.Color, 16, 16)
|
attenuatedColorMap := ntscColorMap
|
||||||
for i := 0; i < len(colorMap); i++ {
|
if screenMode == ScreenModeNTSC {
|
||||||
r, g, b, _ := colorMap[i].RGBA()
|
for i := 0; i < len(colorMap); i++ {
|
||||||
attenuatedColorMap[i] = color.RGBA64{
|
r, g, b, _ := colorMap[i].RGBA()
|
||||||
uint16(r / 2), uint16(g / 2), uint16(b / 2),
|
attenuatedColorMap[i] = color.RGBA64{
|
||||||
65535,
|
uint16(r / 2), uint16(g / 2), uint16(b / 2),
|
||||||
|
65535,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue
Block a user