From 545342262f11ac76d82eb7652f1465f6b8395be7 Mon Sep 17 00:00:00 2001 From: Hajime Hoshi Date: Wed, 24 Jun 2020 01:41:27 +0900 Subject: [PATCH] examples/shader: Show an image --- examples/shader/generate.go | 1 + examples/shader/image.go | 33 +++++++++++++++++++++ examples/shader/image_go.go | 6 ++++ examples/shader/main.go | 59 +++++++++++++++++++++++++++++++++++-- internal/shader/shader.go | 1 + shader.go | 4 ++- 6 files changed, 100 insertions(+), 4 deletions(-) create mode 100644 examples/shader/image.go create mode 100644 examples/shader/image_go.go diff --git a/examples/shader/generate.go b/examples/shader/generate.go index 74805ab2b..dde949220 100644 --- a/examples/shader/generate.go +++ b/examples/shader/generate.go @@ -15,3 +15,4 @@ package main //go:generate file2byteslice -package=main -input=default.go -output=default_go.go -var=default_go +//go:generate file2byteslice -package=main -input=image.go -output=image_go.go -var=image_go diff --git a/examples/shader/image.go b/examples/shader/image.go new file mode 100644 index 000000000..0c05994bc --- /dev/null +++ b/examples/shader/image.go @@ -0,0 +1,33 @@ +// Copyright 2020 The Ebiten 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. + +// +build ignore + +package main + +var Image texture2d + +func Vertex(position vec2, texCoord vec2, color vec4) (vec4, vec2) { + return mat4( + 2/viewportSize().x, 0, 0, 0, + 0, 2/viewportSize().y, 0, 0, + 0, 0, 1, 0, + -1, -1, 0, 1, + ) * vec4(position, 0, 1), texCoord +} + +func Fragment(position vec4, tex vec2) vec4 { + // TODO: Instead of using texture2D directly, define and use special functions for Ebiten images. + return texture2D(Image, tex) +} diff --git a/examples/shader/image_go.go b/examples/shader/image_go.go new file mode 100644 index 000000000..2b7ca81a6 --- /dev/null +++ b/examples/shader/image_go.go @@ -0,0 +1,6 @@ +// Code generated by file2byteslice. DO NOT EDIT. +// (gofmt is fine after generating) + +package main + +var image_go = []byte("// Copyright 2020 The Ebiten Authors\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n// http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\n// +build ignore\n\npackage main\n\nvar Image texture2d\n\nfunc Vertex(position vec2, texCoord vec2, color vec4) (vec4, vec2) {\n\treturn mat4(\n\t\t2/viewportSize().x, 0, 0, 0,\n\t\t0, 2/viewportSize().y, 0, 0,\n\t\t0, 0, 1, 0,\n\t\t-1, -1, 0, 1,\n\t) * vec4(position, 0, 1), texCoord\n}\n\nfunc Fragment(position vec4, tex vec2) vec4 {\n\t// TODO: Instead of using texture2D directly, define and use special functions for Ebiten images.\n\treturn texture2D(Image, tex)\n}\n") diff --git a/examples/shader/main.go b/examples/shader/main.go index e05225153..c28b7ab9f 100644 --- a/examples/shader/main.go +++ b/examples/shader/main.go @@ -17,9 +17,15 @@ package main import ( + "bytes" + "image" + _ "image/jpeg" "log" "github.com/hajimehoshi/ebiten" + "github.com/hajimehoshi/ebiten/ebitenutil" + "github.com/hajimehoshi/ebiten/examples/resources/images" + "github.com/hajimehoshi/ebiten/inpututil" ) const ( @@ -27,8 +33,28 @@ const ( screenHeight = 480 ) +var gophersImage *ebiten.Image + +func init() { + // Decode image from a byte slice instead of a file so that + // this example works in any working directory. + // If you want to use a file, there are some options: + // 1) Use os.Open and pass the file to the image decoder. + // This is a very regular way, but doesn't work on browsers. + // 2) Use ebitenutil.OpenFile and pass the file to the image decoder. + // This works even on browsers. + // 3) Use ebitenutil.NewImageFromFile to create an ebiten.Image directly from a file. + // This also works on browsers. + img, _, err := image.Decode(bytes.NewReader(images.Gophers_jpg)) + if err != nil { + log.Fatal(err) + } + gophersImage, _ = ebiten.NewImageFromImage(img, ebiten.FilterDefault) +} + var shaderSrcs = [][]byte{ default_go, + image_go, } type Game struct { @@ -39,6 +65,15 @@ type Game struct { func (g *Game) Update(screen *ebiten.Image) error { g.time++ + if inpututil.IsKeyJustPressed(ebiten.KeyDown) { + g.idx++ + g.idx %= len(shaderSrcs) + } + if inpututil.IsKeyJustPressed(ebiten.KeyUp) { + g.idx += len(shaderSrcs) - 1 + g.idx %= len(shaderSrcs) + } + if g.shaders == nil { g.shaders = map[int]*ebiten.Shader{} } @@ -63,18 +98,26 @@ func (g *Game) Draw(screen *ebiten.Image) { { DstX: 0, DstY: 0, + SrcX: 0, + SrcY: 0, }, { DstX: float32(w), DstY: 0, + SrcX: float32(w), + SrcY: 0, }, { DstX: 0, DstY: float32(h), + SrcX: 0, + SrcY: float32(h), }, { DstX: float32(w), DstY: float32(h), + SrcX: float32(w), + SrcY: float32(h), }, } is := []uint16{0, 1, 2, 1, 2, 3} @@ -82,11 +125,21 @@ func (g *Game) Draw(screen *ebiten.Image) { cx, cy := ebiten.CursorPosition() op := &ebiten.DrawTrianglesWithShaderOptions{} - op.Uniforms = []interface{}{ - float32(g.time) / 60, // time - []float32{float32(cx), float32(cy)}, // cursor + switch g.idx { + case 0: + op.Uniforms = []interface{}{ + float32(g.time) / 60, // Time + []float32{float32(cx), float32(cy)}, // Cursor + } + default: + op.Uniforms = []interface{}{ + gophersImage, // Image + } } screen.DrawTrianglesWithShader(vs, is, s, op) + + msg := "Press Up/Down to switch the shader." + ebitenutil.DebugPrint(screen, msg) } func (g *Game) Layout(outsideWidth, outsideHeight int) (int, int) { diff --git a/internal/shader/shader.go b/internal/shader/shader.go index a37e0c252..bad981fa2 100644 --- a/internal/shader/shader.go +++ b/internal/shader/shader.go @@ -135,6 +135,7 @@ func Compile(fs *token.FileSet, f *ast.File, vertexEntry, fragmentEntry string) // TODO: Resolve constants // TODO: Make a call graph and reorder the elements. + return &s.ir, nil } diff --git a/shader.go b/shader.go index cb0c85fed..92087b705 100644 --- a/shader.go +++ b/shader.go @@ -28,7 +28,8 @@ var __viewportSize vec2 func viewportSize() vec2 { return __viewportSize -}` +} +` type Shader struct { shader *buffered.Shader @@ -45,6 +46,7 @@ func NewShader(src []byte) (*Shader, error) { return nil, err } + // TODO: Create a pseudo vertex entrypoint to treat the attribute values correctly. s, err := shader.Compile(fs, f, "Vertex", "Fragment") if err != nil { return nil, err