mirror of
https://github.com/hajimehoshi/ebiten.git
synced 2024-12-24 02:38:53 +01:00
parent
ab84184b4f
commit
10fb5e33be
@ -22,9 +22,9 @@ import (
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"math"
|
||||
"syscall/js"
|
||||
"time"
|
||||
|
||||
"github.com/gopherjs/gopherwasm/js"
|
||||
"github.com/hajimehoshi/ebiten/audio"
|
||||
)
|
||||
|
||||
@ -198,7 +198,7 @@ func decode(context *audio.Context, buf []byte, try int) (*Stream, error) {
|
||||
u8 := js.TypedArrayOf(buf)
|
||||
a := u8.Get("buffer").Call("slice", u8.Get("byteOffset"), u8.Get("byteOffset").Int()+u8.Get("byteLength").Int())
|
||||
|
||||
oc.Call("decodeAudioData", a, js.NewCallback(func(args []js.Value) {
|
||||
succeeded := js.FuncOf(func(this js.Value, args []js.Value) interface{} {
|
||||
buf := args[0]
|
||||
s.leftData = float32ArrayToSlice(buf.Call("getChannelData", 0))
|
||||
switch n := buf.Get("numberOfChannels").Int(); n {
|
||||
@ -211,7 +211,11 @@ func decode(context *audio.Context, buf []byte, try int) (*Stream, error) {
|
||||
default:
|
||||
ch <- fmt.Errorf("audio/mp3: number of channels must be 1 or 2 but %d", n)
|
||||
}
|
||||
}), js.NewCallback(func(args []js.Value) {
|
||||
return nil
|
||||
})
|
||||
defer succeeded.Release()
|
||||
|
||||
failed := js.FuncOf(func(this js.Value, args []js.Value) interface{} {
|
||||
err := args[0]
|
||||
if err != js.Null() || err != js.Undefined() {
|
||||
ch <- fmt.Errorf("audio/mp3: decodeAudioData failed: %v", err)
|
||||
@ -220,7 +224,11 @@ func decode(context *audio.Context, buf []byte, try int) (*Stream, error) {
|
||||
// from the next frame (#438).
|
||||
ch <- errTryAgain
|
||||
}
|
||||
}))
|
||||
return nil
|
||||
})
|
||||
defer failed.Release()
|
||||
|
||||
oc.Call("decodeAudioData", a, succeeded, failed)
|
||||
u8.Release()
|
||||
|
||||
timeout := time.Duration(math.Pow(2, float64(try))) * time.Second
|
||||
|
@ -17,8 +17,7 @@ package stb
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
|
||||
"github.com/gopherjs/gopherwasm/js"
|
||||
"syscall/js"
|
||||
)
|
||||
|
||||
var flatten = js.Global().Get("window").Call("eval", `(function(arr) {
|
||||
@ -90,21 +89,18 @@ func DecodeVorbis(buf []byte) (*Samples, int, int, error) {
|
||||
samples := &Samples{}
|
||||
sampleRate := 0
|
||||
|
||||
var f js.Callback
|
||||
f = js.NewCallback(func(args []js.Value) {
|
||||
f := js.FuncOf(func(this js.Value, args []js.Value) interface{} {
|
||||
r := args[0]
|
||||
|
||||
if e := r.Get("error"); e != js.Null() {
|
||||
ch <- fmt.Errorf("audio/vorbis/internal/stb: decode error: %s", e.String())
|
||||
close(ch)
|
||||
f.Release()
|
||||
return
|
||||
return nil
|
||||
}
|
||||
|
||||
if r.Get("eof").Bool() {
|
||||
close(ch)
|
||||
f.Release()
|
||||
return
|
||||
return nil
|
||||
}
|
||||
|
||||
if samples.channels == 0 {
|
||||
@ -117,7 +113,7 @@ func DecodeVorbis(buf []byte) (*Samples, int, int, error) {
|
||||
|
||||
flattened := flatten.Invoke(r.Get("data"))
|
||||
if flattened.Length() == 0 {
|
||||
return
|
||||
return nil
|
||||
}
|
||||
|
||||
s := make([]float32, flattened.Length())
|
||||
@ -127,7 +123,9 @@ func DecodeVorbis(buf []byte) (*Samples, int, int, error) {
|
||||
|
||||
samples.samples = append(samples.samples, s)
|
||||
samples.lengthInSamples += int64(len(s)) / int64(samples.channels)
|
||||
return nil
|
||||
})
|
||||
defer f.Release()
|
||||
|
||||
arr := js.TypedArrayOf(buf)
|
||||
js.Global().Get("stbvorbis").Call("decode", arr, f)
|
||||
|
@ -20,8 +20,7 @@ import (
|
||||
"bytes"
|
||||
"errors"
|
||||
"fmt"
|
||||
|
||||
"github.com/gopherjs/gopherwasm/js"
|
||||
"syscall/js"
|
||||
)
|
||||
|
||||
type file struct {
|
||||
@ -39,23 +38,25 @@ func OpenFile(path string) (ReadSeekCloser, error) {
|
||||
req := js.Global().Get("XMLHttpRequest").New()
|
||||
req.Call("open", "GET", path, true)
|
||||
req.Set("responseType", "arraybuffer")
|
||||
loadCallback := js.NewCallback(func([]js.Value) {
|
||||
loadf := js.FuncOf(func(this js.Value, args []js.Value) interface{} {
|
||||
defer close(ch)
|
||||
status := req.Get("status").Int()
|
||||
if 200 <= status && status < 400 {
|
||||
content = req.Get("response")
|
||||
return
|
||||
return nil
|
||||
}
|
||||
err = errors.New(fmt.Sprintf("http error: %d", status))
|
||||
return nil
|
||||
})
|
||||
defer loadCallback.Release()
|
||||
req.Call("addEventListener", "load", loadCallback)
|
||||
errorCallback := js.NewCallback(func([]js.Value) {
|
||||
defer loadf.Release()
|
||||
req.Call("addEventListener", "load", loadf)
|
||||
errorf := js.FuncOf(func(this js.Value, args []js.Value) interface{} {
|
||||
defer close(ch)
|
||||
err = errors.New(fmt.Sprintf("XMLHttpRequest error: %s", req.Get("statusText").String()))
|
||||
return nil
|
||||
})
|
||||
req.Call("addEventListener", "error", errorCallback)
|
||||
defer errorCallback.Release()
|
||||
req.Call("addEventListener", "error", errorf)
|
||||
defer errorf.Release()
|
||||
req.Call("send")
|
||||
<-ch
|
||||
if err != nil {
|
||||
|
@ -23,10 +23,9 @@ import (
|
||||
_ "image/jpeg"
|
||||
"log"
|
||||
"math"
|
||||
"syscall/js"
|
||||
"time"
|
||||
|
||||
"github.com/gopherjs/gopherwasm/js"
|
||||
|
||||
"github.com/hajimehoshi/ebiten"
|
||||
"github.com/hajimehoshi/ebiten/ebitenutil"
|
||||
"github.com/hajimehoshi/ebiten/examples/resources/images"
|
||||
|
4
go.mod
4
go.mod
@ -4,10 +4,10 @@ require (
|
||||
github.com/go-gl/glfw v0.0.0-20181213070059-819e8ce5125f
|
||||
github.com/gofrs/flock v0.7.0
|
||||
github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0
|
||||
github.com/gopherjs/gopherwasm v1.1.0
|
||||
github.com/gopherjs/gopherjs v0.0.0-20190430165422-3e4dfb77656c
|
||||
github.com/hajimehoshi/bitmapfont v1.1.1
|
||||
github.com/hajimehoshi/go-mp3 v0.2.0
|
||||
github.com/hajimehoshi/oto v0.3.4-0.20190430120619-1c8ecbb2424a
|
||||
github.com/hajimehoshi/oto v0.3.4-0.20190501045152-031fb1b9274d
|
||||
github.com/jakecoffman/cp v0.1.0
|
||||
github.com/jfreymuth/oggvorbis v1.0.0
|
||||
github.com/jfreymuth/vorbis v1.0.0 // indirect
|
||||
|
6
go.sum
6
go.sum
@ -5,8 +5,8 @@ github.com/gofrs/flock v0.7.0/go.mod h1:F1TvTiK9OcQqauNUHlbJvyl9Qa1QvF/gOUDKA14j
|
||||
github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0 h1:DACJavvAHhabrF08vX0COfcOBJRhZ8lUbR+ZWIs0Y5g=
|
||||
github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0/go.mod h1:E/TSTwGwJL78qG/PmXZO1EjYhfJinVAhrmmHX6Z8B9k=
|
||||
github.com/gopherjs/gopherjs v0.0.0-20180628210949-0892b62f0d9f/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY=
|
||||
github.com/gopherjs/gopherjs v0.0.0-20180825215210-0210a2f0f73c h1:16eHWuMGvCjSfgRJKqIzapE78onvvTbdi1rMkU00lZw=
|
||||
github.com/gopherjs/gopherjs v0.0.0-20180825215210-0210a2f0f73c/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY=
|
||||
github.com/gopherjs/gopherjs v0.0.0-20190430165422-3e4dfb77656c/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY=
|
||||
github.com/gopherjs/gopherwasm v0.1.1/go.mod h1:kx4n9a+MzHH0BJJhvlsQ65hqLFXDO/m256AsaDPQ+/4=
|
||||
github.com/gopherjs/gopherwasm v1.0.0/go.mod h1:SkZ8z7CWBz5VXbhJel8TxCmAcsQqzgWGR/8nMhyhZSI=
|
||||
github.com/gopherjs/gopherwasm v1.1.0 h1:fA2uLoctU5+T3OhOn2vYP0DVT6pxc7xhTlBB1paATqQ=
|
||||
@ -18,8 +18,8 @@ github.com/hajimehoshi/go-mp3 v0.1.2/go.mod h1:4i+c5pDNKDrxl1iu9iG90/+fhP37lio6g
|
||||
github.com/hajimehoshi/go-mp3 v0.2.0 h1:isy34iDg+96PsNuFbTdRRXzKr6a1gc2nhsPuFSfXacY=
|
||||
github.com/hajimehoshi/go-mp3 v0.2.0/go.mod h1:4i+c5pDNKDrxl1iu9iG90/+fhP37lio6gNhjCx9WBJw=
|
||||
github.com/hajimehoshi/oto v0.1.1/go.mod h1:hUiLWeBQnbDu4pZsAhOnGqMI1ZGibS6e2qhQdfpwz04=
|
||||
github.com/hajimehoshi/oto v0.3.4-0.20190430120619-1c8ecbb2424a h1:mNlGg4s1p2aifTjhMFn9dtTPYW+MTxKFQjWvm9DZ11U=
|
||||
github.com/hajimehoshi/oto v0.3.4-0.20190430120619-1c8ecbb2424a/go.mod h1:e9eTLBB9iZto045HLbzfHJIc+jP3xaKrjZTghvb6fdM=
|
||||
github.com/hajimehoshi/oto v0.3.4-0.20190501045152-031fb1b9274d h1:C2A7WySl23l4SD7FL1wnr2fk7TWtTf7W30pDDmpsZB4=
|
||||
github.com/hajimehoshi/oto v0.3.4-0.20190501045152-031fb1b9274d/go.mod h1:rj1gPEbAKUBdaV4JiWw2bqUpHtYxBemL7pC5U8rxkO4=
|
||||
github.com/jakecoffman/cp v0.1.0 h1:sgSYEGUgfwiT447fRjloa2c5b6UyYP+7muR3gQK+Ep0=
|
||||
github.com/jakecoffman/cp v0.1.0/go.mod h1:a3xPx9N8RyFAACD644t2dj/nK4SuLg1v+jL61m2yVo4=
|
||||
github.com/jfreymuth/oggvorbis v1.0.0 h1:aOpiihGrFLXpsh2osOlEvTcg5/aluzGQeC7m3uYWOZ0=
|
||||
|
@ -17,9 +17,8 @@
|
||||
package clock
|
||||
|
||||
import (
|
||||
"syscall/js"
|
||||
"time"
|
||||
|
||||
"github.com/gopherjs/gopherwasm/js"
|
||||
)
|
||||
|
||||
func now() int64 {
|
||||
|
@ -17,7 +17,7 @@
|
||||
package devicescale
|
||||
|
||||
import (
|
||||
"github.com/gopherjs/gopherwasm/js"
|
||||
"syscall/js"
|
||||
)
|
||||
|
||||
func impl(x, y int) float64 {
|
||||
|
@ -19,8 +19,7 @@ package opengl
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
|
||||
"github.com/gopherjs/gopherwasm/js"
|
||||
"syscall/js"
|
||||
|
||||
"github.com/hajimehoshi/ebiten/internal/graphics"
|
||||
)
|
||||
|
@ -17,10 +17,9 @@
|
||||
package js
|
||||
|
||||
import (
|
||||
"syscall/js"
|
||||
"unicode"
|
||||
|
||||
"github.com/gopherjs/gopherwasm/js"
|
||||
|
||||
"github.com/hajimehoshi/ebiten/internal/driver"
|
||||
)
|
||||
|
||||
|
@ -21,8 +21,7 @@ import (
|
||||
"log"
|
||||
"runtime"
|
||||
"strconv"
|
||||
|
||||
"github.com/gopherjs/gopherwasm/js"
|
||||
"syscall/js"
|
||||
|
||||
"github.com/hajimehoshi/ebiten/internal/devicescale"
|
||||
"github.com/hajimehoshi/ebiten/internal/driver"
|
||||
@ -226,28 +225,30 @@ func (u *UserInterface) loop(context driver.UIContext) <-chan error {
|
||||
u.context = context
|
||||
|
||||
ch := make(chan error)
|
||||
var cf js.Callback
|
||||
f := func([]js.Value) {
|
||||
var cf js.Func
|
||||
f := func(this js.Value, args []js.Value) interface{} {
|
||||
if u.contextLost {
|
||||
requestAnimationFrame.Invoke(cf)
|
||||
return
|
||||
return nil
|
||||
}
|
||||
|
||||
if err := u.update(); err != nil {
|
||||
ch <- err
|
||||
close(ch)
|
||||
return
|
||||
return nil
|
||||
}
|
||||
if u.vsync {
|
||||
requestAnimationFrame.Invoke(cf)
|
||||
} else {
|
||||
setTimeout.Invoke(cf, 0)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
cf = js.NewCallback(f)
|
||||
// TODO: Should cf be released after the game ends?
|
||||
cf = js.FuncOf(f)
|
||||
// Call f asyncly to be async since ch is used in f.
|
||||
go func() {
|
||||
f(nil)
|
||||
f(js.Value{}, nil)
|
||||
}()
|
||||
return ch
|
||||
}
|
||||
@ -255,38 +256,43 @@ func (u *UserInterface) loop(context driver.UIContext) <-chan error {
|
||||
func init() {
|
||||
if document.Get("body") == js.Null() {
|
||||
ch := make(chan struct{})
|
||||
window.Call("addEventListener", "load", js.NewCallback(func([]js.Value) {
|
||||
window.Call("addEventListener", "load", js.FuncOf(func(this js.Value, args []js.Value) interface{} {
|
||||
close(ch)
|
||||
return nil
|
||||
}))
|
||||
<-ch
|
||||
}
|
||||
|
||||
window.Call("addEventListener", "focus", js.NewCallback(func([]js.Value) {
|
||||
window.Call("addEventListener", "focus", js.FuncOf(func(this js.Value, args []js.Value) interface{} {
|
||||
theUI.windowFocus = true
|
||||
if theUI.suspended() {
|
||||
theUI.context.SuspendAudio()
|
||||
} else {
|
||||
theUI.context.ResumeAudio()
|
||||
}
|
||||
return nil
|
||||
}))
|
||||
window.Call("addEventListener", "blur", js.NewCallback(func([]js.Value) {
|
||||
window.Call("addEventListener", "blur", js.FuncOf(func(this js.Value, args []js.Value) interface{} {
|
||||
theUI.windowFocus = false
|
||||
if theUI.suspended() {
|
||||
theUI.context.SuspendAudio()
|
||||
} else {
|
||||
theUI.context.ResumeAudio()
|
||||
}
|
||||
return nil
|
||||
}))
|
||||
document.Call("addEventListener", "visibilitychange", js.NewCallback(func([]js.Value) {
|
||||
document.Call("addEventListener", "visibilitychange", js.FuncOf(func(this js.Value, args []js.Value) interface{} {
|
||||
theUI.pageVisible = !document.Get("hidden").Bool()
|
||||
if theUI.suspended() {
|
||||
theUI.context.SuspendAudio()
|
||||
} else {
|
||||
theUI.context.ResumeAudio()
|
||||
}
|
||||
return nil
|
||||
}))
|
||||
window.Call("addEventListener", "resize", js.NewCallback(func([]js.Value) {
|
||||
window.Call("addEventListener", "resize", js.FuncOf(func(this js.Value, args []js.Value) interface{} {
|
||||
theUI.updateScreenSize()
|
||||
return nil
|
||||
}))
|
||||
|
||||
// Adjust the initial scale to 1.
|
||||
@ -318,8 +324,9 @@ func init() {
|
||||
|
||||
// TODO: This is OK as long as the game is in an independent iframe.
|
||||
// What if the canvas is embedded in a HTML directly?
|
||||
document.Get("body").Call("addEventListener", "click", js.NewCallback(func([]js.Value) {
|
||||
document.Get("body").Call("addEventListener", "click", js.FuncOf(func(this js.Value, args []js.Value) interface{} {
|
||||
canvas.Call("focus")
|
||||
return nil
|
||||
}))
|
||||
|
||||
canvasStyle := canvas.Get("style")
|
||||
@ -330,57 +337,93 @@ func init() {
|
||||
canvas.Get("style").Set("outline", "none")
|
||||
|
||||
// Keyboard
|
||||
// Don't 'preventDefault' on keydown events or keypress events wouldn't work (#715).
|
||||
canvas.Call("addEventListener", "keydown", js.NewEventCallback(0, func(e js.Value) {
|
||||
canvas.Call("addEventListener", "keydown", js.FuncOf(func(this js.Value, args []js.Value) interface{} {
|
||||
e := args[0]
|
||||
// Don't 'preventDefault' on keydown events or keypress events wouldn't work (#715).
|
||||
theUI.input.Update(e)
|
||||
return nil
|
||||
}))
|
||||
canvas.Call("addEventListener", "keypress", js.NewEventCallback(js.PreventDefault, func(e js.Value) {
|
||||
canvas.Call("addEventListener", "keypress", js.FuncOf(func(this js.Value, args []js.Value) interface{} {
|
||||
e := args[0]
|
||||
e.Call("preventDefault")
|
||||
theUI.input.Update(e)
|
||||
return nil
|
||||
}))
|
||||
canvas.Call("addEventListener", "keyup", js.NewEventCallback(js.PreventDefault, func(e js.Value) {
|
||||
canvas.Call("addEventListener", "keyup", js.FuncOf(func(this js.Value, args []js.Value) interface{} {
|
||||
e := args[0]
|
||||
e.Call("preventDefault")
|
||||
theUI.input.Update(e)
|
||||
return nil
|
||||
}))
|
||||
|
||||
// Mouse
|
||||
canvas.Call("addEventListener", "mousedown", js.NewEventCallback(js.PreventDefault, func(e js.Value) {
|
||||
canvas.Call("addEventListener", "mousedown", js.FuncOf(func(this js.Value, args []js.Value) interface{} {
|
||||
e := args[0]
|
||||
e.Call("preventDefault")
|
||||
theUI.input.Update(e)
|
||||
return nil
|
||||
}))
|
||||
canvas.Call("addEventListener", "mouseup", js.NewEventCallback(js.PreventDefault, func(e js.Value) {
|
||||
canvas.Call("addEventListener", "mouseup", js.FuncOf(func(this js.Value, args []js.Value) interface{} {
|
||||
e := args[0]
|
||||
e.Call("preventDefault")
|
||||
theUI.input.Update(e)
|
||||
return nil
|
||||
}))
|
||||
canvas.Call("addEventListener", "mousemove", js.NewEventCallback(js.PreventDefault, func(e js.Value) {
|
||||
canvas.Call("addEventListener", "mousemove", js.FuncOf(func(this js.Value, args []js.Value) interface{} {
|
||||
e := args[0]
|
||||
e.Call("preventDefault")
|
||||
theUI.input.Update(e)
|
||||
return nil
|
||||
}))
|
||||
canvas.Call("addEventListener", "wheel", js.NewEventCallback(js.PreventDefault, func(e js.Value) {
|
||||
canvas.Call("addEventListener", "wheel", js.FuncOf(func(this js.Value, args []js.Value) interface{} {
|
||||
e := args[0]
|
||||
e.Call("preventDefault")
|
||||
theUI.input.Update(e)
|
||||
return nil
|
||||
}))
|
||||
|
||||
// Touch
|
||||
canvas.Call("addEventListener", "touchstart", js.NewEventCallback(js.PreventDefault, func(e js.Value) {
|
||||
canvas.Call("addEventListener", "touchstart", js.FuncOf(func(this js.Value, args []js.Value) interface{} {
|
||||
e := args[0]
|
||||
e.Call("preventDefault")
|
||||
theUI.input.Update(e)
|
||||
return nil
|
||||
}))
|
||||
canvas.Call("addEventListener", "touchend", js.NewEventCallback(js.PreventDefault, func(e js.Value) {
|
||||
canvas.Call("addEventListener", "touchend", js.FuncOf(func(this js.Value, args []js.Value) interface{} {
|
||||
e := args[0]
|
||||
e.Call("preventDefault")
|
||||
theUI.input.Update(e)
|
||||
return nil
|
||||
}))
|
||||
canvas.Call("addEventListener", "touchmove", js.NewEventCallback(js.PreventDefault, func(e js.Value) {
|
||||
canvas.Call("addEventListener", "touchmove", js.FuncOf(func(this js.Value, args []js.Value) interface{} {
|
||||
e := args[0]
|
||||
e.Call("preventDefault")
|
||||
theUI.input.Update(e)
|
||||
return nil
|
||||
}))
|
||||
|
||||
// Gamepad
|
||||
window.Call("addEventListener", "gamepadconnected", js.NewCallback(func(e []js.Value) {
|
||||
window.Call("addEventListener", "gamepadconnected", js.FuncOf(func(this js.Value, args []js.Value) interface{} {
|
||||
// Do nothing.
|
||||
return nil
|
||||
}))
|
||||
|
||||
canvas.Call("addEventListener", "contextmenu", js.NewEventCallback(js.PreventDefault, func(js.Value) {
|
||||
// Do nothing.
|
||||
canvas.Call("addEventListener", "contextmenu", js.FuncOf(func(this js.Value, args []js.Value) interface{} {
|
||||
e := args[0]
|
||||
e.Call("preventDefault")
|
||||
return nil
|
||||
}))
|
||||
|
||||
// Context
|
||||
canvas.Call("addEventListener", "webglcontextlost", js.NewEventCallback(js.PreventDefault, func(js.Value) {
|
||||
canvas.Call("addEventListener", "webglcontextlost", js.FuncOf(func(this js.Value, args []js.Value) interface{} {
|
||||
e := args[0]
|
||||
e.Call("preventDefault")
|
||||
theUI.contextLost = true
|
||||
return nil
|
||||
}))
|
||||
canvas.Call("addEventListener", "webglcontextrestored", js.NewCallback(func(e []js.Value) {
|
||||
canvas.Call("addEventListener", "webglcontextrestored", js.FuncOf(func(this js.Value, args []js.Value) interface{} {
|
||||
theUI.contextLost = false
|
||||
return nil
|
||||
}))
|
||||
}
|
||||
|
||||
|
@ -19,8 +19,7 @@ package web
|
||||
import (
|
||||
"runtime"
|
||||
"strings"
|
||||
|
||||
"github.com/gopherjs/gopherwasm/js"
|
||||
"syscall/js"
|
||||
)
|
||||
|
||||
func IsGopherJS() bool {
|
||||
|
Loading…
Reference in New Issue
Block a user