4 Commits

Author SHA1 Message Date
b384795e53 added --tps and --background 2024-03-25 20:32:09 +01:00
b41d23a2fd + screenshot 2024-03-25 18:33:02 +01:00
dacbb5567c +logo 2024-03-25 18:26:53 +01:00
6cb30560d0 added Zyko0/Ebiary/asset for live reloading 2024-03-25 18:09:06 +01:00
8 changed files with 97 additions and 38 deletions

BIN
.github/assets/logo.png vendored Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 22 KiB

BIN
.github/assets/screenshot.png vendored Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 253 KiB

View File

@@ -1,9 +1,21 @@
# kage-viewer - Viewer for shaders written in Kage, similar to glslviewer # kage-viewer - Viewer for shaders written in Kage, similar to glslviewer
![Logo](https://github.com/TLINDEN/kageviewer/blob/main/.github/assets/logo.png)
[![License](https://img.shields.io/badge/license-GPL-blue.svg)](https://github.com/tlinden/kage-viewer/blob/master/LICENSE) [![License](https://img.shields.io/badge/license-GPL-blue.svg)](https://github.com/tlinden/kage-viewer/blob/master/LICENSE)
[![Go Report Card](https://goreportcard.com/badge/github.com/tlinden/kage-viewer)](https://goreportcard.com/report/github.com/tlinden/kage-viewer) [![Go Report Card](https://goreportcard.com/badge/github.com/tlinden/kage-viewer)](https://goreportcard.com/report/github.com/tlinden/kage-viewer)
This little tool can be used to test shaders written in [Kage](https://ebitengine.org/en/documents/shader.html), a shader meta language for [Ebitengine](https://github.com/hajimehoshi/ebiten). This little tool can be used to test shaders written in
[Kage](https://ebitengine.org/en/documents/shader.html), a shader meta
language for
[Ebitengine](https://github.com/hajimehoshi/ebiten). kage-viewer
reloads changed assets, which allows you to develop your shader and
see live, how it responds to your changes. If loading fails, an error
will be printed to STDOUT. The same applies for images.
## Screenshot
![Screenshot](https://github.com/TLINDEN/kageviewer/blob/main/.github/assets/screenshot.png)
## Installation ## Installation
@@ -66,6 +78,8 @@ Options:
-s --shader <kage file> Shader to run -s --shader <kage file> Shader to run
-g --geometry <WIDTHxHEIGHT> Window size -g --geometry <WIDTHxHEIGHT> Window size
-p --position <XxY> Position of image0 -p --position <XxY> Position of image0
-b --background <png file> Image to load as background
-t --tps <ticks/s> At how many ticks per second to run
--map-flag <name> Map Flag uniform to <name> --map-flag <name> Map Flag uniform to <name>
--map-ticks <name> Map Flag uniform to <name> --map-ticks <name> Map Flag uniform to <name>
--map-slider <name> Map Flag uniform to <name> --map-slider <name> Map Flag uniform to <name>
@@ -129,7 +143,7 @@ Possible parameters equal the long command line options.
- [X] Implement loading of images and shader files - [X] Implement loading of images and shader files
- [X] Implement basic shader rendering and user input - [X] Implement basic shader rendering and user input
- [ ] Add custom uniforms (maybe using lua code?) - [ ] Add custom uniforms (maybe using lua code?)
- [ ] Provide a way to respond live to shader code changes (use lua as - [x] Provide a way to respond live to shader code changes (use lua as
well?) well?)
# Report bugs # Report bugs

View File

@@ -32,7 +32,7 @@ import (
) )
const ( const (
VERSION string = "0.0.2" VERSION string = "0.0.4"
Usage string = `This is kage-viewer, a shader viewer. Usage string = `This is kage-viewer, a shader viewer.
Usage: kage-viewer [-vd] [-c <config file>] [-g geom] [-p geom] \ Usage: kage-viewer [-vd] [-c <config file>] [-g geom] [-p geom] \
@@ -44,6 +44,8 @@ Options:
-s --shader <kage file> Shader to run -s --shader <kage file> Shader to run
-g --geometry <WIDTHxHEIGHT> Window size -g --geometry <WIDTHxHEIGHT> Window size
-p --position <XxY> Position of image0 -p --position <XxY> Position of image0
-b --background <png file> Image to load as background
-t --tps <ticks/s> At how many ticks per second to run
--map-flag <name> Map Flag uniform to <name> --map-flag <name> Map Flag uniform to <name>
--map-ticks <name> Map Flag uniform to <name> --map-ticks <name> Map Flag uniform to <name>
--map-slider <name> Map Flag uniform to <name> --map-slider <name> Map Flag uniform to <name>
@@ -54,13 +56,15 @@ Options:
) )
type Config struct { type Config struct {
Showversion bool `koanf:"version"` // -v Showversion bool `koanf:"version"` // -v
Debug bool `koanf:"debug"` // -d Debug bool `koanf:"debug"` // -d
Config string `koanf:"config"` // -c Config string `koanf:"config"` // -c
Image []string `koanf:"image"` // -i Image []string `koanf:"image"` // -i
Shader string `koanf:"shader"` // -s Shader string `koanf:"shader"` // -s
Geo string `koanf:"geometry"` // -g Background string `koanf:"background"` // -b
Posision string `koanf:"position"` // -p TPS int `koanf:"tps"` // -t
Geo string `koanf:"geometry"` // -g
Posision string `koanf:"position"` // -p
Flag string `koanf:"map-flag"` Flag string `koanf:"map-flag"`
Ticks string `koanf:"map-ticks"` Ticks string `koanf:"map-ticks"`
Mouse string `koanf:"map-mouse"` Mouse string `koanf:"map-mouse"`
@@ -91,6 +95,8 @@ func InitConfig() (*Config, error) {
flagset.StringP("map-ticks", "", "Ticks", "map ticks uniform") flagset.StringP("map-ticks", "", "Ticks", "map ticks uniform")
flagset.StringP("map-mouse", "", "Mouse", "map mouse uniform") flagset.StringP("map-mouse", "", "Mouse", "map mouse uniform")
flagset.StringP("map-slider", "", "Slider", "map slider uniform") flagset.StringP("map-slider", "", "Slider", "map slider uniform")
flagset.StringP("background", "b", "", "background image")
flagset.IntP("tps", "t", 60, "ticks per second")
if err := flagset.Parse(os.Args[1:]); err != nil { if err := flagset.Parse(os.Args[1:]); err != nil {
return nil, fmt.Errorf("failed to parse program arguments: %w", err) return nil, fmt.Errorf("failed to parse program arguments: %w", err)

79
game.go
View File

@@ -24,17 +24,20 @@ import (
"log/slog" "log/slog"
"os" "os"
"github.com/Zyko0/Ebiary/asset"
"github.com/hajimehoshi/ebiten/v2" "github.com/hajimehoshi/ebiten/v2"
"github.com/hajimehoshi/ebiten/v2/inpututil" "github.com/hajimehoshi/ebiten/v2/inpututil"
) )
type Game struct { type Game struct {
Conf *Config Conf *Config
Images []*ebiten.Image Images []*asset.LiveAsset[*ebiten.Image]
Shader *ebiten.Shader Shader *asset.LiveAsset[*ebiten.Shader]
Ticks int Cursor []float64
Slider float64 Ticks int
Flag int Slider float64
Flag int
Background *asset.LiveAsset[*ebiten.Image]
} }
func LoadImage(name string) (*ebiten.Image, error) { func LoadImage(name string) (*ebiten.Image, error) {
@@ -55,26 +58,35 @@ func LoadImage(name string) (*ebiten.Image, error) {
func (game *Game) Init() error { func (game *Game) Init() error {
for _, image := range game.Conf.Image { for _, image := range game.Conf.Image {
slog.Debug("Loading images", "image", image) slog.Debug("Loading images", "image", image)
img, err := LoadImage(image) //img, err := LoadImage(image)
img, err := asset.NewLiveAsset[*ebiten.Image](image)
if err != nil { if err != nil {
return err return fmt.Errorf("failed to load image %s: %s", image, err)
} }
game.Images = append(game.Images, img) game.Images = append(game.Images, img)
} }
data, err := os.ReadFile(game.Conf.Shader) shader, err := asset.NewLiveAsset[*ebiten.Shader](game.Conf.Shader)
if err != nil { if err != nil {
return fmt.Errorf("failed to load shader %s: %s", game.Conf.Shader, err) return fmt.Errorf("failed to load shader %s: %s", game.Conf.Shader, err)
} }
shader, err := ebiten.NewShader(data) if game.Conf.Background != "" {
if err != nil { slog.Debug("Loading background", "image", game.Conf.Background)
return fmt.Errorf("failed to create new shader %s: %s", game.Conf.Shader, err)
img, err := asset.NewLiveAsset[*ebiten.Image](game.Conf.Background)
if err != nil {
return fmt.Errorf("failed to load image %s: %s", game.Conf.Background, err)
}
game.Background = img
} }
game.Shader = shader game.Shader = shader
ebiten.SetMaxTPS(game.Conf.TPS)
return nil return nil
} }
@@ -120,32 +132,61 @@ func (g *Game) Down() {
} }
func (game *Game) Update() error { func (game *Game) Update() error {
if game.CheckInput() { for _, image := range game.Images {
slog.Debug("Key pressed", "Slider", game.Slider, "Flag", game.Flag) if image.Error() != nil {
fmt.Println("warn: image reloading error:", image.Error())
}
} }
if game.Shader.Error() != nil {
fmt.Println("warn: shader reloading error:", game.Shader.Error())
}
if game.Background != nil {
if game.Background.Error() != nil {
fmt.Println("warn: background image reloading error:", game.Background.Error())
}
}
if game.CheckInput() {
slog.Debug("Key pressed",
game.Conf.Flag, game.Flag,
game.Conf.Slider, game.Slider,
game.Conf.Ticks, fmt.Sprintf("%.02f", float64(game.Ticks)/60),
game.Conf.Mouse, fmt.Sprintf("%.02f, %.02f", game.Cursor[0], game.Cursor[1]),
)
}
mousex, mousey := ebiten.CursorPosition()
game.Cursor = []float64{float64(mousex), float64(mousey)}
game.Ticks++ game.Ticks++
return nil return nil
} }
func (game *Game) Draw(screen *ebiten.Image) { func (game *Game) Draw(screen *ebiten.Image) {
op := &ebiten.DrawRectShaderOptions{} if game.Background != nil {
op := &ebiten.DrawImageOptions{}
screen.DrawImage(game.Background.Value(), op)
}
mousex, mousey := ebiten.CursorPosition() op := &ebiten.DrawRectShaderOptions{}
op.Uniforms = map[string]any{ op.Uniforms = map[string]any{
game.Conf.Flag: game.Flag, game.Conf.Flag: game.Flag,
game.Conf.Slider: game.Slider, game.Conf.Slider: game.Slider,
game.Conf.Ticks: float64(game.Ticks) / 60, game.Conf.Ticks: float64(game.Ticks) / 60,
game.Conf.Mouse: []float64{float64(mousex), float64(mousey)}, game.Conf.Mouse: game.Cursor,
} }
copy(op.Images[:3], game.Images) for idx, image := range game.Images {
op.Images[idx] = image.Value()
}
op.GeoM.Translate(float64(game.Conf.X), float64(game.Conf.Y)) op.GeoM.Translate(float64(game.Conf.X), float64(game.Conf.Y))
screen.DrawRectShader(game.Conf.Width, game.Conf.Height, game.Shader, op) screen.DrawRectShader(game.Conf.Width, game.Conf.Height, game.Shader.Value(), op)
} }
func (game *Game) Layout(outsideWidth, outsideHeight int) (int, int) { func (game *Game) Layout(outsideWidth, outsideHeight int) (int, int) {

3
go.mod
View File

@@ -3,9 +3,10 @@ module github.com/TLINDEN/kage-viewer
go 1.22 go 1.22
require ( require (
github.com/Zyko0/Ebiary/asset v0.0.0-20240304185439-be56fe8a2a6a // indirect
github.com/ebitengine/purego v0.6.0 // indirect github.com/ebitengine/purego v0.6.0 // indirect
github.com/fatih/color v1.16.0 // indirect github.com/fatih/color v1.16.0 // indirect
github.com/fsnotify/fsnotify v1.6.0 // indirect github.com/fsnotify/fsnotify v1.7.0 // indirect
github.com/go-viper/mapstructure/v2 v2.0.0-alpha.1 // indirect github.com/go-viper/mapstructure/v2 v2.0.0-alpha.1 // indirect
github.com/hajimehoshi/ebiten/v2 v2.6.7 // indirect github.com/hajimehoshi/ebiten/v2 v2.6.7 // indirect
github.com/jezek/xgb v1.1.0 // indirect github.com/jezek/xgb v1.1.0 // indirect

4
go.sum
View File

@@ -1,9 +1,13 @@
github.com/Zyko0/Ebiary/asset v0.0.0-20240304185439-be56fe8a2a6a h1:kn4fhGvVA6T1lK7qWujIj3m7e9imCZe4MHBuBeflKgU=
github.com/Zyko0/Ebiary/asset v0.0.0-20240304185439-be56fe8a2a6a/go.mod h1:4CqqwHRUbvGBpBd5ye4MxDA4k/XtZqrAD1sg9uxmcYI=
github.com/ebitengine/purego v0.6.0 h1:Yo9uBc1x+ETQbfEaf6wcBsjrQfCEnh/gaGUg7lguEJY= github.com/ebitengine/purego v0.6.0 h1:Yo9uBc1x+ETQbfEaf6wcBsjrQfCEnh/gaGUg7lguEJY=
github.com/ebitengine/purego v0.6.0/go.mod h1:ah1In8AOtksoNK6yk5z1HTJeUkC1Ez4Wk2idgGslMwQ= github.com/ebitengine/purego v0.6.0/go.mod h1:ah1In8AOtksoNK6yk5z1HTJeUkC1Ez4Wk2idgGslMwQ=
github.com/fatih/color v1.16.0 h1:zmkK9Ngbjj+K0yRhTVONQh1p/HknKYSlNT+vZCzyokM= github.com/fatih/color v1.16.0 h1:zmkK9Ngbjj+K0yRhTVONQh1p/HknKYSlNT+vZCzyokM=
github.com/fatih/color v1.16.0/go.mod h1:fL2Sau1YI5c0pdGEVCbKQbLXB6edEj1ZgiY4NijnWvE= github.com/fatih/color v1.16.0/go.mod h1:fL2Sau1YI5c0pdGEVCbKQbLXB6edEj1ZgiY4NijnWvE=
github.com/fsnotify/fsnotify v1.6.0 h1:n+5WquG0fcWoWp6xPWfHdbskMCQaFnG6PfBrh1Ky4HY= github.com/fsnotify/fsnotify v1.6.0 h1:n+5WquG0fcWoWp6xPWfHdbskMCQaFnG6PfBrh1Ky4HY=
github.com/fsnotify/fsnotify v1.6.0/go.mod h1:sl3t1tCWJFWoRz9R8WJCbQihKKwmorjAbSClcnxKAGw= github.com/fsnotify/fsnotify v1.6.0/go.mod h1:sl3t1tCWJFWoRz9R8WJCbQihKKwmorjAbSClcnxKAGw=
github.com/fsnotify/fsnotify v1.7.0 h1:8JEhPFa5W2WU7YfeZzPNqzMP6Lwt7L2715Ggo0nosvA=
github.com/fsnotify/fsnotify v1.7.0/go.mod h1:40Bi/Hjc2AVfZrqy+aj+yEI+/bRxZnMJyTJwOpGvigM=
github.com/go-viper/mapstructure/v2 v2.0.0-alpha.1 h1:TQcrn6Wq+sKGkpyPvppOz99zsMBaUOKXq6HSv655U1c= github.com/go-viper/mapstructure/v2 v2.0.0-alpha.1 h1:TQcrn6Wq+sKGkpyPvppOz99zsMBaUOKXq6HSv655U1c=
github.com/go-viper/mapstructure/v2 v2.0.0-alpha.1/go.mod h1:oJDH3BJKyqBA2TXFhDsKDGDTlndYOZ6rGS0BRZIxGhM= github.com/go-viper/mapstructure/v2 v2.0.0-alpha.1/go.mod h1:oJDH3BJKyqBA2TXFhDsKDGDTlndYOZ6rGS0BRZIxGhM=
github.com/hajimehoshi/ebiten/v2 v2.6.7 h1:rxlMxu487wZN/JteykmuGdO1qotOolL8vJDU85lPh7A= github.com/hajimehoshi/ebiten/v2 v2.6.7 h1:rxlMxu487wZN/JteykmuGdO1qotOolL8vJDU85lPh7A=

View File

@@ -21,7 +21,6 @@ import (
"fmt" "fmt"
"log" "log"
"os" "os"
"runtime/debug"
"log/slog" "log/slog"
@@ -46,7 +45,6 @@ func main() {
if conf.Debug { if conf.Debug {
logLevel := &slog.LevelVar{} logLevel := &slog.LevelVar{}
// we're using a more verbose logger in debug mode // we're using a more verbose logger in debug mode
buildInfo, _ := debug.ReadBuildInfo()
opts := &yadu.Options{ opts := &yadu.Options{
Level: logLevel, Level: logLevel,
AddSource: true, AddSource: true,
@@ -55,12 +53,7 @@ func main() {
logLevel.Set(slog.LevelDebug) logLevel.Set(slog.LevelDebug)
handler := yadu.NewHandler(os.Stdout, opts) handler := yadu.NewHandler(os.Stdout, opts)
debuglogger := slog.New(handler).With( debuglogger := slog.New(handler)
slog.Group("program_info",
slog.Int("pid", os.Getpid()),
slog.String("go_version", buildInfo.GoVersion),
),
)
slog.SetDefault(debuglogger) slog.SetDefault(debuglogger)
} }