diff --git a/_docs/gen.go b/_docs/gen.go
index 8e1e6c2bb..57a1da495 100644
--- a/_docs/gen.go
+++ b/_docs/gen.go
@@ -136,17 +136,25 @@ func safeHTML(text string) template.HTML {
}
type example struct {
- Name string
- ThumbWidth int
- ThumbHeight int
+ Name string
+ ThumbWidth int
+ ThumbHeight int
+ ScreenWidth int
+ ScreenHeight int
}
func (e *example) Width() int {
- return e.ThumbWidth * 2
+ if e.ScreenWidth == 0 {
+ return e.ThumbWidth * 2
+ }
+ return e.ScreenWidth
}
func (e *example) Height() int {
- return e.ThumbHeight * 2
+ if e.ScreenHeight == 0 {
+ return e.ThumbHeight * 2
+ }
+ return e.ScreenHeight
}
func (e *example) Source() string {
@@ -177,34 +185,37 @@ func versions() string {
}
var (
+ gamesExamples = []example{
+ {Name: "2048", ThumbWidth: 210, ThumbHeight: 300},
+ {Name: "blocks", ThumbWidth: 256, ThumbHeight: 240},
+ }
graphicsExamples = []example{
- {"alphablending", 320, 240},
- {"font", 320, 240},
- {"highdpi", 320, 240},
- {"hsv", 320, 240},
- {"hue", 320, 240},
- {"infinitescroll", 320, 240},
- {"life", 320, 240},
- {"masking", 320, 240},
- {"mosaic", 320, 240},
- {"noise", 320, 240},
- {"paint", 320, 240},
- {"perspective", 320, 240},
- {"rotate", 320, 240},
- {"sprites", 320, 240},
+ {Name: "alphablending", ThumbWidth: 320, ThumbHeight: 240},
+ {Name: "flood", ThumbWidth: 320, ThumbHeight: 240},
+ {Name: "font", ThumbWidth: 320, ThumbHeight: 240},
+ {Name: "highdpi", ThumbWidth: 320, ThumbHeight: 240},
+ {Name: "hsv", ThumbWidth: 320, ThumbHeight: 240},
+ {Name: "hue", ThumbWidth: 320, ThumbHeight: 240},
+ {Name: "infinitescroll", ThumbWidth: 320, ThumbHeight: 240},
+ {Name: "life", ThumbWidth: 320, ThumbHeight: 240},
+ {Name: "mandelbrot", ThumbWidth: 320, ThumbHeight: 320, ScreenWidth: 640, ScreenHeight: 640},
+ {Name: "masking", ThumbWidth: 320, ThumbHeight: 240},
+ {Name: "mosaic", ThumbWidth: 320, ThumbHeight: 240},
+ {Name: "noise", ThumbWidth: 320, ThumbHeight: 240},
+ {Name: "paint", ThumbWidth: 320, ThumbHeight: 240},
+ {Name: "perspective", ThumbWidth: 320, ThumbHeight: 240},
+ {Name: "rotate", ThumbWidth: 320, ThumbHeight: 240},
+ {Name: "sprites", ThumbWidth: 320, ThumbHeight: 240},
}
inputExamples = []example{
- {"gamepad", 320, 240},
- {"keyboard", 320, 240},
- {"typewriter", 320, 240},
+ {Name: "gamepad", ThumbWidth: 320, ThumbHeight: 240},
+ {Name: "keyboard", ThumbWidth: 320, ThumbHeight: 240},
+ {Name: "typewriter", ThumbWidth: 320, ThumbHeight: 240},
}
audioExamples = []example{
- {"audio", 320, 240},
- {"piano", 320, 240},
- }
- gameExamples = []example{
- {"2048", 210, 300},
- {"blocks", 256, 240},
+ {Name: "audio", ThumbWidth: 320, ThumbHeight: 240},
+ {Name: "piano", ThumbWidth: 320, ThumbHeight: 240},
+ {Name: "sinewave", ThumbWidth: 320, ThumbHeight: 240},
}
)
@@ -268,7 +279,7 @@ func outputMain() error {
"GraphicsExamples": graphicsExamples,
"InputExamples": inputExamples,
"AudioExamples": audioExamples,
- "GameExamples": gameExamples,
+ "GamesExamples": gamesExamples,
}
return t.Funcs(funcs).Execute(f, data)
}
@@ -371,7 +382,7 @@ func main() {
examples = append(examples, graphicsExamples...)
examples = append(examples, inputExamples...)
examples = append(examples, audioExamples...)
- examples = append(examples, gameExamples...)
+ examples = append(examples, gamesExamples...)
for _, e := range examples {
if err := outputExampleContent(&e); err != nil {
log.Fatal(err)
diff --git a/_docs/index.tmpl.html b/_docs/index.tmpl.html
index 72ab4a728..17459111b 100644
--- a/_docs/index.tmpl.html
+++ b/_docs/index.tmpl.html
@@ -60,6 +60,14 @@
Examples
+ Games
+
+ {{range .GamesExamples -}}
+
+
+
+ {{- end}}
+
Graphics
{{range .GraphicsExamples -}}
@@ -84,14 +92,6 @@
{{- end}}
- Game
-
- {{range .GameExamples -}}
-
-
-
- {{- end}}
-
The Gopher photographs by Chris Nokleberg are licensed under the Creative Commons 3.0 Attributions License.
diff --git a/docs/examples/flood.content.html b/docs/examples/flood.content.html
new file mode 100644
index 000000000..1d8cb38a5
--- /dev/null
+++ b/docs/examples/flood.content.html
@@ -0,0 +1,31 @@
+
+
+
+(Example)
+Now Loading...
diff --git a/docs/examples/flood.html b/docs/examples/flood.html
new file mode 100644
index 000000000..c136f64aa
--- /dev/null
+++ b/docs/examples/flood.html
@@ -0,0 +1,120 @@
+
+
+
+
+
+
+Ebiten example - flood
+
+
+
+
+
+
+
+
+
+
+
Ebiten example - flood
+
+
// +build example
+
+package main
+
+import (
+ "image/color"
+ _ "image/png"
+ "log"
+
+ "github.com/hajimehoshi/ebiten"
+ "github.com/hajimehoshi/ebiten/ebitenutil"
+)
+
+const (
+ screenWidth = 320
+ screenHeight = 240
+)
+
+var (
+ ebitenImage *ebiten.Image
+ colors = []color.RGBA{
+ {0xff, 0xff, 0xff, 0xff},
+ {0xff, 0xff, 0x0, 0xff},
+ {0xff, 0x0, 0xff, 0xff},
+ {0xff, 0x0, 0x0, 0xff},
+ {0x0, 0xff, 0xff, 0xff},
+ {0x0, 0xff, 0x0, 0xff},
+ {0x0, 0x0, 0xff, 0xff},
+ {0x0, 0x0, 0x0, 0xff},
+ }
+)
+
+func update(screen *ebiten.Image) error {
+ if ebiten.IsRunningSlowly() {
+ return nil
+ }
+
+ const (
+ ox = 10
+ oy = 10
+ dx = 60
+ dy = 50
+ )
+ screen.Fill(color.NRGBA{0x00, 0x40, 0x80, 0xff})
+
+ op := &ebiten.DrawImageOptions{}
+ op.GeoM.Translate(ox, oy)
+ screen.DrawImage(ebitenImage, op)
+
+ // Fill with solid colors
+ for i, c := range colors {
+ op := &ebiten.DrawImageOptions{}
+ x := i % 4
+ y := i/4 + 1
+ op.GeoM.Translate(ox+float64(dx*x), oy+float64(dy*y))
+
+ // Reset RGB (not Alpha) 0 forcibly
+ op.ColorM.Scale(0, 0, 0, 1)
+
+ // Set color
+ r := float64(c.R) / 0xff
+ g := float64(c.G) / 0xff
+ b := float64(c.B) / 0xff
+ op.ColorM.Translate(r, g, b, 0)
+ screen.DrawImage(ebitenImage, op)
+ }
+ return nil
+}
+
+func main() {
+ var err error
+ ebitenImage, _, err = ebitenutil.NewImageFromFile("_resources/images/ebiten.png", ebiten.FilterNearest)
+ if err != nil {
+ log.Fatal(err)
+ }
+ if err := ebiten.Run(update, screenWidth, screenHeight, 2, "Flood fill with solid colors (Ebiten Demo)"); err != nil {
+ log.Fatal(err)
+ }
+}
+
+
+
+
+
+
+
+
diff --git a/docs/examples/mandelbrot.content.html b/docs/examples/mandelbrot.content.html
new file mode 100644
index 000000000..e93dda207
--- /dev/null
+++ b/docs/examples/mandelbrot.content.html
@@ -0,0 +1,31 @@
+
+
+
+(Example)
+Now Loading...
diff --git a/docs/examples/mandelbrot.html b/docs/examples/mandelbrot.html
new file mode 100644
index 000000000..0bb14fc5c
--- /dev/null
+++ b/docs/examples/mandelbrot.html
@@ -0,0 +1,124 @@
+
+
+
+
+
+
+Ebiten example - mandelbrot
+
+
+
+
+
+
+
+
+
+
+
Ebiten example - mandelbrot
+
+
// +build example
+
+package main
+
+import (
+ "log"
+ "math"
+
+ "github.com/hajimehoshi/ebiten"
+)
+
+const (
+ screenWidth = 640
+ screenHeight = 640
+ maxIt = 128
+)
+
+var (
+ offscreen *ebiten.Image
+ offscreenPix []byte
+ palette [maxIt]byte
+)
+
+func init() {
+ offscreen, _ = ebiten.NewImage(screenWidth, screenHeight, ebiten.FilterNearest)
+ offscreenPix = make([]byte, screenWidth*screenHeight*4)
+ for i := range palette {
+ palette[i] = byte(math.Sqrt(float64(i)/float64(len(palette))) * 0x80)
+ }
+}
+
+func color(it int) (r, g, b byte) {
+ if it == maxIt {
+ return 0xff, 0xff, 0xff
+ }
+ c := palette[it]
+ return c, c, c
+}
+
+func updateOffscreen(centerX, centerY, size float64) {
+ for j := 0; j < screenHeight; j++ {
+ for i := 0; i < screenHeight; i++ {
+ x := float64(i)*size/screenWidth - size/2 + centerX
+ y := (screenHeight-float64(j))*size/screenHeight - size/2 + centerY
+ c := complex(x, y)
+ z := complex(0, 0)
+ it := 0
+ for ; it < maxIt; it++ {
+ z = z*z + c
+ if real(z)*real(z)+imag(z)*imag(z) > 4 {
+ break
+ }
+ }
+ r, g, b := color(it)
+ p := 4 * (i + j*screenWidth)
+ offscreenPix[p] = r
+ offscreenPix[p+1] = g
+ offscreenPix[p+2] = b
+ offscreenPix[p+3] = 0xff
+ }
+ }
+ offscreen.ReplacePixels(offscreenPix)
+}
+
+func init() {
+ // Now it is not feasible to call updateOffscreen every frame due to performance.
+ updateOffscreen(-0.75, 0.25, 2)
+}
+
+func update(screen *ebiten.Image) error {
+ if ebiten.IsRunningSlowly() {
+ return nil
+ }
+
+ screen.DrawImage(offscreen, nil)
+ return nil
+}
+
+func main() {
+ if err := ebiten.Run(update, screenWidth, screenHeight, 1, "Mandelbrot (Ebiten Demo)"); err != nil {
+ log.Fatal(err)
+ }
+}
+
+
+
+
+
+
+
+
diff --git a/docs/examples/sinewave.content.html b/docs/examples/sinewave.content.html
new file mode 100644
index 000000000..c481ba41f
--- /dev/null
+++ b/docs/examples/sinewave.content.html
@@ -0,0 +1,31 @@
+
+
+
+(Example)
+Now Loading...
diff --git a/docs/examples/sinewave.html b/docs/examples/sinewave.html
new file mode 100644
index 000000000..ba50f6f24
--- /dev/null
+++ b/docs/examples/sinewave.html
@@ -0,0 +1,150 @@
+
+
+
+
+
+
+Ebiten example - sinewave
+
+
+
+
+
+
+
+
+
+
+
Ebiten example - sinewave
+
+
// +build example
+
+package main
+
+import (
+ "errors"
+ "fmt"
+ "io"
+ "log"
+ "math"
+
+ "github.com/hajimehoshi/ebiten"
+ "github.com/hajimehoshi/ebiten/audio"
+ "github.com/hajimehoshi/ebiten/ebitenutil"
+)
+
+const (
+ screenWidth = 320
+ screenHeight = 240
+ sampleRate = 44100
+ frequency = 440
+)
+
+var audioContext *audio.Context
+
+func init() {
+ var err error
+ audioContext, err = audio.NewContext(sampleRate)
+ if err != nil {
+ log.Fatal(err)
+ }
+}
+
+// stream is an infinite stream of 440 Hz sine wave.
+type stream struct {
+ position int64
+}
+
+// Read is io.Reader's Read.
+//
+// Read fills the data with sine wave samples.
+func (s *stream) Read(data []byte) (int, error) {
+ if len(data)%4 != 0 {
+ return 0, errors.New("len(data) % 4 must be 0")
+ }
+ const length = sampleRate / frequency // TODO: This should be integer?
+ p := s.position / 4
+ for i := 0; i < len(data)/4; i++ {
+ const max = (1<<15 - 1) / 2
+ b := int16(math.Sin(2*math.Pi*float64(p)/length) * max)
+ data[4*i] = byte(b)
+ data[4*i+1] = byte(b >> 8)
+ data[4*i+2] = byte(b)
+ data[4*i+3] = byte(b >> 8)
+ p++
+ }
+ s.position += int64(len(data))
+ s.position %= length * 4
+ return len(data), nil
+}
+
+// Seek is io.Seeker's Seek.
+//
+// whence must be io.SeekStart or io.SeekCurrent.
+func (s *stream) Seek(offset int64, whence int) (int64, error) {
+ const length = sampleRate / frequency
+ switch whence {
+ case io.SeekStart:
+ s.position = offset
+ case io.SeekCurrent:
+ s.position += offset
+ default:
+ return 0, errors.New("whence must be io.SeekStart or io.SeekCurrent")
+ }
+ s.position %= length * 4
+ return s.position, nil
+}
+
+// Close is io.Closer's Close.
+func (s *stream) Close() error {
+ return nil
+}
+
+var player *audio.Player
+
+func update(screen *ebiten.Image) error {
+ if player == nil {
+ // Pass the (infinite) stream to audio.NewPlayer.
+ // After calling Play, the stream never ends as long as the player object lives.
+ var err error
+ player, err = audio.NewPlayer(audioContext, &stream{})
+ if err != nil {
+ return err
+ }
+ player.Play()
+ }
+ if ebiten.IsRunningSlowly() {
+ return nil
+ }
+ msg := fmt.Sprintf("FPS: %0.2f\nThis is an example using infinite audio stream.", ebiten.CurrentFPS())
+ ebitenutil.DebugPrint(screen, msg)
+ return nil
+}
+
+func main() {
+ if err := ebiten.Run(update, screenWidth, screenHeight, 2, "Sine Wave (Ebiten Demo)"); err != nil {
+ log.Fatal(err)
+ }
+}
+
+
+
+
+
+
+
+
diff --git a/docs/images/examples/flood.png b/docs/images/examples/flood.png
new file mode 100644
index 000000000..27157e940
Binary files /dev/null and b/docs/images/examples/flood.png differ
diff --git a/docs/images/examples/mandelbrot.png b/docs/images/examples/mandelbrot.png
new file mode 100644
index 000000000..4bb780a80
Binary files /dev/null and b/docs/images/examples/mandelbrot.png differ
diff --git a/docs/images/examples/sinewave.png b/docs/images/examples/sinewave.png
new file mode 100644
index 000000000..7df50ae4e
Binary files /dev/null and b/docs/images/examples/sinewave.png differ
diff --git a/docs/index.html b/docs/index.html
index ef53dd9ef..64e653218 100644
--- a/docs/index.html
+++ b/docs/index.html
@@ -60,10 +60,20 @@
Examples
+ Games
+
+
+
+
+
+
+
Graphics
+
+
@@ -76,6 +86,8 @@
+
+
@@ -108,14 +120,8 @@
-
-
- Game
-