Support monochrome graphics

This commit is contained in:
Ivan Izaguirre 2019-04-26 18:08:30 +02:00
parent d4d47f3968
commit 1196890c18
8 changed files with 150 additions and 39 deletions

View File

@ -85,6 +85,10 @@ func (p *ioC0Page) internalPeek(address uint8) uint8 {
return 0
}
func (p *ioC0Page) all() []uint8 {
return nil
}
func (p *ioC0Page) Poke(address uint8, value uint8) {
//fmt.Printf("Poke on $C0%02x with %02x ", address, value)
ss := p.softSwitchesW[address]

View File

@ -20,6 +20,7 @@ type memoryPage interface {
Peek(uint8) uint8
Poke(uint8, uint8)
internalPeek(uint8) uint8
all() []uint8
}
const (
@ -43,6 +44,10 @@ func (mmu *memoryManager) internalPeek(address uint16) uint8 {
return mmu.activeMemory[hi].internalPeek(lo)
}
func (mmu *memoryManager) internalPage(hi uint8) []uint8 {
return mmu.activeMemory[hi].all()
}
// Poke sets the data at the given address
func (mmu *memoryManager) Poke(address uint16, value uint8) {
if address == ioC8Off {

View File

@ -22,6 +22,10 @@ func (p *rxmPage) internalPeek(address uint8) uint8 {
return p.data[address]
}
func (p *rxmPage) all() []uint8 {
return p.data[:]
}
func (p *rxmPage) Poke(address uint8, value uint8) {
p.touch(address, true)
p.data[address] = value

View File

@ -10,18 +10,29 @@ import (
// Snapshot the currently visible screen
func Snapshot(a *Apple2) *image.RGBA {
isTextMode := a.io.isSoftSwitchActive(ioFlagGraphics)
isTextMode := a.io.isSoftSwitchActive(ioFlagText)
is80ColMode := a.io.isSoftSwitchActive(ioFlag80Col)
isHiResMode := a.io.isSoftSwitchActive(ioFlagHiRes)
pageIndex := 0
if a.io.isSoftSwitchActive(ioFlagSecondPage) {
pageIndex = 1
}
if isTextMode && !is80ColMode {
//Text mode
return snapshotTextMode(a, pageIndex)
if isTextMode {
if is80ColMode {
// Not supported
} else {
return snapshotTextMode(a, pageIndex)
}
} else {
if isHiResMode {
return snapshotGraphMode(a, pageIndex)
} else {
// Not supported
}
}
fmt.Printf("t: %v, 8: %v\n", isTextMode, is80ColMode)
//fmt.Printf("g: %v, 8: %v, h: %v\n", isTextMode, is80ColMode, isHiResMode)
return nil
//panic("Screen mode not supported")
}
@ -44,29 +55,39 @@ func saveSnapshot(a *Apple2) {
}
const (
charWidth = 7
charHeight = 8
textColumns = 40
textLines = 24
textPage1Address = uint16(0x400)
textPage2Address = uint16(0x400)
charWidth = 7
charHeight = 8
textColumns = 40
textLines = 24
textPage1Address = uint16(0x0400)
textPage2Address = uint16(0x0800)
graphWidth = 280
graphHeight = 192
graphPage1Address = uint16(0x2000)
graphPage2Address = uint16(0x4000)
)
func getTextCharOffset(col int, line int) uint16 {
// See "Understand the Apple II", page 5-10
// http://www.applelogic.org/files/UNDERSTANDINGTHEAII.pdf
section := line / 8 // Top, middle and bottom
eigth := line % 8
return uint16(section*40 + eigth*0x80 + col)
}
func getTextChar(a *Apple2, col int, line int, page int) uint8 {
address := textPage1Address
if page == 1 {
address = textPage2Address
}
// See "Understand the Apple II", page 5-10
// http://www.applelogic.org/files/UNDERSTANDINGTHEAII.pdf
section := line / 8 // Top, middle and bottom
eigth := line % 8
address += uint16(section*40 + eigth*0x80 + col)
address += getTextCharOffset(col, line)
return a.mmu.internalPeek(address)
}
func snapshotTextMode(a *Apple2, page int) *image.RGBA {
// TODO: Missing inverse and flash modes
width := textColumns * charWidth
height := textLines * charHeight
size := image.Rect(0, 0, width, height)
@ -90,3 +111,51 @@ func snapshotTextMode(a *Apple2, page int) *image.RGBA {
return img
}
func getGraphLineOffset(line int) uint16 {
// See "Understand the Apple II", page 5-14
// http://www.applelogic.org/files/UNDERSTANDINGTHEAII.pdf
section := line >> 6 // Top, middle and bottom
outerEigth := (line >> 3) & 0x07
innerEigth := line & 0x07
return uint16(section*40 + outerEigth*0x80 + innerEigth*0x400)
}
func getGraphLine(a *Apple2, line int, page int) []uint8 {
address := graphPage1Address
if page == 1 {
address = graphPage2Address
}
address += getGraphLineOffset(line)
hi := uint8(address >> 8)
lo := uint8(address)
memPage := a.mmu.internalPage(hi)
//fmt.Printf("line: %v, lo: %x\n", line, lo)
return memPage[lo : lo+40]
}
func snapshotGraphMode(a *Apple2, page int) *image.RGBA {
size := image.Rect(0, 0, graphWidth, graphHeight)
img := image.NewRGBA(size)
for y := 0; y < graphHeight; 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
}

24
apple2/screen_test.go Normal file
View File

@ -0,0 +1,24 @@
package apple2
import (
"testing"
)
func TestGetGraphLineOffest(t *testing.T) {
scenarios := map[int]uint16{
0: 0x2000,
1: 0x2400,
8: 0x2080,
63: 0x3f80,
64: 0x2028,
128: 0x2050,
191: 0x3fd0,
}
for in, want := range scenarios {
got := 0x2000 + getGraphLineOffset(in)
if want != got {
t.Errorf("expected %x but got %x for line %v", want, got, in)
}
}
}

View File

@ -3,7 +3,7 @@ package apple2
const (
ioDataKeyboard uint8 = 0x10
ioFlagGraphics uint8 = 0x50
ioFlagText uint8 = 0x50
ioFlagMixed uint8 = 0x52
ioFlagSecondPage uint8 = 0x54
ioFlagHiRes uint8 = 0x56
@ -33,8 +33,8 @@ func addApple2SoftSwitches(io *ioC0Page) {
// for read and write. But the Apple2e take over some of them, with
// the prevention on acting only on writes.
io.addSoftSwitchRW(0x50, getSoftSwitch(ioFlagGraphics, false))
io.addSoftSwitchRW(0x51, getSoftSwitch(ioFlagGraphics, true))
io.addSoftSwitchRW(0x50, getSoftSwitch(ioFlagText, false))
io.addSoftSwitchRW(0x51, getSoftSwitch(ioFlagText, true))
io.addSoftSwitchRW(0x52, getSoftSwitch(ioFlagMixed, false))
io.addSoftSwitchRW(0x53, getSoftSwitch(ioFlagMixed, true))
io.addSoftSwitchRW(0x54, getSoftSwitch(ioFlagSecondPage, false))

View File

@ -14,6 +14,10 @@ func (p *unassignedPage) internalPeek(address uint8) uint8 {
return 0xdd
}
func (p *unassignedPage) all() []uint8 {
return nil
}
func (p *unassignedPage) Poke(address uint8, value uint8) {
//fmt.Printf("Write on address 0x%02x%02x\n", p.page, address)
//panic(address)

View File

@ -42,26 +42,27 @@ func SDLRun(a *apple2.Apple2) {
}
}
img := *apple2.Snapshot(a)
surface, err := sdl.CreateRGBSurfaceFrom(unsafe.Pointer(&img.Pix[0]), 40*7, 24*8, 32, 40*7*4,
0xff000000, 0x00ff0000, 0x0000ff00, 0x000000ff)
if err != nil {
panic(err)
img := apple2.Snapshot(a)
if img != nil {
surface, err := sdl.CreateRGBSurfaceFrom(unsafe.Pointer(&img.Pix[0]), 40*7, 24*8, 32, 40*7*4,
0xff000000, 0x00ff0000, 0x0000ff00, 0x000000ff)
if err != nil {
panic(err)
}
texture, err := renderer.CreateTextureFromSurface(surface)
if err != nil {
panic(err)
}
renderer.Clear()
w, h := window.GetSize()
renderer.Copy(texture, nil, &sdl.Rect{X: 0, Y: 0, W: w, H: h})
renderer.Present()
surface.Free()
texture.Destroy()
}
texture, err := renderer.CreateTextureFromSurface(surface)
if err != nil {
panic(err)
}
renderer.Clear()
w, h := window.GetSize()
renderer.Copy(texture, nil, &sdl.Rect{X: 0, Y: 0, W: w, H: h})
renderer.Present()
surface.Free()
texture.Destroy()
sdl.Delay(1000 / 60)
}