mirror of
https://github.com/JetSetIlly/Gopher2600.git
synced 2025-04-02 11:02:17 -04:00
o sdl
- added faded metavideo layer for incomplete frames
This commit is contained in:
parent
8d1797a938
commit
c424a4a24b
14 changed files with 233 additions and 207 deletions
2
FUTURE
2
FUTURE
|
@ -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
|
||||
|
||||
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
76
debugger/metavideo.go
Normal 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
|
||||
}
|
|
@ -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
|
||||
}
|
34
gui/gui.go
34
gui/gui.go
|
@ -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
|
||||
|
|
17
gui/metavideo/metavideo.go
Normal file
17
gui/metavideo/metavideo.go
Normal 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
|
||||
}
|
|
@ -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)
|
||||
}
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Add table
Reference in a new issue