From 62d0a35b3ea6db8ab0b727f96c3997cd7fdb8f6a Mon Sep 17 00:00:00 2001 From: Ivan Izaguirre Date: Sun, 9 Aug 2020 16:42:16 +0200 Subject: [PATCH] Support for video7 RGB 160*192 video mode --- apple2sdl/main.go | 3 ++- cardRGB.go | 3 +++ screen.go | 9 ++++++++- screenDebugParts.go | 20 ++++++++++++-------- screenDoubleHiRes.go | 30 ++++++++++++++++++++++++++++++ screenLoRes.go | 4 ++-- screenNtscFilter.go | 10 ++++++---- 7 files changed, 63 insertions(+), 16 deletions(-) diff --git a/apple2sdl/main.go b/apple2sdl/main.go index 37db463..790fa92 100644 --- a/apple2sdl/main.go +++ b/apple2sdl/main.go @@ -1,6 +1,7 @@ package main import ( + "fmt" "image" "unsafe" @@ -81,7 +82,7 @@ func SDLRun(a *apple2.Apple2) { var img *image.RGBA if kp.showPages { img = a.SnapshotParts() - window.SetTitle(a.Name + " " + a.VideoModeName()) + window.SetTitle(fmt.Sprintf("%v %v %vx%v", a.Name, a.VideoModeName(), img.Rect.Dx()/2, img.Rect.Dy()/2)) } else { img = a.Snapshot() } diff --git a/cardRGB.go b/cardRGB.go index f915ce1..0c7518c 100644 --- a/cardRGB.go +++ b/cardRGB.go @@ -7,6 +7,9 @@ See: https://apple2online.com/web_documents/Video-7%20Manual%20KB.pdf https://mirrors.apple2.org.za/ftp.apple.asimov.net/documentation/hardware/video/DIGICARD%2064K%20Extended%2080%20Column%20RGB%20Card%20for%20Apple%20IIe%20Instruction%20Manual.pdf +Diagnostics disk: + https://mirrors.apple2.org.za/ftp.apple.asimov.net/images/hardware/video/Video-7%20Apple%20II%20RGB%20Demo%20%28Video-7%2C%20Inc.%29%281984%29.dsk + It goes to the 80 column slot. To set the state it AN3 in graphics mode has to go off-on-off-on. Each pair off-on record the state of 80col: diff --git a/screen.go b/screen.go index eeeb195..4a5b9cd 100644 --- a/screen.go +++ b/screen.go @@ -27,7 +27,8 @@ const ( videoRGBText40 uint8 = 0x10 videoMono560 uint8 = 0x11 videoRGBMix uint8 = 0x12 - videoSHR uint8 = 0x13 + videoRGB160 uint8 = 0x13 + videoSHR uint8 = 0x14 // Modifiers videoBaseMask uint8 = 0x1f @@ -47,6 +48,8 @@ func getCurrentVideoMode(a *Apple2) uint8 { rgbFlag2 := a.io.isSoftSwitchActive(ioFlag2RGBCard) isMono560 := isDoubleResMode && !rgbFlag1 && !rgbFlag2 isRGBMixMode := isDoubleResMode && !rgbFlag1 && rgbFlag2 + isRGB160Mode := isDoubleResMode && rgbFlag1 && !rgbFlag2 + isMixMode := a.io.isSoftSwitchActive(ioFlagMixed) mode := uint8(0) @@ -71,6 +74,8 @@ func getCurrentVideoMode(a *Apple2) uint8 { mode = videoMono560 } else if isRGBMixMode { mode = videoRGBMix + } else if isRGB160Mode { + mode = videoRGB160 } else { mode = videoDHGR } @@ -137,6 +142,8 @@ func snapshotByMode(a *Apple2, videoMode uint8) *image.RGBA { applyNTSCFilter = false case videoRGBMix: snap, ntscMask = snapshotDoubleHiResModeMono(a, isSecondPage, true /*isRGBMixMode*/, lightColor) + case videoRGB160: + snap = snapshotDoubleHiRes160ModeMono(a, isSecondPage, lightColor) case videoSHR: snap = snapshotSuperHiResMode(a) applyNTSCFilter = false diff --git a/screenDebugParts.go b/screenDebugParts.go index 739e785..d664f27 100644 --- a/screenDebugParts.go +++ b/screenDebugParts.go @@ -63,6 +63,8 @@ func (a *Apple2) VideoModeName() string { applyNTSCFilter = false case videoRGBMix: name = "RGMMIX" + case videoRGB160: + name = "RGB160" case videoSHR: name = "SHR" applyNTSCFilter = false @@ -89,21 +91,23 @@ func (a *Apple2) VideoModeName() string { } func mixFourSnapshots(snaps []*image.RGBA) *image.RGBA { - size := image.Rect(0, 0, hiResWidth*4, hiResHeight*2) + width := snaps[0].Rect.Dx() + height := snaps[0].Rect.Dy() + size := image.Rect(0, 0, width*2, height*2) out := image.NewRGBA(size) - for i := 0; i < 4; i++ { - if snaps[i].Bounds().Dx() < hiResWidth*2 { + for i := 1; i < 4; i++ { + if snaps[i].Bounds().Dx() < width { snaps[i] = doubleWidthFilter(snaps[i]) } } - for y := 0; y < hiResHeight; y++ { - for x := 0; x < hiResWidth*2; x++ { + for y := 0; y < height; y++ { + for x := 0; x < width; x++ { out.Set(x, y, snaps[0].At(x, y)) - out.Set(x+hiResWidth*2, y, snaps[1].At(x, y)) - out.Set(x, y+hiResHeight, snaps[2].At(x, y)) - out.Set(x+hiResWidth*2, y+hiResHeight, snaps[3].At(x, y)) + out.Set(x+width, y, snaps[1].At(x, y)) + out.Set(x, y+height, snaps[2].At(x, y)) + out.Set(x+width, y+height, snaps[3].At(x, y)) } } diff --git a/screenDoubleHiRes.go b/screenDoubleHiRes.go index 8321c18..4233788 100644 --- a/screenDoubleHiRes.go +++ b/screenDoubleHiRes.go @@ -7,6 +7,7 @@ import ( const ( doubleHiResWidth = 2 * hiResWidth + rgb160Width = 4 * 160 ) func snapshotDoubleHiResModeMono(a *Apple2, isSecondPage bool, getNTSCMask bool, light color.Color) (*image.RGBA, *image.Alpha) { @@ -62,3 +63,32 @@ func snapshotDoubleHiResModeMono(a *Apple2, isSecondPage bool, getNTSCMask bool, } return img, ntscMask } + +func snapshotDoubleHiRes160ModeMono(a *Apple2, isSecondPage bool, light color.Color) *image.RGBA { + size := image.Rect(0, 0, rgb160Width, hiResHeight) + img := image.NewRGBA(size) + + for y := 0; y < hiResHeight; y++ { + lineParts := [][]uint8{ + getHiResLine(a, y, isSecondPage, true /*auxmem*/), + getHiResLine(a, y, isSecondPage, false /*auxmem*/), + } + x := 0 + for iByte := 0; iByte < hiResLineBytes; iByte++ { + for iPart := 0; iPart < 2; iPart++ { + b := lineParts[iPart][iByte] + for j := uint(0); j < 8; j++ { + // Set color + bit := (b >> j) & 1 + colour := light + if bit == 0 { + colour = color.Black + } + img.Set(x, y, colour) + x++ + } + } + } + } + return img +} diff --git a/screenLoRes.go b/screenLoRes.go index c95af85..1b046f4 100644 --- a/screenLoRes.go +++ b/screenLoRes.go @@ -73,8 +73,8 @@ func renderGrMode(data []uint8, isDoubleResMode bool, light color.Color) *image. if isDoubleResMode && ((c % 2) == 0) { // See "Understanding the Apple II", page 8-44 - // Even blocks color are rotated left on bit - offset = offset + 3 + // Even blocks color are rotated left one bit + offset = offset + 3 // Equivalent to -1 } // Insert the pixelWidth pixels required diff --git a/screenNtscFilter.go b/screenNtscFilter.go index 19f2a29..c90705b 100644 --- a/screenNtscFilter.go +++ b/screenNtscFilter.go @@ -52,13 +52,15 @@ func filterNTSCColor(in *image.RGBA, mask *image.Alpha) *image.RGBA { colorMap := ntscColorMap // or rgbColorMap b := in.Bounds() - size := image.Rect(0, 0, b.Dx()+3, b.Dy()) + width := b.Dx() + height := b.Dy() + size := image.Rect(0, 0, width+4, height) out := image.NewRGBA(size) - for y := b.Min.Y; y < b.Max.Y; y++ { + for y := 0; y < height; y++ { // We store the last four bits. We start with 0000 v := 0 - for x := b.Min.X; x < b.Dx(); x++ { + for x := 0; x < width; x++ { cIn := in.At(x, y) r, _, _, _ := cIn.RGBA() @@ -82,7 +84,7 @@ func filterNTSCColor(in *image.RGBA, mask *image.Alpha) *image.RGBA { } // We fade for the last three positions - for x := b.Dx(); x < b.Max.X; x++ { + for x := width; x < width+4; x++ { v >>= 1 cOut := colorMap[v] out.Set(x, y, cOut)