mirror of
https://github.com/ivanizag/izapple2.git
synced 2024-12-22 09:30:19 +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
|
||||
}
|
||||
|
||||
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]
|
||||
|
@ -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 {
|
||||
|
@ -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
|
||||
|
103
apple2/screen.go
103
apple2/screen.go
@ -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
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 (
|
||||
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))
|
||||
|
@ -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)
|
||||
|
@ -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)
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user