Support for video7 RGB 160*192 video mode

This commit is contained in:
Ivan Izaguirre 2020-08-09 16:42:16 +02:00
parent d47b0a5e28
commit 62d0a35b3e
7 changed files with 63 additions and 16 deletions

View File

@ -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()
}

View File

@ -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:

View File

@ -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

View File

@ -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))
}
}

View File

@ -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
}

View File

@ -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

View File

@ -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)