2020-10-16 18:41:34 +00:00
|
|
|
package screen
|
2019-05-12 17:22:32 +00:00
|
|
|
|
|
|
|
import (
|
|
|
|
"image"
|
2019-05-12 22:17:31 +00:00
|
|
|
"image/color"
|
2019-05-12 17:22:32 +00:00
|
|
|
)
|
|
|
|
|
|
|
|
const (
|
2019-11-08 23:44:13 +00:00
|
|
|
loResPixelWidth = charWidth * 2
|
|
|
|
doubleLoResPixelWidth = charWidth
|
|
|
|
loResPixelHeight = charHeight / 2
|
2019-05-12 17:22:32 +00:00
|
|
|
)
|
|
|
|
|
2019-05-12 22:17:31 +00:00
|
|
|
func getColorPatterns(light color.Color) [16][16]color.Color {
|
|
|
|
/*
|
|
|
|
For each lores pixel we have to fill 14 half mono pixels with
|
|
|
|
the 4 bits of the color repeated. We will need to shift by 2 bits
|
|
|
|
on the odd columns. Lets prepare 14+2 values for each color.
|
|
|
|
*/
|
|
|
|
|
|
|
|
var data [16][16]color.Color
|
|
|
|
|
|
|
|
for ci := 0; ci < 16; ci++ {
|
|
|
|
for cb := uint8(0); cb < 4; cb++ {
|
|
|
|
bit := (ci >> cb) & 1
|
|
|
|
var colour color.Color
|
|
|
|
if bit == 0 {
|
|
|
|
colour = color.Black
|
|
|
|
} else {
|
|
|
|
colour = light
|
|
|
|
}
|
|
|
|
for i := uint8(0); i < 4; i++ {
|
|
|
|
data[ci][cb+4*i] = colour
|
|
|
|
}
|
2019-05-12 17:22:32 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
return data
|
2019-05-12 22:17:31 +00:00
|
|
|
|
2019-05-12 17:22:32 +00:00
|
|
|
}
|
|
|
|
|
2020-10-16 18:41:34 +00:00
|
|
|
func snapshotLoRes(vs VideoSource, isSecondPage bool, light color.Color) *image.RGBA {
|
|
|
|
data := getTextFromMemory(vs, isSecondPage, false)
|
|
|
|
return renderGr(data, false /*isMeres*/, light)
|
2020-08-08 17:23:35 +00:00
|
|
|
}
|
|
|
|
|
2020-10-16 18:41:34 +00:00
|
|
|
func snapshotMeRes(vs VideoSource, isSecondPage bool, light color.Color) *image.RGBA {
|
|
|
|
data := getText80FromMemory(vs, isSecondPage)
|
|
|
|
return renderGr(data, true /*isMeres*/, light)
|
2020-08-08 17:23:35 +00:00
|
|
|
}
|
|
|
|
|
2020-10-16 18:41:34 +00:00
|
|
|
func renderGr(data []uint8, isDoubleResMode bool, light color.Color) *image.RGBA {
|
2020-08-08 17:23:35 +00:00
|
|
|
grLines := textLines * 2
|
|
|
|
columns := len(data) / textLines
|
2019-11-08 23:44:13 +00:00
|
|
|
pixelWidth := loResPixelWidth
|
|
|
|
if isDoubleResMode {
|
|
|
|
pixelWidth = doubleLoResPixelWidth
|
|
|
|
}
|
2019-05-12 17:22:32 +00:00
|
|
|
|
2019-11-08 23:44:13 +00:00
|
|
|
size := image.Rect(0, 0, columns*pixelWidth, grLines*loResPixelHeight)
|
2019-05-12 17:22:32 +00:00
|
|
|
img := image.NewRGBA(size)
|
|
|
|
|
2019-05-12 22:17:31 +00:00
|
|
|
patterns := getColorPatterns(light)
|
2019-11-08 22:56:54 +00:00
|
|
|
for l := 0; l < grLines; l++ {
|
|
|
|
for c := 0; c < columns; c++ {
|
2020-08-08 17:23:35 +00:00
|
|
|
char := data[(l/2)*columns+c]
|
2019-11-08 22:56:54 +00:00
|
|
|
grPixel := char >> 4
|
|
|
|
if l%2 == 0 {
|
|
|
|
grPixel = char & 0xf
|
|
|
|
}
|
2019-11-08 23:44:13 +00:00
|
|
|
// We place pixelWidth mono pixels per graphic pixel.
|
2020-08-08 11:44:45 +00:00
|
|
|
// The groups of 4 mono pixels need to be aligned with an offset to get plain surfaces
|
2019-11-08 23:44:13 +00:00
|
|
|
offset := (c * pixelWidth) % 4
|
2019-05-12 22:17:31 +00:00
|
|
|
|
2020-04-05 15:02:11 +00:00
|
|
|
if isDoubleResMode && ((c % 2) == 0) {
|
|
|
|
// See "Understanding the Apple II", page 8-44
|
2020-08-09 14:42:16 +00:00
|
|
|
// Even blocks color are rotated left one bit
|
|
|
|
offset = offset + 3 // Equivalent to -1
|
2020-04-05 15:02:11 +00:00
|
|
|
}
|
|
|
|
|
2019-11-08 23:44:13 +00:00
|
|
|
// Insert the pixelWidth pixels required
|
|
|
|
for i := 0; i < pixelWidth; i++ {
|
2019-11-08 22:56:54 +00:00
|
|
|
v := patterns[grPixel][i+offset]
|
2019-05-12 22:17:31 +00:00
|
|
|
// Repeat the same color for 4 lines
|
|
|
|
for r := 0; r < loResPixelHeight; r++ {
|
2020-04-05 15:02:11 +00:00
|
|
|
img.Set(c*pixelWidth+i, l*4+r, v)
|
2019-05-12 17:22:32 +00:00
|
|
|
}
|
|
|
|
}
|
2019-11-08 22:56:54 +00:00
|
|
|
|
2019-05-12 17:22:32 +00:00
|
|
|
}
|
|
|
|
}
|
2019-11-08 22:56:54 +00:00
|
|
|
|
2019-05-12 17:22:32 +00:00
|
|
|
return img
|
|
|
|
}
|