mirror of
https://github.com/ivanizag/izapple2.git
synced 2024-12-31 21:31:41 +00:00
Save GIFs on headless mode
This commit is contained in:
parent
dcc1597cb2
commit
695eaa603b
5
.gitignore
vendored
5
.gitignore
vendored
@ -4,4 +4,7 @@ a2sdl.exe
|
||||
frontend/a2sdl/a2sdl
|
||||
frontend/a2sdl/*.woz
|
||||
frontend/a2sdl/*.dsk
|
||||
frontend/a2fyne/a2fyne
|
||||
frontend/a2fyne/a2fyne
|
||||
frontend/headless/headless
|
||||
frontend/*/snapshot.gif
|
||||
frontend/*/snapshot.png
|
@ -3,8 +3,10 @@ package main
|
||||
import (
|
||||
"bufio"
|
||||
"fmt"
|
||||
"image/gif"
|
||||
"os"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/ivanizag/izapple2"
|
||||
"github.com/ivanizag/izapple2/screen"
|
||||
@ -88,6 +90,9 @@ func main() {
|
||||
case "return":
|
||||
fe.keyChannel <- 13
|
||||
|
||||
case "gif":
|
||||
SaveGif(a, "snapshot.gif")
|
||||
|
||||
case "help":
|
||||
fmt.Print(`
|
||||
Available commands:
|
||||
@ -99,6 +104,7 @@ Available commands:
|
||||
Key or k: Sends a key to the emulator
|
||||
Keys or ks: Sends a string to the emulator
|
||||
Return or r: Sends a return to the emulator
|
||||
GIF or gif: Captures a GIF animation
|
||||
Help: Prints this help
|
||||
`)
|
||||
default:
|
||||
@ -107,6 +113,40 @@ Available commands:
|
||||
}
|
||||
}
|
||||
|
||||
func SaveGif(a *izapple2.Apple2, filename string) error {
|
||||
animation := gif.GIF{}
|
||||
|
||||
delay := 50 * time.Millisecond
|
||||
delayHundredsS := 5
|
||||
frames := 20 // 1 second
|
||||
|
||||
planned := time.Now()
|
||||
for i := 0; i < frames; i++ {
|
||||
lapse := planned.Sub(time.Now())
|
||||
fmt.Printf("%v\n", lapse)
|
||||
if lapse > 0 {
|
||||
time.Sleep(lapse)
|
||||
}
|
||||
|
||||
fmt.Printf("%v\n", time.Now())
|
||||
img := screen.SnapshotPaletted(a, screen.ScreenModeNTSC)
|
||||
animation.Image = append(animation.Image, img)
|
||||
animation.Delay = append(animation.Delay, delayHundredsS)
|
||||
|
||||
planned = planned.Add(delay)
|
||||
}
|
||||
|
||||
f, err := os.Create(filename)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer f.Close()
|
||||
|
||||
gif.EncodeAll(f, &animation)
|
||||
return nil
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
Uses the console to send commands and queries to an emulated machine.
|
||||
*/
|
||||
|
@ -30,6 +30,21 @@ var ntscColorMap = [16]color.Color{
|
||||
color.RGBA{255, 255, 255, 255}, // White
|
||||
}
|
||||
|
||||
var attenuatedColorMap = buildAttenuatedColorMap(ntscColorMap)
|
||||
|
||||
func buildAttenuatedColorMap(colorMap [16]color.Color) [16]color.Color {
|
||||
colors := [16]color.Color{}
|
||||
for i := 0; i < len(colorMap); i++ {
|
||||
r, g, b, _ := colorMap[i].RGBA()
|
||||
colors[i] = color.RGBA64{
|
||||
uint16(r / 2), uint16(g / 2), uint16(b / 2),
|
||||
65535,
|
||||
}
|
||||
}
|
||||
return colors
|
||||
}
|
||||
|
||||
/*
|
||||
var rgbColorMap = [16]color.Color{
|
||||
color.RGBA{0, 0, 0, 255}, // Black
|
||||
color.RGBA{221, 0, 51, 255}, // Magenta
|
||||
@ -48,18 +63,13 @@ var rgbColorMap = [16]color.Color{
|
||||
color.RGBA{68, 255, 153, 255}, // Aquamarine
|
||||
color.RGBA{255, 255, 255, 255}, // White
|
||||
}
|
||||
*/
|
||||
|
||||
func filterNTSCColor(in *image.RGBA, mask *image.Alpha, screenMode int) *image.RGBA {
|
||||
colorMap := ntscColorMap // or rgbColorMap
|
||||
attenuatedColorMap := ntscColorMap
|
||||
colorMapLow := ntscColorMap
|
||||
if screenMode == ScreenModeNTSC {
|
||||
for i := 0; i < len(colorMap); i++ {
|
||||
r, g, b, _ := colorMap[i].RGBA()
|
||||
attenuatedColorMap[i] = color.RGBA64{
|
||||
uint16(r / 2), uint16(g / 2), uint16(b / 2),
|
||||
65535,
|
||||
}
|
||||
}
|
||||
colorMapLow = attenuatedColorMap
|
||||
}
|
||||
|
||||
b := in.Bounds()
|
||||
@ -90,7 +100,7 @@ func filterNTSCColor(in *image.RGBA, mask *image.Alpha, screenMode int) *image.R
|
||||
if r != 0 {
|
||||
cOut = colorMap[v]
|
||||
} else {
|
||||
cOut = attenuatedColorMap[v]
|
||||
cOut = colorMapLow[v]
|
||||
}
|
||||
if mask != nil {
|
||||
// RGB mode7
|
||||
|
@ -36,6 +36,16 @@ func Snapshot(vs VideoSource, screenMode int) *image.RGBA {
|
||||
return snap
|
||||
}
|
||||
|
||||
// SnapshotPaletted, snapshot of the currently visible screen as a paletted image
|
||||
func SnapshotPaletted(vs VideoSource, screenMode int) *image.Paletted {
|
||||
img := Snapshot(vs, screenMode)
|
||||
return palletedFilter(img)
|
||||
}
|
||||
|
||||
// Color for typical Apple ][ period green P1 phosphor monitors
|
||||
// See: https://superuser.com/questions/361297/what-colour-is-the-dark-green-on-old-fashioned-green-screen-computer-displays
|
||||
var greenPhosphorColor = color.RGBA{65, 255, 0, 255}
|
||||
|
||||
func snapshotByMode(vs VideoSource, videoMode uint16, screenMode int) *image.RGBA {
|
||||
videoBase := videoMode & VideoBaseMask
|
||||
mixMode := videoMode & VideoMixTextMask
|
||||
@ -44,9 +54,7 @@ func snapshotByMode(vs VideoSource, videoMode uint16, screenMode int) *image.RGB
|
||||
|
||||
var lightColor color.Color = color.White
|
||||
if screenMode == ScreenModeGreen {
|
||||
// Color for typical Apple ][ period green P1 phosphor monitors
|
||||
// See: https://superuser.com/questions/361297/what-colour-is-the-dark-green-on-old-fashioned-green-screen-computer-displays
|
||||
lightColor = color.RGBA{65, 255, 0, 255}
|
||||
lightColor = greenPhosphorColor
|
||||
}
|
||||
|
||||
applyNTSCFilter := screenMode != ScreenModeGreen
|
||||
@ -170,3 +178,21 @@ func linesSeparatedFilter(in *image.RGBA) *image.RGBA {
|
||||
}
|
||||
return out
|
||||
}
|
||||
|
||||
func palletedFilter(in *image.RGBA) *image.Paletted {
|
||||
bounds := in.Bounds()
|
||||
outBounds := image.Rect(0, 0, bounds.Dx()*2, bounds.Dy())
|
||||
palette := []color.Color{color.Black, color.White, greenPhosphorColor}
|
||||
palette = append(palette, ntscColorMap[:]...)
|
||||
palette = append(palette, attenuatedColorMap[:]...)
|
||||
paletted := image.NewPaletted(outBounds, palette)
|
||||
|
||||
for y := bounds.Min.Y; y < bounds.Max.Y; y++ {
|
||||
for x := bounds.Min.X; x < bounds.Max.X; x++ {
|
||||
c := in.At(x, y)
|
||||
paletted.Set(x*2, y, c)
|
||||
paletted.Set(x*2+1, y, c)
|
||||
}
|
||||
}
|
||||
return paletted
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user