- added faded metavideo layer for incomplete frames
This commit is contained in:
steve 2019-07-17 17:53:15 +01:00
parent 8d1797a938
commit c424a4a24b
14 changed files with 233 additions and 207 deletions

2
FUTURE
View file

@ -36,8 +36,6 @@ o display of colors in the terminal (check for 256 color terminal)
sdl screen
----------
o faded copy of metasignal overlay for incomplete frames (when halted)
o info under mouse. floating tooltip

View file

@ -1023,7 +1023,7 @@ func (dbg *Debugger) enactCommand(tokens *commandline.Tokens, interactive bool)
return doNothing, err
}
case "METASIGNALS":
err = dbg.gui.SetFeature(gui.ReqToggleShowMetaPixels)
err = dbg.gui.SetFeature(gui.ReqToggleShowMetaVideo)
if err != nil {
return doNothing, err
}

View file

@ -4,7 +4,6 @@ import (
"fmt"
"gopher2600/debugger/commandline"
"gopher2600/debugger/console"
"gopher2600/debugger/metavideo"
"gopher2600/debugger/script"
"gopher2600/disassembly"
"gopher2600/errors"
@ -50,9 +49,9 @@ type Debugger struct {
// metavideo is additional information about the emulation state (ie.
// if a sprite was reset or if WSYNC is active, etc.)
//
// videomon.Check() is called every video cycle to inform the gui of
// metavideo.Check() is called every video cycle to inform the gui of
// the metainformation of the last television signal
videomon *metavideo.Monitor
metavideo *metavideoMonitor
// halt conditions
breakpoints *breakpoints
@ -169,8 +168,8 @@ func NewDebugger(tvType string) (*Debugger, error) {
// set up debugging interface to memory
dbg.dbgmem = &memoryDebug{mem: dbg.vcs.Mem, symtable: &dbg.disasm.Symtable}
// set up metapixel monitor
dbg.videomon = &metavideo.Monitor{Mem: dbg.vcs.Mem, MC: dbg.vcs.CPU, Rend: dbg.vcs.TV}
// set up metavideo monitor
dbg.metavideo = &metavideoMonitor{Mem: dbg.vcs.Mem, MC: dbg.vcs.CPU, Renderer: dbg.gui}
// set up breakpoints/traps
dbg.breakpoints = newBreakpoints(dbg)
@ -298,7 +297,7 @@ func (dbg *Debugger) videoCycle(result *result.Instruction) error {
dbg.trapMessages = dbg.traps.check(dbg.trapMessages)
dbg.watchMessages = dbg.watches.check(dbg.watchMessages)
return dbg.videomon.Check()
return dbg.metavideo.Check()
}
// inputLoop has two modes, defined by the videoCycle argument. when

View file

@ -32,7 +32,7 @@ func (dbg *Debugger) guiEventHandler(event gui.Event) error {
err = dbg.gui.SetFeature(gui.ReqToggleAltColors)
case "2":
// toggle metasignals overlay
err = dbg.gui.SetFeature(gui.ReqToggleShowMetaPixels)
err = dbg.gui.SetFeature(gui.ReqToggleShowMetaVideo)
case "=":
fallthrough // equal sign is the same as plus, for convenience

76
debugger/metavideo.go Normal file
View file

@ -0,0 +1,76 @@
package debugger
import (
"gopher2600/gui/metavideo"
"gopher2600/hardware/cpu"
"gopher2600/hardware/memory"
)
// metavideoMonitor watches for writes to specific video related memory locations. when
// these locations are written to, a MetaSignal is sent to the Renderer
// implementation.
type metavideoMonitor struct {
Mem *memory.VCSMemory
MC *cpu.CPU
Renderer metavideo.Renderer
// the emulation doesn't access memory every video cycle. we do check if it
// every cycle however, so we need a way of filtering out false-positives
// indicators that a memory address has been triggered.
lastAddress uint16
}
// Check should be called every video cycle to record the current state of the
// emulation/system
func (mv *metavideoMonitor) Check() error {
var err error
var sig metavideo.MetaSignalAttributes
// special handling of WSYNC signal - we want every pixel to be coloured
// while the RdyFlag is false, not just when WSYNC is first triggered.
if !mv.MC.RdyFlg {
sig = metavideo.MetaSignalAttributes{Label: "WSYNC", Red: 0, Green: 0, Blue: 255}
err = mv.Renderer.MetaSignal(sig)
if err != nil {
return err
}
return nil
}
if mv.Mem.LastAccessWrite && mv.Mem.LastAccessAddress != mv.lastAddress {
sendSignal := true
switch mv.Mem.LastAccessAddress {
case 0x03: // RSYNC
sig = metavideo.MetaSignalAttributes{Label: "RSYNC", Red: 255, Green: 0, Blue: 0}
case 0x2a: // HMOVE
sig = metavideo.MetaSignalAttributes{Label: "HMOVE", Red: 0, Green: 255, Blue: 0}
case 0x10:
sig = metavideo.MetaSignalAttributes{Label: "RESP0", Red: 0, Green: 255, Blue: 255}
case 0x11:
sig = metavideo.MetaSignalAttributes{Label: "RESP1", Red: 0, Green: 255, Blue: 255}
case 0x12:
sig = metavideo.MetaSignalAttributes{Label: "RESM0", Red: 0, Green: 255, Blue: 255}
case 0x13:
sig = metavideo.MetaSignalAttributes{Label: "RESM1", Red: 0, Green: 255, Blue: 255}
case 0x14:
sig = metavideo.MetaSignalAttributes{Label: "RESBL", Red: 0, Green: 255, Blue: 255}
case 0x2b:
sig = metavideo.MetaSignalAttributes{Label: "HMCLR", Red: 255, Green: 0, Blue: 255}
default:
sendSignal = false
}
if sendSignal {
err = mv.Renderer.MetaSignal(sig)
if err != nil {
return err
}
}
// note address
mv.lastAddress = mv.Mem.LastAccessAddress
}
return nil
}

View file

@ -1,91 +0,0 @@
package metavideo
import (
"gopher2600/hardware/cpu"
"gopher2600/hardware/memory"
)
// MetaSignalAttributes contains information about the last television signal. it is up to
// the Renderer to match this up with the last television signal
type MetaSignalAttributes struct {
Label string
// Renderer implementations are free to use the color information
// as they wish (adding alpha information seems a probable scenario).
Red, Green, Blue byte
}
// Renderer implementations will add signal information to a presentation layer
// somehow.
type Renderer interface {
MetaSignal(MetaSignalAttributes) error
}
// Monitor watches for writes to specific video related memory locations. when
// these locations are written to, a MetaSignal is sent to the Renderer
// implementation.
type Monitor struct {
Mem *memory.VCSMemory
MC *cpu.CPU
Rend Renderer
// the emulation doesn't access memory every video cycle. we do check if it
// every cycle however, so we need a way of filtering out false-positives
// indicators that a memory address has been triggered.
lastAddress uint16
}
// Check should be called every video cycle to record the current state of the
// emulation/system
func (mon *Monitor) Check() error {
var err error
var sig MetaSignalAttributes
// special handling of WSYNC signal - we want every pixel to be coloured
// while the RdyFlag is false, not just when WSYNC is first triggered.
if !mon.MC.RdyFlg {
sig = MetaSignalAttributes{Label: "WSYNC", Red: 0, Green: 0, Blue: 255}
err = mon.Rend.MetaSignal(sig)
if err != nil {
return err
}
return nil
}
if mon.Mem.LastAccessWrite && mon.Mem.LastAccessAddress != mon.lastAddress {
sendSignal := true
switch mon.Mem.LastAccessAddress {
case 0x03: // RSYNC
sig = MetaSignalAttributes{Label: "RSYNC", Red: 255, Green: 0, Blue: 0}
case 0x2a: // HMOVE
sig = MetaSignalAttributes{Label: "HMOVE", Red: 0, Green: 255, Blue: 0}
case 0x10:
sig = MetaSignalAttributes{Label: "RESP0", Red: 0, Green: 255, Blue: 255}
case 0x11:
sig = MetaSignalAttributes{Label: "RESP1", Red: 0, Green: 255, Blue: 255}
case 0x12:
sig = MetaSignalAttributes{Label: "RESM0", Red: 0, Green: 255, Blue: 255}
case 0x13:
sig = MetaSignalAttributes{Label: "RESM1", Red: 0, Green: 255, Blue: 255}
case 0x14:
sig = MetaSignalAttributes{Label: "RESBL", Red: 0, Green: 255, Blue: 255}
case 0x2b:
sig = MetaSignalAttributes{Label: "HMCLR", Red: 255, Green: 0, Blue: 255}
default:
sendSignal = false
}
if sendSignal {
err = mon.Rend.MetaSignal(sig)
if err != nil {
return err
}
}
// note address
mon.lastAddress = mon.Mem.LastAccessAddress
}
return nil
}

View file

@ -1,32 +1,36 @@
package gui
import "gopher2600/television"
import (
"gopher2600/gui/metavideo"
"gopher2600/television"
)
// FeatureReq is used to request the setting of a gui attribute
// eg. toggling the metapixel layer
// eg. toggling the metavideo layer
type FeatureReq int
// list of valid feature requests
const (
ReqSetVisibility FeatureReq = iota // bool, optional bool (update on show)
ReqSetVisibilityStable // none
ReqSetAllowDebugging // bool
ReqSetPause // bool
ReqSetMasking // bool
ReqToggleMasking // none
ReqSetAltColors // bool
ReqToggleAltColors // none
ReqSetShowMetaPixels // bool
ReqToggleShowMetaPixels // none
ReqSetScale // float
ReqIncScale // none
ReqDecScale // none
ReqSetVisibility FeatureReq = iota // bool, optional bool (update on show)
ReqSetVisibilityStable // none
ReqSetAllowDebugging // bool
ReqSetPause // bool
ReqSetMasking // bool
ReqToggleMasking // none
ReqSetAltColors // bool
ReqToggleAltColors // none
ReqSetShowMetaVideo // bool
ReqToggleShowMetaVideo // none
ReqSetScale // float
ReqIncScale // none
ReqDecScale // none
)
// GUI defines the operations that can be performed on GUIs
type GUI interface {
television.Television
television.Renderer
metavideo.Renderer
// returns true if GUI is currently visible. false if not
IsVisible() bool

View file

@ -0,0 +1,17 @@
package metavideo
// Renderer implementations will add signal information to a presentation layer
// somehow.
type Renderer interface {
MetaSignal(MetaSignalAttributes) error
}
// MetaSignalAttributes contains information about the last television signal. it is up to
// the Renderer to match this up with the last television signal
type MetaSignalAttributes struct {
Label string
// Renderer implementations are free to use the color information
// as they wish (adding alpha information seems a probable scenario).
Red, Green, Blue byte
}

View file

@ -1,7 +1,7 @@
package sdl
import (
"gopher2600/debugger/metavideo"
"gopher2600/gui/metavideo"
"github.com/veandco/go-sdl2/sdl"
)
@ -9,66 +9,102 @@ import (
type metaVideoOverlay struct {
scr *screen
pixels []byte
texture *sdl.Texture
texture *sdl.Texture
textureFade *sdl.Texture
pixels []byte
pixelsFade []byte
labels [][]string
}
func newMetaVideoOverlay(scr *screen) (*metaVideoOverlay, error) {
mpx := new(metaVideoOverlay)
mpx.scr = scr
mv := new(metaVideoOverlay)
mv.scr = scr
// our acutal screen data
mpx.pixels = make([]byte, mpx.scr.maxWidth*mpx.scr.maxHeight*scrDepth)
mv.pixels = make([]byte, mv.scr.maxWidth*mv.scr.maxHeight*scrDepth)
mv.pixelsFade = make([]byte, mv.scr.maxWidth*mv.scr.maxHeight*scrDepth)
// labels
mpx.labels = make([][]string, mpx.scr.maxHeight)
for i := 0; i < len(mpx.labels); i++ {
mpx.labels[i] = make([]string, mpx.scr.maxWidth)
mv.labels = make([][]string, mv.scr.maxHeight)
for i := 0; i < len(mv.labels); i++ {
mv.labels[i] = make([]string, mv.scr.maxWidth)
}
var err error
mpx.texture, err = scr.renderer.CreateTexture(uint32(sdl.PIXELFORMAT_ABGR8888), int(sdl.TEXTUREACCESS_STREAMING), int32(mpx.scr.maxWidth), int32(mpx.scr.maxHeight))
mv.texture, err = scr.renderer.CreateTexture(uint32(sdl.PIXELFORMAT_ABGR8888), int(sdl.TEXTUREACCESS_STREAMING), int32(mv.scr.maxWidth), int32(mv.scr.maxHeight))
if err != nil {
return nil, err
}
mpx.texture.SetAlphaMod(100)
mpx.texture.SetBlendMode(sdl.BlendMode(sdl.BLENDMODE_BLEND))
mv.texture.SetBlendMode(sdl.BlendMode(sdl.BLENDMODE_BLEND))
mv.texture.SetAlphaMod(100)
return mpx, nil
mv.textureFade, err = scr.renderer.CreateTexture(uint32(sdl.PIXELFORMAT_ABGR8888), int(sdl.TEXTUREACCESS_STREAMING), int32(mv.scr.maxWidth), int32(mv.scr.maxHeight))
if err != nil {
return nil, err
}
mv.textureFade.SetBlendMode(sdl.BlendMode(sdl.BLENDMODE_BLEND))
mv.textureFade.SetAlphaMod(50)
return mv, nil
}
func (mpx *metaVideoOverlay) setPixel(sig metavideo.MetaSignalAttributes) error {
i := (mpx.scr.lastY*mpx.scr.maxWidth + mpx.scr.lastX) * scrDepth
func (mv *metaVideoOverlay) setPixel(sig metavideo.MetaSignalAttributes) error {
i := (mv.scr.lastY*mv.scr.maxWidth + mv.scr.lastX) * scrDepth
if i >= int32(len(mpx.pixels)) {
if i >= int32(len(mv.pixels)) {
return nil
}
mpx.pixels[i] = sig.Red
mpx.pixels[i+1] = sig.Green
mpx.pixels[i+2] = sig.Blue
mpx.pixels[i+3] = 255
mv.pixels[i] = sig.Red
mv.pixels[i+1] = sig.Green
mv.pixels[i+2] = sig.Blue
mv.pixels[i+3] = 255
// silently allow empty labels
mpx.labels[mpx.scr.lastY][mpx.scr.lastX] = sig.Label
mv.labels[mv.scr.lastY][mv.scr.lastX] = sig.Label
return nil
}
func (mpx *metaVideoOverlay) clearPixels() {
for i := 0; i < len(mpx.pixels); i++ {
mpx.pixels[i] = 0
func (mv *metaVideoOverlay) newFrame() {
// swap pixel array with pixelsFade array
// -- see comment in sdl.screen.newFrame() function for why we do this
swp := mv.pixels
mv.pixels = mv.pixelsFade
mv.pixelsFade = swp
// clear regular pixels
for i := 0; i < len(mv.pixels); i++ {
mv.pixels[i] = 0
}
}
func (mpx *metaVideoOverlay) update() error {
err := mpx.texture.Update(nil, mpx.pixels, int(mpx.scr.maxWidth*scrDepth))
func (mv *metaVideoOverlay) update(paused bool) error {
if paused {
err := mv.textureFade.Update(nil, mv.pixelsFade, int(mv.scr.maxWidth*scrDepth))
if err != nil {
return err
}
err = mv.scr.renderer.Copy(mv.textureFade, mv.scr.srcRect, mv.scr.destRect)
if err != nil {
return err
}
}
err := mv.texture.Update(nil, mv.pixels, int(mv.scr.maxWidth*scrDepth))
if err != nil {
return err
}
err = mv.scr.renderer.Copy(mv.texture, mv.scr.srcRect, mv.scr.destRect)
if err != nil {
return err
}
return nil
}
@ -79,10 +115,5 @@ func (gtv *GUI) MetaSignal(sig metavideo.MetaSignalAttributes) error {
return nil
}
err := gtv.Television.MetaSignal(sig)
if err != nil {
return err
}
return gtv.scr.metaPixels.setPixel(sig)
return gtv.scr.metaVideo.setPixel(sig)
}

View file

@ -51,12 +51,12 @@ func (gtv *GUI) SetFeature(request gui.FeatureReq, args ...interface{}) error {
gtv.scr.useAltPixels = !gtv.scr.useAltPixels
gtv.update()
case gui.ReqSetShowMetaPixels:
gtv.scr.showMetaPixels = args[0].(bool)
case gui.ReqSetShowMetaVideo:
gtv.scr.showMetaVideo = args[0].(bool)
gtv.update()
case gui.ReqToggleShowMetaPixels:
gtv.scr.showMetaPixels = !gtv.scr.showMetaPixels
case gui.ReqToggleShowMetaVideo:
gtv.scr.showMetaVideo = !gtv.scr.showMetaVideo
gtv.update()
case gui.ReqSetScale:

View file

@ -3,6 +3,7 @@ package sdl
import (
"gopher2600/errors"
"gopher2600/performance/limiter"
"gopher2600/television"
"github.com/veandco/go-sdl2/sdl"
)
@ -12,7 +13,8 @@ import (
const scrDepth int32 = 4
type screen struct {
gtv *GUI
gtv *GUI
spec *television.Specification
// regulates how often the screen is updated
fpsLimiter *limiter.FpsLimiter
@ -74,9 +76,9 @@ type screen struct {
// overlay for screen showing metasignal information
// -- always allocated but only used when tv.allowDebugging and
// showMetaPixels are true
metaPixels *metaVideoOverlay
showMetaPixels bool
// showMetaVideo are true
metaVideo *metaVideoOverlay
showMetaVideo bool
}
func newScreen(gtv *GUI) (*screen, error) {
@ -107,7 +109,7 @@ func newScreen(gtv *GUI) (*screen, error) {
scr.stb = newScreenStabiliser(scr)
// new overlay
scr.metaPixels, err = newMetaVideoOverlay(scr)
scr.metaVideo, err = newMetaVideoOverlay(scr)
if err != nil {
return nil, err
}
@ -118,14 +120,14 @@ func newScreen(gtv *GUI) (*screen, error) {
func (scr *screen) changeTVSpec() error {
var err error
spec := scr.gtv.GetSpec()
scr.spec = scr.gtv.GetSpec()
scr.maxWidth = int32(spec.ClocksPerScanline)
scr.maxHeight = int32(spec.ScanlinesTotal)
scr.maxWidth = int32(scr.spec.ClocksPerScanline)
scr.maxHeight = int32(scr.spec.ScanlinesTotal)
scr.maxMask = &sdl.Rect{X: 0, Y: 0, W: scr.maxWidth, H: scr.maxHeight}
scr.playWidth = int32(spec.ClocksPerVisible)
scr.setPlayArea(int32(spec.ScanlinesPerVisible), int32(spec.ScanlinesPerVBlank+spec.ScanlinesPerVSync))
scr.playWidth = int32(scr.spec.ClocksPerVisible)
scr.setPlayArea(int32(scr.spec.ScanlinesPerVisible), int32(scr.spec.ScanlinesPerVBlank+scr.spec.ScanlinesPerVSync))
// pixelWidth is the number of tv pixels per color clock. we don't need to
// worry about this again once we've created the window and set the scaling
@ -158,7 +160,7 @@ func (scr *screen) changeTVSpec() error {
scr.altPixelsFade = make([]byte, scr.maxWidth*scr.maxHeight*scrDepth)
// frame limiter
scr.fpsLimiter, err = limiter.NewFPSLimiter(int(spec.FramesPerSecond))
scr.fpsLimiter, err = limiter.NewFPSLimiter(int(scr.spec.FramesPerSecond))
if err != nil {
return errors.NewFormattedError(errors.SDL, err)
}
@ -170,7 +172,7 @@ func (scr *screen) changeTVSpec() error {
func (scr *screen) setPlayArea(scanlines int32, top int32) error {
scr.playHeight = scanlines
scr.playDstMask = &sdl.Rect{X: 0, Y: 0, W: scr.playWidth, H: scr.playHeight}
scr.playSrcMask = &sdl.Rect{X: int32(scr.gtv.GetSpec().ClocksPerHblank), Y: top, W: scr.playWidth, H: scr.playHeight}
scr.playSrcMask = &sdl.Rect{X: int32(scr.spec.ClocksPerHblank), Y: top, W: scr.playWidth, H: scr.playHeight}
return scr.setMasking(scr.unmasked)
}
@ -317,18 +319,12 @@ func (scr *screen) update(paused bool) error {
if scr.unmasked {
scr.renderer.SetDrawColor(100, 100, 100, 20)
scr.renderer.SetDrawBlendMode(sdl.BlendMode(sdl.BLENDMODE_BLEND))
spec := scr.gtv.GetSpec()
scr.renderer.FillRect(&sdl.Rect{X: 0, Y: 0, W: int32(spec.ClocksPerHblank), H: int32(spec.ScanlinesTotal)})
scr.renderer.FillRect(&sdl.Rect{X: 0, Y: 0, W: int32(scr.spec.ClocksPerHblank), H: int32(scr.spec.ScanlinesTotal)})
}
// show metasignal overlay
if scr.gtv.allowDebugging && scr.showMetaPixels {
err = scr.metaPixels.update()
if err != nil {
return err
}
err = scr.renderer.Copy(scr.metaPixels.texture, scr.srcRect, scr.destRect)
if scr.gtv.allowDebugging && scr.showMetaVideo {
err = scr.metaVideo.update(paused)
if err != nil {
return err
}
@ -343,7 +339,7 @@ func (scr *screen) update(paused bool) error {
// cursor is one step ahead of pixel -- move to new scanline if
// necessary
if x >= scr.gtv.GetSpec().ClocksPerScanline+scr.gtv.GetSpec().ClocksPerHblank {
if x >= scr.spec.ClocksPerScanline+scr.spec.ClocksPerHblank {
x = 0
y++
}
@ -383,29 +379,28 @@ func (scr *screen) update(paused bool) error {
return nil
}
func (scr *screen) clearPixels(fade bool) {
func (scr *screen) newFrame() {
if scr.gtv.allowDebugging {
// clear pixels in additional overlays
scr.metaPixels.clearPixels()
// swap pixel array with pixelsFade array
// -- note that we don't do this with the texture instead because
// updating the the extra texture if we don't need to (faded pixels
// only show when the emulation is paused) is expensive
swp := scr.pixels
scr.pixels = scr.pixelsFade
scr.pixelsFade = swp
if fade {
// "fade" alternative pixels and clear
swp := scr.altPixels
scr.altPixels = scr.altPixelsFade
scr.altPixelsFade = swp
for i := 0; i < len(scr.altPixels); i++ {
scr.altPixels[i] = 0
}
// clear pixels in metavideo overlay
scr.metaVideo.newFrame()
// "fade" regular pixels
swp = scr.pixels
scr.pixels = scr.pixelsFade
scr.pixelsFade = swp
} else {
// clear "faded" pixels
for i := 0; i < len(scr.pixelsFade); i++ {
scr.pixelsFade[i] = 0
}
// swap pixel array with pixelsFade array
// -- see comment above
swp = scr.altPixels
scr.altPixels = scr.altPixelsFade
scr.altPixelsFade = swp
// clear altpixels
for i := 0; i < len(scr.altPixels); i++ {
scr.altPixels[i] = 0
}
}

View file

@ -90,7 +90,6 @@ func NewGUI(tvType string, scale float32, tv television.Television) (gui.GUI, er
// update the gui so that it reflects changes to buffered data in the tv struct
func (gtv *GUI) update() error {
// abbrogate most of the updating to the screen instance
err := gtv.scr.update(gtv.paused)
if err != nil {
return err
@ -113,12 +112,19 @@ func (gtv *GUI) ChangeTVSpec() error {
// NewFrame implements television.Renderer interface
func (gtv *GUI) NewFrame(frameNum int) error {
defer gtv.scr.clearPixels(true)
err := gtv.scr.stb.stabiliseFrame()
if err != nil {
return err
}
return gtv.update()
err = gtv.update()
if err != nil {
return err
}
gtv.scr.newFrame()
return nil
}
// NewScanline implements television.Renderer interface
@ -145,7 +151,7 @@ func (gtv *GUI) Reset() error {
if err != nil {
return err
}
gtv.scr.clearPixels(false)
gtv.scr.newFrame()
gtv.scr.lastX = 0
gtv.scr.lastY = 0
return nil

View file

@ -2,7 +2,6 @@ package television
import (
"fmt"
"gopher2600/debugger/metavideo"
"gopher2600/errors"
"strings"
)
@ -291,11 +290,6 @@ func (btv *BasicTelevision) Signal(sig SignalAttributes) error {
return nil
}
// MetaSignal recieves (and processes) additional emulator information from the emulator
func (btv *BasicTelevision) MetaSignal(metavideo.MetaSignalAttributes) error {
return nil
}
// GetState returns the TVState object for the named state. television
// implementations in other packages will difficulty extending this function
// because TVStateReq does not expose its members. (although it may need to if

View file

@ -1,7 +1,5 @@
package television
import "gopher2600/debugger/metavideo"
// StateReq is used to identify which television attribute is being asked
// with the GetState() function
type StateReq int
@ -56,7 +54,6 @@ type Television interface {
Reset() error
Signal(SignalAttributes) error
MetaSignal(metavideo.MetaSignalAttributes) error
GetState(StateReq) (int, error)
GetSpec() *Specification