Initial commit

This commit is contained in:
Alex D. 2023-03-12 13:43:32 +00:00
commit c240d1ed40
Signed by: caskd
GPG Key ID: F92BA85F61F4C173
3 changed files with 165 additions and 0 deletions

7
go.mod Normal file
View File

@ -0,0 +1,7 @@
module git.redxen.eu/caskd/v6canvas
go 1.20
require golang.org/x/net v0.8.0
require golang.org/x/sys v0.6.0 // indirect

4
go.sum Normal file
View File

@ -0,0 +1,4 @@
golang.org/x/net v0.8.0 h1:Zrh2ngAOFYneWTAIAPethzeaQLuHwhuBkuV6ZiRnUaQ=
golang.org/x/net v0.8.0/go.mod h1:QVkue5JL9kW//ek3r6jTKnTFis1tRmNAW2P1shuFdJc=
golang.org/x/sys v0.6.0 h1:MVltZSvRTcU2ljQOhs94SXPftV6DCNnZViHeQps87pQ=
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=

154
main.go Normal file
View File

@ -0,0 +1,154 @@
package main
import (
"flag"
"fmt"
"image"
"image/color"
_ "image/png"
"os"
"sync"
"time"
"log"
"net"
"golang.org/x/net/icmp"
"golang.org/x/net/ipv6"
)
func main() {
var (
dt uint
err error
)
flag.UintVar(&dt, "timeout", 5000, "Frame display time (ms)")
flag.Parse()
var (
up = make(chan image.Image)
lo = make(chan image.Image)
dx = make(chan pixdelta)
)
c, err := icmp.ListenPacket("udp6", "::")
if err != nil {
log.Fatalln("Failed to listen for ICMP packets:", err)
}
go sendDelta(dx, c)
go syncColors(up, lo, dx)
var imgs [2]image.Image
for i := range imgs {
imgs[i] = image.NewRGBA(image.Rect(0, 0, 511, 511))
}
for _, v := range flag.Args() {
f, err := os.Open(v)
if err != nil {
log.Fatalln("Failed to open image:", err)
}
imgs[0] = imgs[1]
imgs[1], _, err = image.Decode(f)
if err != nil {
log.Fatalln("Failed to decode image:", err)
}
up <- imgs[0]
lo <- imgs[1]
time.Sleep(time.Duration(dt) * time.Millisecond)
}
}
func sendDelta(d chan pixdelta, c *icmp.PacketConn) {
pm := icmp.Message{
Type: ipv6.ICMPTypeEchoRequest, Code: 0,
Body: &icmp.Echo{Seq: 1},
}
bb, err := pm.Marshal(nil)
if err != nil {
log.Fatalln("Failed to encode ICMP packet")
}
for {
select {
case delta := <-d:
dest := &net.UDPAddr{
IP: convV6(delta.p, delta.c),
}
if _, err := c.WriteTo(bb, dest); err != nil {
log.Println("Failed to send packet to:", dest)
}
}
}
}
func syncColors(upstream, local chan image.Image, dx chan pixdelta) {
var (
oimg, nimg image.Image
)
oimg = nil
nimg = nil
for {
select {
case nimg = <-local:
break
case oimg = <-upstream:
break
}
if oimg == nil || nimg == nil {
continue
}
jobs := uint64(0)
wg := new(sync.WaitGroup)
b := nimg.Bounds()
for x := 0; x < b.Dx(); x++ {
for y := 0; y < b.Dy(); y++ {
wg.Add(1)
go comparePixel(oimg, nimg, image.Point{X: x, Y: y}, dx, wg)
jobs++
}
}
wg.Wait()
}
}
// Framebuffer
type pixdelta struct {
p image.Point
c color.Color
}
func comparePixel(a, b image.Image, loc image.Point, r chan pixdelta, wg *sync.WaitGroup) {
defer wg.Done()
car, cab, cag, _ := a.At(loc.X, loc.Y).RGBA()
cbr, cbb, cbg, cba := b.At(loc.X, loc.Y).RGBA()
if (cba == 0xFFFF) && !(car == cbr && cag == cbg && cab == cbb) {
r <- pixdelta{c: b.At(loc.X, loc.Y), p: loc}
}
}
// Network
// fdcf:8538:9ad5:3333:XXXX:YYYY:11RR:GGBB
func convV6(p image.Point, c color.Color) (addr net.IP) {
addr = net.IP{
0xfd, 0xcf, 0x85, 0x38, 0x9a, 0xd5, 0x33, 0x33,
}
addr = append(addr, split2Bytes(uint16(p.X))...)
addr = append(addr, split2Bytes(uint16(p.Y))...)
r, g, b, _ := c.RGBA()
addr = append(addr, 0x11, uint8(r), uint8(g), uint8(b))
return
}
func split2Bytes(s uint16) []uint8 {
return []uint8{
uint8((s & (0xFF << 8)) >> 8),
uint8(s & 0xFF),
}
}