example/keyboard: Add a keyboard image

This commit is contained in:
Hajime Hoshi 2015-01-18 21:11:03 +09:00
parent a5e335819d
commit ff020e8b1c
9 changed files with 362 additions and 18 deletions

18
example/generate.go Normal file
View File

@ -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

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.1 KiB

View File

@ -19,6 +19,8 @@ import (
"github.com/hajimehoshi/ebiten/ebitenutil" "github.com/hajimehoshi/ebiten/ebitenutil"
"image/color" "image/color"
"math" "math"
"path/filepath"
"runtime"
"strings" "strings"
) )
@ -40,7 +42,9 @@ func (f *Font) TextWidth(str string) int {
} }
func init() { 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 { if err != nil {
panic(err) panic(err)
} }

View File

@ -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)
}
}

View File

@ -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
}

View File

@ -17,10 +17,9 @@ package main
import ( import (
"github.com/hajimehoshi/ebiten" "github.com/hajimehoshi/ebiten"
"github.com/hajimehoshi/ebiten/ebitenutil" "github.com/hajimehoshi/ebiten/ebitenutil"
"github.com/hajimehoshi/ebiten/example/keyboard/keyboard"
"log" "log"
"sort"
"strconv" "strconv"
"strings"
) )
const ( const (
@ -28,13 +27,23 @@ const (
screenHeight = 240 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{ var keyNames = map[ebiten.Key]string{
ebiten.KeyBackspace: "Backspace", ebiten.KeyBackspace: "BS",
ebiten.KeyComma: "','", ebiten.KeyComma: ",",
ebiten.KeyDelete: "Delete", ebiten.KeyDelete: "Del",
ebiten.KeyEnter: "Enter", ebiten.KeyEnter: "Enter",
ebiten.KeyEscape: "Esc", ebiten.KeyEscape: "Esc",
ebiten.KeyPeriod: "'.'", ebiten.KeyPeriod: ".",
ebiten.KeySpace: "Space", ebiten.KeySpace: "Space",
ebiten.KeyTab: "Tab", ebiten.KeyTab: "Tab",
@ -50,7 +59,32 @@ var keyNames = map[ebiten.Key]string{
ebiten.KeyAlt: "Alt", 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 { 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{} pressed := []string{}
for i := 0; i <= 9; i++ { for i := 0; i <= 9; i++ {
if ebiten.IsKeyPressed(ebiten.Key(i) + ebiten.Key0) { if ebiten.IsKeyPressed(ebiten.Key(i) + ebiten.Key0) {
@ -72,9 +106,13 @@ func update(screen *ebiten.Image) error {
pressed = append(pressed, name) pressed = append(pressed, name)
} }
} }
sort.Strings(pressed)
str := "Pressed Keys: " + strings.Join(pressed, ", ") op = &ebiten.DrawImageOptions{
ebitenutil.DebugPrint(screen, str) ImageParts: pressedKeysParts(pressed),
}
op.GeoM.Translate(offsetX, offsetY)
screen.DrawImage(keyboardImage, op)
return nil return nil
} }

View File

@ -22,12 +22,11 @@
package main package main
import ( import (
"io/ioutil" "github.com/hajimehoshi/ebiten/internal"
"log" "log"
"os" "os"
"sort" "sort"
"strconv" "strconv"
"strings"
"text/template" "text/template"
) )
@ -224,12 +223,10 @@ func (k KeyNames) Swap(i, j int) {
} }
func main() { func main() {
l, err := ioutil.ReadFile("license.txt") license, err := internal.LicenseComment()
if err != nil { if err != nil {
log.Fatal(err) 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." notice := "DO NOT EDIT: This file is auto-generated by genkeys.go."
@ -263,13 +260,15 @@ func main() {
log.Fatal(err) log.Fatal(err)
} }
// NOTE: According to godoc, maps are automatically sorted by key. // 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, "License": license,
"Notice": notice, "Notice": notice,
"KeyCodeToName": keyCodeToName, "KeyCodeToName": keyCodeToName,
"Codes": codes, "Codes": codes,
"KeyNames": names, "KeyNames": names,
"KeyNamesWithoutMods": namesWithoutMods, "KeyNamesWithoutMods": namesWithoutMods,
}) }); err != nil {
log.Fatal(err)
}
} }
} }

View File

@ -53,7 +53,7 @@ func text_png() (*asset, error) {
return nil, err 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} a := &asset{bytes: bytes, info: info}
return a, nil return a, nil
} }

34
internal/license.go Normal file
View File

@ -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
}