ebiten/internal/gamepaddb/gen_dbs.go
Kenny Goodin ca8ee8e23b internal/gamepaddb: generate respective controller dbs for each platform
Replace singular embedded controller database file with separate generated
files for each supported platform. The controller database file is some
~500KB, so this change should reduce the overall binary size per
platform.
2024-03-26 12:07:23 -04:00

162 lines
6.2 KiB
Go

// Copyright 2024 The Ebitengine Authors
//
// 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:build ignore
// This program generates platform-specific controller dbs. It can be invoked by running
// go generate
package main
import (
"bytes"
_ "embed"
"fmt"
"log"
"os"
"path/filepath"
"strings"
"text/template"
)
const license = `// Copyright 2024 The Ebitengine Authors
//
// 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.
`
// gamecontrollerdb.txt is downloaded at https://github.com/mdqinc/SDL_GameControllerDB.
// To update the database file, run:
//
// curl --location --remote-name https://raw.githubusercontent.com/mdqinc/SDL_GameControllerDB/master/gamecontrollerdb.txt
//go:embed gamecontrollerdb.txt
var gamecontrollerdb_txt []byte
// additional GLFW gamepads for Windows
var additionalGLFWGamepads = []byte(`
78696e70757401000000000000000000,XInput Gamepad (GLFW),platform:Windows,a:b0,b:b1,x:b2,y:b3,leftshoulder:b4,rightshoulder:b5,back:b6,start:b7,leftstick:b8,rightstick:b9,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:a4,righttrigger:a5,dpup:h0.1,dpright:h0.2,dpdown:h0.4,dpleft:h0.8,
78696e70757402000000000000000000,XInput Wheel (GLFW),platform:Windows,a:b0,b:b1,x:b2,y:b3,leftshoulder:b4,rightshoulder:b5,back:b6,start:b7,leftstick:b8,rightstick:b9,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:a4,righttrigger:a5,dpup:h0.1,dpright:h0.2,dpdown:h0.4,dpleft:h0.8,
78696e70757403000000000000000000,XInput Arcade Stick (GLFW),platform:Windows,a:b0,b:b1,x:b2,y:b3,leftshoulder:b4,rightshoulder:b5,back:b6,start:b7,leftstick:b8,rightstick:b9,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:a4,righttrigger:a5,dpup:h0.1,dpright:h0.2,dpdown:h0.4,dpleft:h0.8,
78696e70757404000000000000000000,XInput Flight Stick (GLFW),platform:Windows,a:b0,b:b1,x:b2,y:b3,leftshoulder:b4,rightshoulder:b5,back:b6,start:b7,leftstick:b8,rightstick:b9,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:a4,righttrigger:a5,dpup:h0.1,dpright:h0.2,dpdown:h0.4,dpleft:h0.8,
78696e70757405000000000000000000,XInput Dance Pad (GLFW),platform:Windows,a:b0,b:b1,x:b2,y:b3,leftshoulder:b4,rightshoulder:b5,back:b6,start:b7,leftstick:b8,rightstick:b9,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:a4,righttrigger:a5,dpup:h0.1,dpright:h0.2,dpdown:h0.4,dpleft:h0.8,
78696e70757406000000000000000000,XInput Guitar (GLFW),platform:Windows,a:b0,b:b1,x:b2,y:b3,leftshoulder:b4,rightshoulder:b5,back:b6,start:b7,leftstick:b8,rightstick:b9,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:a4,righttrigger:a5,dpup:h0.1,dpright:h0.2,dpdown:h0.4,dpleft:h0.8,
78696e70757408000000000000000000,XInput Drum Kit (GLFW),platform:Windows,a:b0,b:b1,x:b2,y:b3,leftshoulder:b4,rightshoulder:b5,back:b6,start:b7,leftstick:b8,rightstick:b9,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:a4,righttrigger:a5,dpup:h0.1,dpright:h0.2,dpdown:h0.4,dpleft:h0.8,
`)
//go:generate go run gen_dbs.go
func main() {
// Follow the standard comment rule (https://pkg.go.dev/cmd/go#hdr-Generate_Go_files_by_processing_source).
doNotEdit := "// Code generated by gen_dbs.go using 'go generate'. DO NOT EDIT."
type gamePadPlatform struct {
genFileName string
buildTag string
}
supported := map[string]gamePadPlatform{
"Windows": {
genFileName: "windows",
buildTag: "//go:build windows && !microsoftgdk",
},
"Mac OS X": {
genFileName: "macos_darwin",
buildTag: "//go:build darwin && !ios",
},
"Linux": {
genFileName: "linbsd",
buildTag: "//go:build (freebsd || (linux && !android) || netbsd || openbsd) && !nintendosdk && !playstation5",
},
"iOS": {
genFileName: "ios",
buildTag: "//go:build ios",
},
"Android": {
genFileName: "android",
buildTag: "//go:build android",
},
}
tmpl, err := template.ParseFiles("gamepaddb_tmpl.tpl")
if err != nil {
log.Fatal(err)
}
controllerDbs := splitControllerDb(gamecontrollerdb_txt)
for sdlName, platform := range supported {
path := filepath.Join("internal", "gamepaddb", fmt.Sprintf("db_%s.go", platform.genFileName))
f, err := os.Create(path)
if err != nil {
log.Fatal(err)
}
defer f.Close()
controllerDb, ok := controllerDbs[sdlName]
if !ok {
log.Fatalf("failed to find controller db for platform %s in gamecontrollerdb_txt", sdlName)
}
err = tmpl.Execute(f, struct {
License string
DoNotEdit string
BuildTag string
SDLPlatform string
ControllerBytes []byte
GLFWGamePads []byte
}{
License: license,
DoNotEdit: doNotEdit,
BuildTag: platform.buildTag,
SDLPlatform: sdlName,
ControllerBytes: controllerDb,
GLFWGamePads: additionalGLFWGamepads,
})
if err != nil {
log.Fatal(err)
}
}
}
// splitControllerDb maps the game controller db into respective controller definition byte slices for
// each platform
func splitControllerDb(controllerDb []byte) map[string][]byte {
dbs := map[string][]byte{}
// split at #, skip first 3 header chunks
chunks := bytes.Split(controllerDb, []byte{'#'})[3:]
for _, chunk := range chunks {
// find each platform string
lines := bytes.Split(chunk, []byte{'\n'})
if len(lines) == 0 {
continue
}
platform := strings.TrimSpace(string(lines[0]))
// count platform string len + space + newline
bytesRead := len(lines[0]) + 1
dbs[platform] = chunk[bytesRead:]
}
return dbs
}