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:
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 {