mirror of
https://github.com/ivanizag/izapple2.git
synced 2025-01-03 11:30:29 +00:00
Support monochrome graphics
This commit is contained in:
parent
d4d47f3968
commit
1196890c18
@ -85,6 +85,10 @@ func (p *ioC0Page) internalPeek(address uint8) uint8 {
|
|||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (p *ioC0Page) all() []uint8 {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
func (p *ioC0Page) Poke(address uint8, value uint8) {
|
func (p *ioC0Page) Poke(address uint8, value uint8) {
|
||||||
//fmt.Printf("Poke on $C0%02x with %02x ", address, value)
|
//fmt.Printf("Poke on $C0%02x with %02x ", address, value)
|
||||||
ss := p.softSwitchesW[address]
|
ss := p.softSwitchesW[address]
|
||||||
|
@ -20,6 +20,7 @@ type memoryPage interface {
|
|||||||
Peek(uint8) uint8
|
Peek(uint8) uint8
|
||||||
Poke(uint8, uint8)
|
Poke(uint8, uint8)
|
||||||
internalPeek(uint8) uint8
|
internalPeek(uint8) uint8
|
||||||
|
all() []uint8
|
||||||
}
|
}
|
||||||
|
|
||||||
const (
|
const (
|
||||||
@ -43,6 +44,10 @@ func (mmu *memoryManager) internalPeek(address uint16) uint8 {
|
|||||||
return mmu.activeMemory[hi].internalPeek(lo)
|
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
|
// Poke sets the data at the given address
|
||||||
func (mmu *memoryManager) Poke(address uint16, value uint8) {
|
func (mmu *memoryManager) Poke(address uint16, value uint8) {
|
||||||
if address == ioC8Off {
|
if address == ioC8Off {
|
||||||
|
@ -22,6 +22,10 @@ func (p *rxmPage) internalPeek(address uint8) uint8 {
|
|||||||
return p.data[address]
|
return p.data[address]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (p *rxmPage) all() []uint8 {
|
||||||
|
return p.data[:]
|
||||||
|
}
|
||||||
|
|
||||||
func (p *rxmPage) Poke(address uint8, value uint8) {
|
func (p *rxmPage) Poke(address uint8, value uint8) {
|
||||||
p.touch(address, true)
|
p.touch(address, true)
|
||||||
p.data[address] = value
|
p.data[address] = value
|
||||||
|
@ -10,18 +10,29 @@ import (
|
|||||||
|
|
||||||
// Snapshot the currently visible screen
|
// Snapshot the currently visible screen
|
||||||
func Snapshot(a *Apple2) *image.RGBA {
|
func Snapshot(a *Apple2) *image.RGBA {
|
||||||
isTextMode := a.io.isSoftSwitchActive(ioFlagGraphics)
|
isTextMode := a.io.isSoftSwitchActive(ioFlagText)
|
||||||
is80ColMode := a.io.isSoftSwitchActive(ioFlag80Col)
|
is80ColMode := a.io.isSoftSwitchActive(ioFlag80Col)
|
||||||
|
isHiResMode := a.io.isSoftSwitchActive(ioFlagHiRes)
|
||||||
pageIndex := 0
|
pageIndex := 0
|
||||||
if a.io.isSoftSwitchActive(ioFlagSecondPage) {
|
if a.io.isSoftSwitchActive(ioFlagSecondPage) {
|
||||||
pageIndex = 1
|
pageIndex = 1
|
||||||
}
|
}
|
||||||
|
|
||||||
if isTextMode && !is80ColMode {
|
if isTextMode {
|
||||||
//Text mode
|
if is80ColMode {
|
||||||
|
// Not supported
|
||||||
|
} else {
|
||||||
return snapshotTextMode(a, pageIndex)
|
return snapshotTextMode(a, pageIndex)
|
||||||
}
|
}
|
||||||
fmt.Printf("t: %v, 8: %v\n", isTextMode, is80ColMode)
|
} else {
|
||||||
|
if isHiResMode {
|
||||||
|
return snapshotGraphMode(a, pageIndex)
|
||||||
|
} else {
|
||||||
|
// Not supported
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//fmt.Printf("g: %v, 8: %v, h: %v\n", isTextMode, is80ColMode, isHiResMode)
|
||||||
return nil
|
return nil
|
||||||
//panic("Screen mode not supported")
|
//panic("Screen mode not supported")
|
||||||
}
|
}
|
||||||
@ -48,25 +59,35 @@ const (
|
|||||||
charHeight = 8
|
charHeight = 8
|
||||||
textColumns = 40
|
textColumns = 40
|
||||||
textLines = 24
|
textLines = 24
|
||||||
textPage1Address = uint16(0x400)
|
textPage1Address = uint16(0x0400)
|
||||||
textPage2Address = uint16(0x400)
|
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 {
|
func getTextChar(a *Apple2, col int, line int, page int) uint8 {
|
||||||
address := textPage1Address
|
address := textPage1Address
|
||||||
if page == 1 {
|
if page == 1 {
|
||||||
address = textPage2Address
|
address = textPage2Address
|
||||||
}
|
}
|
||||||
|
address += getTextCharOffset(col, line)
|
||||||
// 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)
|
|
||||||
return a.mmu.internalPeek(address)
|
return a.mmu.internalPeek(address)
|
||||||
}
|
}
|
||||||
|
|
||||||
func snapshotTextMode(a *Apple2, page int) *image.RGBA {
|
func snapshotTextMode(a *Apple2, page int) *image.RGBA {
|
||||||
|
// TODO: Missing inverse and flash modes
|
||||||
|
|
||||||
width := textColumns * charWidth
|
width := textColumns * charWidth
|
||||||
height := textLines * charHeight
|
height := textLines * charHeight
|
||||||
size := image.Rect(0, 0, width, height)
|
size := image.Rect(0, 0, width, height)
|
||||||
@ -90,3 +111,51 @@ func snapshotTextMode(a *Apple2, page int) *image.RGBA {
|
|||||||
|
|
||||||
return img
|
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
24
apple2/screen_test.go
Normal 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)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -3,7 +3,7 @@ package apple2
|
|||||||
const (
|
const (
|
||||||
ioDataKeyboard uint8 = 0x10
|
ioDataKeyboard uint8 = 0x10
|
||||||
|
|
||||||
ioFlagGraphics uint8 = 0x50
|
ioFlagText uint8 = 0x50
|
||||||
ioFlagMixed uint8 = 0x52
|
ioFlagMixed uint8 = 0x52
|
||||||
ioFlagSecondPage uint8 = 0x54
|
ioFlagSecondPage uint8 = 0x54
|
||||||
ioFlagHiRes uint8 = 0x56
|
ioFlagHiRes uint8 = 0x56
|
||||||
@ -33,8 +33,8 @@ func addApple2SoftSwitches(io *ioC0Page) {
|
|||||||
// for read and write. But the Apple2e take over some of them, with
|
// for read and write. But the Apple2e take over some of them, with
|
||||||
// the prevention on acting only on writes.
|
// the prevention on acting only on writes.
|
||||||
|
|
||||||
io.addSoftSwitchRW(0x50, getSoftSwitch(ioFlagGraphics, false))
|
io.addSoftSwitchRW(0x50, getSoftSwitch(ioFlagText, false))
|
||||||
io.addSoftSwitchRW(0x51, getSoftSwitch(ioFlagGraphics, true))
|
io.addSoftSwitchRW(0x51, getSoftSwitch(ioFlagText, true))
|
||||||
io.addSoftSwitchRW(0x52, getSoftSwitch(ioFlagMixed, false))
|
io.addSoftSwitchRW(0x52, getSoftSwitch(ioFlagMixed, false))
|
||||||
io.addSoftSwitchRW(0x53, getSoftSwitch(ioFlagMixed, true))
|
io.addSoftSwitchRW(0x53, getSoftSwitch(ioFlagMixed, true))
|
||||||
io.addSoftSwitchRW(0x54, getSoftSwitch(ioFlagSecondPage, false))
|
io.addSoftSwitchRW(0x54, getSoftSwitch(ioFlagSecondPage, false))
|
||||||
|
@ -14,6 +14,10 @@ func (p *unassignedPage) internalPeek(address uint8) uint8 {
|
|||||||
return 0xdd
|
return 0xdd
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (p *unassignedPage) all() []uint8 {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
func (p *unassignedPage) Poke(address uint8, value uint8) {
|
func (p *unassignedPage) Poke(address uint8, value uint8) {
|
||||||
//fmt.Printf("Write on address 0x%02x%02x\n", p.page, address)
|
//fmt.Printf("Write on address 0x%02x%02x\n", p.page, address)
|
||||||
//panic(address)
|
//panic(address)
|
||||||
|
@ -42,7 +42,8 @@ func SDLRun(a *apple2.Apple2) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
img := *apple2.Snapshot(a)
|
img := apple2.Snapshot(a)
|
||||||
|
if img != nil {
|
||||||
surface, err := sdl.CreateRGBSurfaceFrom(unsafe.Pointer(&img.Pix[0]), 40*7, 24*8, 32, 40*7*4,
|
surface, err := sdl.CreateRGBSurfaceFrom(unsafe.Pointer(&img.Pix[0]), 40*7, 24*8, 32, 40*7*4,
|
||||||
0xff000000, 0x00ff0000, 0x0000ff00, 0x000000ff)
|
0xff000000, 0x00ff0000, 0x0000ff00, 0x000000ff)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -61,7 +62,7 @@ func SDLRun(a *apple2.Apple2) {
|
|||||||
|
|
||||||
surface.Free()
|
surface.Free()
|
||||||
texture.Destroy()
|
texture.Destroy()
|
||||||
|
}
|
||||||
sdl.Delay(1000 / 60)
|
sdl.Delay(1000 / 60)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user