diff --git a/example/generate.go b/example/generate.go new file mode 100644 index 000000000..a392de694 --- /dev/null +++ b/example/generate.go @@ -0,0 +1,18 @@ +// Copyright 2015 Hajime Hoshi +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +//go:generate go run keyboard/keyboard/gen.go +//go:generate gofmt -w . + +package example diff --git a/example/images/keyboard/keyboard.png b/example/images/keyboard/keyboard.png new file mode 100644 index 000000000..dc3693760 Binary files /dev/null and b/example/images/keyboard/keyboard.png differ diff --git a/example/internal/font.go b/example/internal/font.go index c8a81ebea..3951552d6 100644 --- a/example/internal/font.go +++ b/example/internal/font.go @@ -19,6 +19,8 @@ import ( "github.com/hajimehoshi/ebiten/ebitenutil" "image/color" "math" + "path/filepath" + "runtime" "strings" ) @@ -40,7 +42,9 @@ func (f *Font) TextWidth(str string) int { } func init() { - arcadeFontImage, _, err := ebitenutil.NewImageFromFile("images/arcadefont.png", ebiten.FilterNearest) + _, path, _, _ := runtime.Caller(0) + arcadeFontPath := filepath.Join(filepath.Dir(path), "..", "images", "arcadefont.png") + arcadeFontImage, _, err := ebitenutil.NewImageFromFile(arcadeFontPath, ebiten.FilterNearest) if err != nil { panic(err) } diff --git a/example/keyboard/keyboard/gen.go b/example/keyboard/keyboard/gen.go new file mode 100644 index 000000000..3fb8b4f2e --- /dev/null +++ b/example/keyboard/keyboard/gen.go @@ -0,0 +1,169 @@ +// Copyright 2015 Hajime Hoshi +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// +build ignore + +package main + +import ( + "github.com/hajimehoshi/ebiten" + "github.com/hajimehoshi/ebiten/example/internal" + einternal "github.com/hajimehoshi/ebiten/internal" + "image" + "image/color" + "image/png" + "log" + "os" + "text/template" +) + +var keyboardKeys = [][]string{ + {"Esc", "1", "2", "3", "4", "5", "6", "7", "8", "9", "0", " ", " ", " ", "Del"}, + {"Tab", "Q", "W", "E", "R", "T", "Y", "U", "I", "O", "P", " ", " ", "BS"}, + {"Ctrl", "A", "S", "D", "F", "G", "H", "J", "K", "L", " ", " ", "Enter"}, + {"Shift", "Z", "X", "C", "V", "B", "N", "M", ",", ".", " ", " "}, + {" ", "Alt", "Space", " ", " "}, + {}, + {"", "Up", ""}, + {"Left", "Down", "Right"}, +} + +func drawKey(t *ebiten.Image, name string, x, y, width int) { + const height = 16 + width-- + c := color.White + t.DrawLine(x, y+3, x, y+height-3, c) + t.DrawLine(x+width-1, y+3, x+width-1, y+height-3, c) + t.DrawLine(x+3, y, x+width-3, y, c) + t.DrawLine(x+3, y+height-1, x+width-3, y+height-1, c) + + t.DrawLine(x, y+3, x+3, y, c) + t.DrawLine(x+width-4, y, x+width-1, y+3, c) + t.DrawLine(x, y+height-4, x+3, y+height-1, c) + t.DrawLine(x+width-1, y+height-4, x+width-4, y+height-1, c) + + internal.ArcadeFont.DrawText(t, name, x+4, y+5, 1, color.White) +} + +func outputKeyboardImage() (map[string]image.Rectangle, error) { + keyMap := map[string]image.Rectangle{} + img, err := ebiten.NewImage(320, 240, ebiten.FilterNearest) + if err != nil { + return nil, err + } + x, y := 0, 0 + for j, line := range keyboardKeys { + x = 0 + const height = 18 + for i, key := range line { + width := 16 + switch j { + default: + switch i { + case 0: + width = 16 + 8*(j+2) + case len(line) - 1: + width = 16 + 8*(j+2) + } + case 4: + switch i { + case 0: + width = 16 + 8*(j+2) + case 1: + width = 16 * 2 + case 2: + width = 16 * 5 + case 3: + width = 16 * 2 + case 4: + width = 16 + 8*(j+2) + } + case 6, 7: + width = 16 * 3 + } + if key != "" { + drawKey(img, key, x, y, width) + if key != " " { + keyMap[key] = image.Rect(x, y, x+width, y+height) + } + } + x += width + } + y += height + } + + f, err := os.Create("images/keyboard/keyboard.png") + if err != nil { + return nil, err + } + defer f.Close() + if err := png.Encode(f, img); err != nil { + return nil, err + } + return keyMap, nil +} + +const keyRectTmpl = `{{.License}} + +// DO NOT EDIT: This file is auto-generated by genkeys.go. + +package keyboard + +import ( + "image" +) + +var keyboardKeyRects = map[string]image.Rectangle{} + +func init() { +{{range $key, $rect := .KeyRectsMap}} keyboardKeyRects["{{$key}}"] = image.Rect({{$rect.Min.X}}, {{$rect.Min.Y}}, {{$rect.Max.X}}, {{$rect.Max.Y}}) +{{end}}} + +func KeyRect(name string) (image.Rectangle, bool) { + r, ok := keyboardKeyRects[name] + return r, ok +}` + +func outputKeyRectsGo(k map[string]image.Rectangle) error { + license, err := einternal.LicenseComment() + if err != nil { + return err + } + path := "keyboard/keyboard/keyrects.go" + + f, err := os.Create(path) + if err != nil { + return err + } + defer f.Close() + + tmpl, err := template.New(path).Parse(keyRectTmpl) + if err != nil { + return err + } + return tmpl.Execute(f, map[string]interface{}{ + "License": license, + "KeyRectsMap": k, + }) +} + +func main() { + m, err := outputKeyboardImage() + if err != nil { + log.Fatal(err) + } + if err := outputKeyRectsGo(m); err != nil { + log.Fatal(err) + } +} diff --git a/example/keyboard/keyboard/keyrects.go b/example/keyboard/keyboard/keyrects.go new file mode 100644 index 000000000..b301e4515 --- /dev/null +++ b/example/keyboard/keyboard/keyrects.go @@ -0,0 +1,82 @@ +// Copyright 2015 Hajime Hoshi +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// DO NOT EDIT: This file is auto-generated by genkeys.go. + +package keyboard + +import ( + "image" +) + +var keyboardKeyRects = map[string]image.Rectangle{} + +func init() { + keyboardKeyRects[","] = image.Rect(168, 54, 184, 72) + keyboardKeyRects["."] = image.Rect(184, 54, 200, 72) + keyboardKeyRects["0"] = image.Rect(176, 0, 192, 18) + keyboardKeyRects["1"] = image.Rect(32, 0, 48, 18) + keyboardKeyRects["2"] = image.Rect(48, 0, 64, 18) + keyboardKeyRects["3"] = image.Rect(64, 0, 80, 18) + keyboardKeyRects["4"] = image.Rect(80, 0, 96, 18) + keyboardKeyRects["5"] = image.Rect(96, 0, 112, 18) + keyboardKeyRects["6"] = image.Rect(112, 0, 128, 18) + keyboardKeyRects["7"] = image.Rect(128, 0, 144, 18) + keyboardKeyRects["8"] = image.Rect(144, 0, 160, 18) + keyboardKeyRects["9"] = image.Rect(160, 0, 176, 18) + keyboardKeyRects["A"] = image.Rect(48, 36, 64, 54) + keyboardKeyRects["Alt"] = image.Rect(64, 72, 96, 90) + keyboardKeyRects["B"] = image.Rect(120, 54, 136, 72) + keyboardKeyRects["BS"] = image.Rect(232, 18, 272, 36) + keyboardKeyRects["C"] = image.Rect(88, 54, 104, 72) + keyboardKeyRects["Ctrl"] = image.Rect(0, 36, 48, 54) + keyboardKeyRects["D"] = image.Rect(80, 36, 96, 54) + keyboardKeyRects["Del"] = image.Rect(240, 0, 272, 18) + keyboardKeyRects["Down"] = image.Rect(48, 126, 96, 144) + keyboardKeyRects["E"] = image.Rect(72, 18, 88, 36) + keyboardKeyRects["Enter"] = image.Rect(224, 36, 272, 54) + keyboardKeyRects["Esc"] = image.Rect(0, 0, 32, 18) + keyboardKeyRects["F"] = image.Rect(96, 36, 112, 54) + keyboardKeyRects["G"] = image.Rect(112, 36, 128, 54) + keyboardKeyRects["H"] = image.Rect(128, 36, 144, 54) + keyboardKeyRects["I"] = image.Rect(152, 18, 168, 36) + keyboardKeyRects["J"] = image.Rect(144, 36, 160, 54) + keyboardKeyRects["K"] = image.Rect(160, 36, 176, 54) + keyboardKeyRects["L"] = image.Rect(176, 36, 192, 54) + keyboardKeyRects["Left"] = image.Rect(0, 126, 48, 144) + keyboardKeyRects["M"] = image.Rect(152, 54, 168, 72) + keyboardKeyRects["N"] = image.Rect(136, 54, 152, 72) + keyboardKeyRects["O"] = image.Rect(168, 18, 184, 36) + keyboardKeyRects["P"] = image.Rect(184, 18, 200, 36) + keyboardKeyRects["Q"] = image.Rect(40, 18, 56, 36) + keyboardKeyRects["R"] = image.Rect(88, 18, 104, 36) + keyboardKeyRects["Right"] = image.Rect(96, 126, 144, 144) + keyboardKeyRects["S"] = image.Rect(64, 36, 80, 54) + keyboardKeyRects["Shift"] = image.Rect(0, 54, 56, 72) + keyboardKeyRects["Space"] = image.Rect(96, 72, 176, 90) + keyboardKeyRects["T"] = image.Rect(104, 18, 120, 36) + keyboardKeyRects["Tab"] = image.Rect(0, 18, 40, 36) + keyboardKeyRects["U"] = image.Rect(136, 18, 152, 36) + keyboardKeyRects["Up"] = image.Rect(48, 108, 96, 126) + keyboardKeyRects["V"] = image.Rect(104, 54, 120, 72) + keyboardKeyRects["W"] = image.Rect(56, 18, 72, 36) + keyboardKeyRects["X"] = image.Rect(72, 54, 88, 72) + keyboardKeyRects["Y"] = image.Rect(120, 18, 136, 36) + keyboardKeyRects["Z"] = image.Rect(56, 54, 72, 72) +} + +func KeyRect(name string) (image.Rectangle, bool) { + r, ok := keyboardKeyRects[name] + return r, ok +} diff --git a/example/keyboard/main.go b/example/keyboard/main.go index 9635ea3b9..72d1221a0 100644 --- a/example/keyboard/main.go +++ b/example/keyboard/main.go @@ -17,10 +17,9 @@ package main import ( "github.com/hajimehoshi/ebiten" "github.com/hajimehoshi/ebiten/ebitenutil" + "github.com/hajimehoshi/ebiten/example/keyboard/keyboard" "log" - "sort" "strconv" - "strings" ) const ( @@ -28,13 +27,23 @@ const ( screenHeight = 240 ) +var keyboardImage *ebiten.Image + +func init() { + var err error + keyboardImage, _, err = ebitenutil.NewImageFromFile("images/keyboard/keyboard.png", ebiten.FilterNearest) + if err != nil { + log.Fatal(err) + } +} + var keyNames = map[ebiten.Key]string{ - ebiten.KeyBackspace: "Backspace", - ebiten.KeyComma: "','", - ebiten.KeyDelete: "Delete", + ebiten.KeyBackspace: "BS", + ebiten.KeyComma: ",", + ebiten.KeyDelete: "Del", ebiten.KeyEnter: "Enter", ebiten.KeyEscape: "Esc", - ebiten.KeyPeriod: "'.'", + ebiten.KeyPeriod: ".", ebiten.KeySpace: "Space", ebiten.KeyTab: "Tab", @@ -50,7 +59,32 @@ var keyNames = map[ebiten.Key]string{ ebiten.KeyAlt: "Alt", } +type pressedKeysParts []string + +func (p pressedKeysParts) Len() int { + return len(p) +} + +func (p pressedKeysParts) Dst(i int) (x0, y0, x1, y1 int) { + k := p[i] + r, ok := keyboard.KeyRect(k) + if !ok { + return 0, 0, 0, 0 + } + return r.Min.X, r.Min.Y, r.Max.X, r.Max.Y +} + +func (p pressedKeysParts) Src(i int) (x0, y0, x1, y1 int) { + return p.Dst(i) +} + func update(screen *ebiten.Image) error { + const offsetX, offsetY = 24, 40 + op := &ebiten.DrawImageOptions{} + op.GeoM.Translate(offsetX, offsetY) + op.ColorM.Scale(0.5, 0.5, 0.5, 1) + screen.DrawImage(keyboardImage, op) + pressed := []string{} for i := 0; i <= 9; i++ { if ebiten.IsKeyPressed(ebiten.Key(i) + ebiten.Key0) { @@ -72,9 +106,13 @@ func update(screen *ebiten.Image) error { pressed = append(pressed, name) } } - sort.Strings(pressed) - str := "Pressed Keys: " + strings.Join(pressed, ", ") - ebitenutil.DebugPrint(screen, str) + + op = &ebiten.DrawImageOptions{ + ImageParts: pressedKeysParts(pressed), + } + op.GeoM.Translate(offsetX, offsetY) + screen.DrawImage(keyboardImage, op) + return nil } diff --git a/genkeys.go b/genkeys.go index 8192099f2..8502d8424 100644 --- a/genkeys.go +++ b/genkeys.go @@ -22,12 +22,11 @@ package main import ( - "io/ioutil" + "github.com/hajimehoshi/ebiten/internal" "log" "os" "sort" "strconv" - "strings" "text/template" ) @@ -224,12 +223,10 @@ func (k KeyNames) Swap(i, j int) { } func main() { - l, err := ioutil.ReadFile("license.txt") + license, err := internal.LicenseComment() if err != nil { log.Fatal(err) } - lines := strings.Split(string(l), "\n") - license := "// " + strings.Join(lines[:len(lines)-1], "\n// ") notice := "DO NOT EDIT: This file is auto-generated by genkeys.go." @@ -263,13 +260,15 @@ func main() { log.Fatal(err) } // NOTE: According to godoc, maps are automatically sorted by key. - tmpl.Execute(f, map[string]interface{}{ + if err := tmpl.Execute(f, map[string]interface{}{ "License": license, "Notice": notice, "KeyCodeToName": keyCodeToName, "Codes": codes, "KeyNames": names, "KeyNamesWithoutMods": namesWithoutMods, - }) + }); err != nil { + log.Fatal(err) + } } } diff --git a/internal/assets/bindata.go b/internal/assets/bindata.go index 08c28cc18..6db365d16 100644 --- a/internal/assets/bindata.go +++ b/internal/assets/bindata.go @@ -53,7 +53,7 @@ func text_png() (*asset, error) { return nil, err } - info := bindata_file_info{name: "text.png", size: 2058, mode: os.FileMode(420), modTime: time.Unix(1419689280, 0)} + info := bindata_file_info{name: "text.png", size: 2058, mode: os.FileMode(420), modTime: time.Unix(1420820510, 0)} a := &asset{bytes: bytes, info: info} return a, nil } diff --git a/internal/license.go b/internal/license.go new file mode 100644 index 000000000..864118f7c --- /dev/null +++ b/internal/license.go @@ -0,0 +1,34 @@ +// Copyright 2015 Hajime Hoshi +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package internal + +import ( + "io/ioutil" + "path/filepath" + "runtime" + "strings" +) + +func LicenseComment() (string, error) { + _, path, _, _ := runtime.Caller(0) + licensePath := filepath.Join(filepath.Dir(path), "..", "license.txt") + l, err := ioutil.ReadFile(licensePath) + if err != nil { + return "", err + } + lines := strings.Split(string(l), "\n") + license := "// " + strings.Join(lines[:len(lines)-1], "\n// ") + return license, nil +}