izapple2/screen/testScenarios.go

185 lines
4.1 KiB
Go

package screen
import (
"encoding/json"
"fmt"
"image"
"image/color"
"image/png"
"os"
"strings"
)
// TestScenario is the computer video state
type TestScenario struct {
VideoMode uint16 `json:"mode"`
VideoModeName string `json:"name"`
ScreenModes []int `json:"screens"`
TextPages [4][]uint8 `json:"text"`
VideoPages [4][]uint8 `json:"video"`
SVideoPage []uint8 `json:"svideo"`
}
func grabTestScenario(vs VideoSource) *TestScenario {
textPages := [4][]uint8{
cloneSlice(vs.GetTextMemory(false, false)),
cloneSlice(vs.GetTextMemory(false, true)),
cloneSlice(vs.GetTextMemory(true, false)),
cloneSlice(vs.GetTextMemory(true, true)),
}
videoPages := [4][]uint8{
cloneSlice(vs.GetVideoMemory(false, false)),
cloneSlice(vs.GetVideoMemory(false, true)),
cloneSlice(vs.GetVideoMemory(true, false)),
cloneSlice(vs.GetVideoMemory(true, true)),
}
knownModes := []int{
ScreenModeGreen,
ScreenModeNTSC,
ScreenModePlain,
}
return &TestScenario{
vs.GetCurrentVideoMode(),
VideoModeName(vs),
knownModes,
textPages,
videoPages,
cloneSlice(vs.GetSuperVideoMemory()),
}
}
func cloneSlice(src []uint8) []uint8 {
dst := make([]uint8, len(src))
copy(dst, src)
return dst
}
func loadTestScenario(filename string) (*TestScenario, error) {
bytes, err := os.ReadFile(filename)
if err != nil {
return nil, err
}
var ts TestScenario
err = json.Unmarshal(bytes, &ts)
if err != nil {
return nil, err
}
return &ts, nil
}
func (ts *TestScenario) save(dir string) (string, error) {
bytes, err := json.Marshal(ts)
if err != nil {
return "", err
}
pattern := fmt.Sprintf("%v_*.json", strings.ToLower(ts.VideoModeName))
file, err := os.CreateTemp(dir, pattern)
if err != nil {
return "", err
}
defer file.Close()
_, err = file.Write(bytes)
return file.Name(), err
}
// GetCurrentVideoMode returns the active video mode
func (ts *TestScenario) GetCurrentVideoMode() uint16 {
return ts.VideoMode
}
func optionsToIndex(secondPage bool, ext bool) int {
index := 0
if secondPage {
index += 2
}
if ext {
index++
}
return index
}
// GetTextMemory returns a slice to the text memory pages
func (ts *TestScenario) GetTextMemory(secondPage bool, ext bool) []uint8 {
return ts.TextPages[optionsToIndex(secondPage, ext)]
}
// GetVideoMemory returns a slice to the video memory pages
func (ts *TestScenario) GetVideoMemory(secondPage bool, ext bool) []uint8 {
return ts.VideoPages[optionsToIndex(secondPage, ext)]
}
// GetCharacterPixel returns the pixel as output by the character generator
func (ts *TestScenario) GetCharacterPixel(char uint8, rowInChar int, colInChar int, isAltText bool, isFlashedFrame bool) bool {
// We don't have a character generator. We will return a square or blank for spaces
if char&0x3f == 0x20 {
return false // Space char
}
return !(rowInChar == 0 || rowInChar == 7 || colInChar == 0 || colInChar == 6)
}
// GetSuperVideoMemory returns a slice to the SHR video memory
func (ts *TestScenario) GetSuperVideoMemory() []uint8 {
return ts.SVideoPage
}
// GetCardImage returns an image provided by a card, like the videx card
func (ts *TestScenario) GetCardImage(light color.Color) *image.RGBA {
return nil
}
func buildImageName(name string, screenMode int, altSet bool) string {
var screenName string
switch screenMode {
case ScreenModeGreen:
screenName = "green"
case ScreenModeNTSC:
screenName = "ntsc"
case ScreenModePlain:
screenName = "plain"
default:
screenName = "unknown"
}
if altSet {
screenName += "_new"
}
return strings.TrimSuffix(name, ".json") +
screenName + ".png"
}
func (ts *TestScenario) generateSnapshots(baseName string, altSet bool) error {
for _, screen := range ts.ScreenModes {
image := Snapshot(ts, screen)
imageName := buildImageName(baseName, screen, altSet)
f, err := os.Create(imageName)
if err != nil {
return err
}
defer f.Close()
png.Encode(f, image)
}
return nil
}
// AddScenario Generate a new video scenario
func AddScenario(vs VideoSource, dir string) error {
// Get memory contents
ts := grabTestScenario(vs)
name, err := ts.save(dir)
if err != nil {
return err
}
return ts.generateSnapshots(name, false)
}