-
Notifications
You must be signed in to change notification settings - Fork 20
/
protocol.go
170 lines (154 loc) · 6.15 KB
/
protocol.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
// This file is part of Gopher2600.
//
// Gopher2600 is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Gopher2600 is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Gopher2600. If not, see <https://www.gnu.org/licenses/>.
package television
import (
"github.com/jetsetilly/gopher2600/hardware/television/signal"
)
// PixelRenderer implementations displays, or otherwise works with, visual
// information from a television. For example digest.Video
//
// PixelRenderer implementations often find it convenient to maintain a reference to
// the parent Television implementation and maybe even embed the Television
// interface. ie.
//
// type ExampleTV struct {
// television.Television
// ...
// }
//
// The most useful source of information though is the FrameInfo type supplied
// to the PixelRenderer through the Resize() and NewFrame() functions. A
// current copy of this information is also available from the television type
// GetFrameInfo() function
type PixelRenderer interface {
// NewFrame is called at the start of a new frame
//
// Renderers should be prepared to resize the rendering display to either a
// smaller or larger frame size
NewFrame(FrameInfo) error
// NewScanline is called at the start of a new scanline
NewScanline(scanline int) error
// SetPixels is used to Render a series of signals. The number of signals
// will always be television.MaxSignalHistory
//
// Producing a 2d image from the signals sent by SetPixels() can easily be
// done by first allocating a bitmap of width specification.ClksScanline
// and height specification.AbsoluateMaxScanlines. This bitmap will have
// television.MaxSignalHistory entries
//
// Every signal from SetPixels() therefore corresponds to a pixel in the
// bitmap - the first entry always referes to the top-left pixel
//
// Setting the color of a pixel can be done by extracting the ColorSignal
// from the SignalAttributes (see signal package)
//
// The last parameter indicates the index of the array entry that was most
// recently set. This is useful to know when showing televison images when
// the emulation is paused. All entries upto and including last are from
// teh *current* frame. All entries afterwards are from the *previous*
// frame
//
// If the entry contains signal.NoSignal then that screen pixel has not
// been written to recently
//
// For renderers that are producing an accurate visual image, the pixel
// should always be set to video black if VBLANK is on. Some renderers
// however may find it useful to set the pixel to the RGB value regardless
// of VBLANK
//
// A very important note is that some ROMs use VBLANK to control pixel
// color within the visible display area. For example:
//
// * Custer's Revenge
// * Ladybug
// * ET (turns VBLANK off late on scanline 40)
//
// In other words, the PixelRenderer should not simply assume VBLANK is
// restricted to the "off-screen" areas as defined by the FrameInfo sent to
// Resize()
SetPixels(sig []signal.SignalAttributes, last int) error
// Reset all pixels. Called when TV is reset.
//
// Note that a Reset event does not imply a Resize() event. Implementations
// should not call the Resize() function as a byproduct of a Reset(). The
// television will send an explicit Resize() request if it is appropriate
Reset()
// Some renderers may need to conclude and/or dispose of resources gently
EndRendering() error
}
// PixelRendererFPSCap is an extension to the PixelRenderer interface. Pixel
// renderers that implement this interface will be notified when the
// television's frame capping policy is changed
type PixelRendererFPSCap interface {
SetFPSCap(limit bool)
}
// FrameTrigger implementations listen for Pause events
type PauseTrigger interface {
Pause(pause bool) error
}
// FrameTrigger implementations listen for NewFrame events. FrameTrigger is a
// subset of PixelRenderer
type FrameTrigger interface {
NewFrame(FrameInfo) error
}
// ScanlineTrigger implementations listen for NewScanline events. It is a
// subset of PixelRenderer
type ScanlineTrigger interface {
NewScanline(FrameInfo) error
}
// AudioMixer implementations work with sound; most probably playing it. An
// example of an AudioMixer that does not play sound but otherwise works with
// it is the digest.Audio type
type AudioMixer interface {
// for efficiency reasons, SetAudio() implementations can be sent
// SignalAttributes values that do not have valid AudioData (ie.
// AudioUpdate bit is zero). implemenations should therefore take care when
// processing the sig slice
//
// the general algorithm for processing the sig slice is:
//
// for _, s := range sig {
// if s&signal.AudioUpdate != signal.AudioUpdate {
// continue
// }
// d := uint8((s & signal.AudioData) >> signal.AudioDataShift)
//
// ...
// }
SetAudio(sig []signal.SignalAttributes) error
// some mixers may need to conclude and/or dispose of resources gently.
// for simplicity, the AudioMixer should be considered unusable after
// EndMixing() has been called
EndMixing() error
// Reset buffered audio and anything else that might need doing on, for
// example, a cartridge change
Reset()
}
// RealtimeAudioMixer is an extension for the AudioMixer interface.
// Implementations of this interface expect to be given more audio data on
// demand
//
// MoreAudio() is called periodically (every scanline) and the implementation
// should return true if more audio data is required immediately
type RealtimeAudioMixer interface {
AudioMixer
MoreAudio() bool
}
// VCSReturnChannel is used to send information from the TV back to the parent
// console. Named because I think of it as being similar to the Audio Return
// Channel (ARC) present in modern TVs
type VCSReturnChannel interface {
SetClockSpeed(tvSpec string) error
}