twitchapon-anim

Basic Twitchapon Receiver/Visuals
git clone git://bsandro.tech/twitchapon-anim
Log | Files | Refs | README | LICENSE

commit f51477cc80f70cf15c72401ec41a4e054607c0b8
parent 53bc3ea85b7a702681d69c42bc8965f6513ed520
Author: bsandro <brian.drosan@gmail.com>
Date:   Mon, 10 May 2021 22:12:42 +0300

Basic GIF animations support with a sample of dancing Terry <3

Diffstat:
M.gitignore | 1+
MTODO | 3++-
Aassets/dance01.gif | 0
Aassets/dance02.gif | 0
Aassets/dance03.gif | 0
Aassets/dance04.gif | 0
Aassets/terry1.gif | 0
Aassets/terry2.gif | 0
Mebitest.go | 67+++++++++++++++++++++++++++++++++++++++++++++++++++++++++----------
Agif_object.go | 28++++++++++++++++++++++++++++
Mgo.sum | 9++++-----
Minit.go | 4+---
12 files changed, 93 insertions(+), 19 deletions(-)

diff --git a/.gitignore b/.gitignore @@ -4,3 +4,4 @@ vendor *.swp twitchapon-anim twitchapon-anim.exe +.directory diff --git a/TODO b/TODO @@ -3,6 +3,7 @@ twitchapon-anim brief TODO list - general code cleanup - make it configurable - distinct different type of messages and react to them differently -- some GIF animation support +- GIF animation support - sound support - use native go 1.16 embeddable binaries feature +- config with a settings which alert triggers which feature (gif or sound) diff --git a/assets/dance01.gif b/assets/dance01.gif Binary files differ. diff --git a/assets/dance02.gif b/assets/dance02.gif Binary files differ. diff --git a/assets/dance03.gif b/assets/dance03.gif Binary files differ. diff --git a/assets/dance04.gif b/assets/dance04.gif Binary files differ. diff --git a/assets/terry1.gif b/assets/terry1.gif Binary files differ. diff --git a/assets/terry2.gif b/assets/terry2.gif Binary files differ. diff --git a/ebitest.go b/ebitest.go @@ -6,7 +6,7 @@ import ( "fmt" "github.com/hajimehoshi/ebiten/v2" "github.com/hajimehoshi/ebiten/v2/ebitenutil" - _ "image" + "image" "image/color" _ "image/jpeg" _ "image/png" @@ -44,8 +44,9 @@ type Sprite struct { } type Game struct { - inited bool - sprites []*Sprite + inited bool + sprites []*Sprite + animation *TGifObject } var game *Game @@ -139,17 +140,56 @@ func (g *Game) Draw(screen *ebiten.Image) { //defer g.ShowDebug(screen) // background - screen.Fill(color.RGBA{0xFF, 0, 0xFF, 0xFF}) + screen.Fill(color.RGBA{0, 0xFF, 0, 0xFF}) for _, sprite := range g.sprites { - //w, h := sprite.img.Size() + w, h := sprite.img.Size() sprite.opt.GeoM.Reset() - //sprite.opt.GeoM.Translate(-float64(w)/2.0, -float64(h)/2.0) - //sprite.opt.GeoM.Rotate(sprite.rotation) + sprite.opt.GeoM.Translate(-float64(w)/2, -float64(h)/2) + sprite.opt.GeoM.Rotate(sprite.rotation) + sprite.opt.GeoM.Translate(float64(w/2), float64(h/2)) sprite.opt.GeoM.Translate(sprite.x, sprite.y) - sprite.opt.ColorM.Translate(0, 0, 0, -0.0003) + //sprite.opt.ColorM.Translate(0, 0, 0, -0.0003) screen.DrawImage(sprite.img, &sprite.opt) } + + // screen size + scr_w, scr_h := ScreenSize.width, ScreenSize.height + // reference image (canvas) size + img_w, img_h := g.animation.Anim.Config.Width, g.animation.Anim.Config.Height + // frame rectangle + var bounds image.Rectangle = g.animation.Anim.Image[g.animation.Frame].Bounds() + // frame image + src_img := ebiten.NewImageFromImage(g.animation.Anim.Image[g.animation.Frame]) + //src_w, src_h := src_img.Size() + img_opts := &ebiten.DrawImageOptions{} + // shifting by rectangle properties + img_opts.GeoM.Translate(float64(bounds.Min.X), float64(bounds.Min.Y)) + //img_opts.GeoM.Translate(-float64(src_w / 2), -float64(src_h / 2)) + //img_opts.GeoM.Translate(-float64(img_w / 2), -float64(img_h / 2)) + //img_opts.GeoM.Translate(float64(src_w / 2), float64(src_h / 2)) + //img_opts.GeoM.Translate(float64(scr_w / 2), float64(scr_h / 2)) + + // image from reference size + img := ebiten.NewImage(img_w, img_h) + //img.Fill(color.RGBA{0xF0, 0x10, 0x0F, 0xFF}) + + img.DrawImage(src_img, img_opts) + opts := &ebiten.DrawImageOptions{} + // center image + opts.GeoM.Translate(-float64(img_w/2), -float64(img_h/2)) + opts.GeoM.Translate(float64(scr_w/2), float64(scr_h/2)) + screen.DrawImage(img, opts) + delay := int64(g.animation.Anim.Delay[g.animation.Frame]) + cur_time := time.Now() + elapsed := cur_time.Sub(g.animation.FrameTime) + if elapsed.Milliseconds() > delay*10 { + g.animation.FrameTime = cur_time + g.animation.Frame += 1 + if g.animation.Frame >= len(g.animation.Anim.Image) { + g.animation.Frame = 0 + } + } } func (g *Game) Layout(outsideWidth, outsideHeight int) (screenWidth, screenHeight int) { @@ -161,13 +201,18 @@ func (g *Game) init() { g.inited = true fmt.Println("Game inited ok") }() - fmt.Println("Game::init()") rand.Seed(time.Now().UnixNano()) for i := 0; i < NumSprites; i++ { g.sprites = append(g.sprites, makeRandomSprite()) } + + var err error + g.animation, err = MakeGifObject("assets/terry1.gif") + if err != nil { + log.Fatal(err) + } } func makeRandomSprite() *Sprite { @@ -187,11 +232,13 @@ func main() { ebiten.SetWindowSize(ScreenSize.width, ScreenSize.height) ebiten.SetWindowTitle("Twitchapon Receiver Module") ebiten.SetMaxTPS(S_FRAMERATE) + ebiten.SetRunnableOnUnfocused(true) + http.HandleFunc("/", handleHttpRequest) go func() { http.ListenAndServe("localhost:2345", nil) }() - ebiten.SetRunnableOnUnfocused(true) + if err := ebiten.RunGame(game); err != nil { log.Fatal(err) } diff --git a/gif_object.go b/gif_object.go @@ -0,0 +1,28 @@ +package main + +import ( + "image/gif" + "os" + "time" +) + +type TGifObject struct { + Anim *gif.GIF + Frame int + FrameTime time.Time +} + +func MakeGifObject(file_path string) (obj *TGifObject, err error) { + obj = new(TGifObject) + + fileReader, err := os.Open(file_path) + if err != nil { + return + } + obj.Anim, err = gif.DecodeAll(fileReader) + if err != nil { + return + } + + return +} diff --git a/go.sum b/go.sum @@ -1,23 +1,22 @@ github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200707082815-5321531c36a2 h1:Ac1OEHHkbAZ6EUnJahF0GKcU0FjPc/V8F1DvjhKngFE= github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200707082815-5321531c36a2/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= +github.com/gofrs/flock v0.8.0 h1:MSdYClljsF3PbENUUEx85nkWfJSGfzYI9yEBZOJz6CY= github.com/gofrs/flock v0.8.0/go.mod h1:F1TvTiK9OcQqauNUHlbJvyl9Qa1QvF/gOUDKA14jxHU= github.com/hajimehoshi/bitmapfont/v2 v2.1.0/go.mod h1:2BnYrkTQGThpr/CY6LorYtt/zEPNzvE/ND69CRTaHMs= -github.com/hajimehoshi/ebiten v1.12.3 h1:/KYCLW5VvfMKOMb8TqjKFlDCQAibM+OiA+LUwjS8t0E= github.com/hajimehoshi/ebiten/v2 v2.0.0 h1:G8mhkKFtnDPPZ/ChaGWx4Bm0NusYEcafGCJ8QLxEaYs= github.com/hajimehoshi/ebiten/v2 v2.0.0/go.mod h1:hpZZQ/kk8DZqft7QsQ5hZLRQXHSZPdKnaa0tcJ3CZFE= github.com/hajimehoshi/file2byteslice v0.0.0-20200812174855-0e5e8a80490e/go.mod h1:CqqAHp7Dk/AqQiwuhV1yT2334qbA/tFWQW0MD2dGqUE= github.com/hajimehoshi/go-mp3 v0.3.1/go.mod h1:qMJj/CSDxx6CGHiZeCgbiq2DSUkbK0UbtXShQcnfyMM= github.com/hajimehoshi/oto v0.6.1/go.mod h1:0QXGEkbuJRohbJaxr7ZQSxnju7hEhseiPx2hrh6raOI= -github.com/hajimehoshi/oto v0.6.6 h1:HYSZ8cYZqOL4iHugvbcfhNN2smiSOsBMaoSBi4nnWcw= github.com/hajimehoshi/oto v0.6.6/go.mod h1:0QXGEkbuJRohbJaxr7ZQSxnju7hEhseiPx2hrh6raOI= github.com/jakecoffman/cp v1.0.0/go.mod h1:JjY/Fp6d8E1CHnu74gWNnU0+b9VzEdUVPoJxg2PsTQg= -github.com/jfreymuth/oggvorbis v1.0.1 h1:NT0eXBgE2WHzu6RT/6zcb2H10Kxj6Fm3PccT0LE6bqw= github.com/jfreymuth/oggvorbis v1.0.1/go.mod h1:NqS+K+UXKje0FUYUPosyQ+XTVvjmVjps1aEZH1sumIk= -github.com/jfreymuth/vorbis v1.0.0 h1:SmDf783s82lIjGZi8EGUUaS7YxPHgRj4ZXW/h7rUi7U= github.com/jfreymuth/vorbis v1.0.0/go.mod h1:8zy3lUAm9K/rJJk223RKy6vjCZTWC61NA2QD06bfOE0= github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= +github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= +github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e h1:fD57ERR4JtEqsWbfPhv4DMiApHyliiK5xCTNVSPiaAs= github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno= github.com/pkg/browser v0.0.0-20180916011732-0a3d74bf9ce4/go.mod h1:4OwLy04Bl9Ef3GJJCoec+30X3LQs/0/m4HFRt/2LUSA= github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= @@ -54,7 +53,6 @@ golang.org/x/sys v0.0.0-20190429190828-d89cdac9e872/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201009025420-dfb3f7c4e634 h1:bNEHhJCnrwMKNMmOx3yAynp5vs5/gRy+XWFtZFu7NBM= golang.org/x/sys v0.0.0-20201009025420-dfb3f7c4e634/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/text v0.3.0 h1:g61tztE5qeGQ89tm6NTjjM9VPIm088od1l6aSorWRWg= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/tools v0.0.0-20190312151545-0bb0c0a6e846/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= @@ -63,4 +61,5 @@ golang.org/x/tools v0.0.0-20201009162240-fcf82128ed91/go.mod h1:z6u4i615ZeAfBE4X golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +gopkg.in/check.v1 v1.0.0-20200902074654-038fdea0a05b h1:QRR6H1YWRnHb4Y/HeNFCTJLFVxaq6wH4YuVdsUOr75U= gopkg.in/check.v1 v1.0.0-20200902074654-038fdea0a05b/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= diff --git a/init.go b/init.go @@ -6,6 +6,7 @@ import ( "github.com/hajimehoshi/ebiten/v2" _ "golang.org/x/image/webp" "image" + _ "image/gif" _ "image/jpeg" _ "image/png" "log" @@ -25,9 +26,6 @@ func init() { fmt.Printf("Loaded '%s' - %d bytes\n", fname, len(raw)) } - //imageNames := []string{"BakaHa2.webp", "space.jpg"} - - //for _, name := range imageNames { for name, _ := range Assets { img, err := getImage(name) if err != nil {