diff --git a/examples/shaders/parallax-edge-detection/README.md b/examples/shaders/parallax-edge-detection/README.md new file mode 100644 index 0000000..ceda9ed --- /dev/null +++ b/examples/shaders/parallax-edge-detection/README.md @@ -0,0 +1,9 @@ +# Parallax scrolling demo + +Created by [Sergio Vera](https://github.com/svera) + +This example shows how to implement an infinite side scrolling background with a depth effect, using [parallax scrolling](https://en.wikipedia.org/wiki/Parallax_scrolling). Code is based in the [infinite scrolling background](https://github.com/faiface/pixel/tree/master/examples/community/scrolling-background) demo. + +Credits to [Peter Hellberg](https://github.com/peterhellberg) for the improved background images. + +![Parallax scrolling background](result.png) diff --git a/examples/shaders/parallax-edge-detection/background.png b/examples/shaders/parallax-edge-detection/background.png new file mode 100644 index 0000000..97359fc Binary files /dev/null and b/examples/shaders/parallax-edge-detection/background.png differ diff --git a/examples/shaders/parallax-edge-detection/foreground.png b/examples/shaders/parallax-edge-detection/foreground.png new file mode 100644 index 0000000..7328cd8 Binary files /dev/null and b/examples/shaders/parallax-edge-detection/foreground.png differ diff --git a/examples/shaders/parallax-edge-detection/main.go b/examples/shaders/parallax-edge-detection/main.go new file mode 100644 index 0000000..79c6e6b --- /dev/null +++ b/examples/shaders/parallax-edge-detection/main.go @@ -0,0 +1,137 @@ +package main + +import ( + "fmt" + "image" + "os" + "time" + + _ "image/png" + + "github.com/faiface/pixel" + "github.com/faiface/pixel/pixelgl" +) + +// InstallShader ... +func InstallShader(w *pixelgl.Window, weight *float32) { + wc := w.GetCanvas() + wc.SetFragmentShader(edgeDetectionFragShader) + wc.BindUniform("u_weight", weight) + wc.UpdateShader() +} + +func loadPicture(path string) (pixel.Picture, error) { + file, err := os.Open(path) + if err != nil { + return nil, err + } + defer file.Close() + img, _, err := image.Decode(file) + if err != nil { + return nil, err + } + return pixel.PictureDataFromImage(img), nil +} + +const ( + windowWidth = 600 + windowHeight = 450 + foregroundHeight = 149 + // This is the scrolling speed (pixels per second) + // Negative values will make background to scroll to the left, + // positive to the right. + backgroundSpeed = -60 + foregroundSpeed = -120 +) + +func run() { + fmt.Println("Use +/- to adjust weight") + + cfg := pixelgl.WindowConfig{ + Title: "Parallax scrolling demo", + Bounds: pixel.R(0, 0, windowWidth, windowHeight), + VSync: true, + } + win, err := pixelgl.NewWindow(cfg) + if err != nil { + panic(err) + } + + var uWeight float32 + + uWeight = 4.0 + + InstallShader(win, &uWeight) + + // Pic must have double the width of the window, as it will scroll to the left or right + picBackground, err := loadPicture("background.png") + if err != nil { + panic(err) + } + picForeground, err := loadPicture("foreground.png") + if err != nil { + panic(err) + } + + background := NewScrollingBackground(picBackground, windowWidth, windowHeight, backgroundSpeed) + foreground := NewScrollingBackground(picForeground, windowWidth, foregroundHeight, foregroundSpeed) + win.SetTitle(fmt.Sprint("Weight: ", uWeight)) + last := time.Now() + for !win.Closed() { + dt := time.Since(last).Seconds() + last = time.Now() + background.Update(win, dt) + foreground.Update(win, dt) + + if win.Pressed(pixelgl.KeyEqual) { + uWeight += 0.1 + win.SetTitle(fmt.Sprint("Weight: ", uWeight)) + } + if win.Pressed(pixelgl.KeyMinus) { + uWeight -= 0.1 + win.SetTitle(fmt.Sprint("Weight: ", uWeight)) + } + + win.Update() + + } +} + +func main() { + pixelgl.Run(run) +} + +var edgeDetectionFragShader = ` +#version 330 core + +#ifdef GL_ES +precision mediump float; +precision mediump int; +#endif + +in vec2 texcoords; + +out vec4 fragColor; + +uniform vec4 u_texbounds; +uniform sampler2D u_texture; +uniform float u_weight; + +void main(void) +{ + vec2 t = (texcoords - u_texbounds.xy) / u_texbounds.zw; + vec2 onePixel = vec2(1.0, 1.0) / u_texbounds.zw; + vec4 colorSum = + texture(u_texture, t + onePixel * vec2(-1, -1)) * -0.1 + + texture(u_texture, t + onePixel * vec2( 0, -1)) * -0.1 + + texture(u_texture, t + onePixel * vec2( 1, -1)) * -0.1 + + texture(u_texture, t + onePixel * vec2(-1, 0)) * -0.1 + + texture(u_texture, t + onePixel * vec2( 0, 0)) * 8.0 + + texture(u_texture, t + onePixel * vec2( 1, 0)) * -0.1 + + texture(u_texture, t + onePixel * vec2(-1, 1)) * -0.1 + + texture(u_texture, t + onePixel * vec2( 0, 1)) * -0.1 + + texture(u_texture, t + onePixel * vec2( 1, 1)) * -0.1 ; + + fragColor = (colorSum / u_weight).rgba; +} +` diff --git a/examples/shaders/parallax-edge-detection/result.png b/examples/shaders/parallax-edge-detection/result.png new file mode 100644 index 0000000..3236c67 Binary files /dev/null and b/examples/shaders/parallax-edge-detection/result.png differ diff --git a/examples/shaders/parallax-edge-detection/scrolling_background.go b/examples/shaders/parallax-edge-detection/scrolling_background.go new file mode 100644 index 0000000..32c5bf4 --- /dev/null +++ b/examples/shaders/parallax-edge-detection/scrolling_background.go @@ -0,0 +1,64 @@ +package main + +import ( + "math" + + "github.com/faiface/pixel" + "github.com/faiface/pixel/pixelgl" +) + +// ScrollingBackground stores all needed information to scroll a background +// to the left or right +type ScrollingBackground struct { + width float64 + height float64 + displacement float64 + speed float64 + backgrounds [2]*pixel.Sprite + positions [2]pixel.Vec +} + +// NewScrollingBackground construct and returns a new instance of scrollingBackground, +// positioning the background images according to the speed value +func NewScrollingBackground(pic pixel.Picture, width, height, speed float64) *ScrollingBackground { + sb := &ScrollingBackground{ + width: width, + height: height, + speed: speed, + backgrounds: [2]*pixel.Sprite{ + pixel.NewSprite(pic, pixel.R(0, 0, width, height)), + pixel.NewSprite(pic, pixel.R(width, 0, width*2, height)), + }, + } + + sb.positionImages() + return sb +} + +// If scrolling speed > 0, put second background image ouside the screen, +// at the left side, otherwise put it at the right side. +func (sb *ScrollingBackground) positionImages() { + if sb.speed > 0 { + sb.positions = [2]pixel.Vec{ + pixel.V(sb.width/2, sb.height/2), + pixel.V((sb.width/2)-sb.width, sb.height/2), + } + } else { + sb.positions = [2]pixel.Vec{ + pixel.V(sb.width/2, sb.height/2), + pixel.V(sb.width+(sb.width/2), sb.height/2), + } + } +} + +// Update will move backgrounds certain pixels, depending of the amount of time passed +func (sb *ScrollingBackground) Update(win *pixelgl.Window, dt float64) { + if math.Abs(sb.displacement) >= sb.width { + sb.displacement = 0 + sb.positions[0], sb.positions[1] = sb.positions[1], sb.positions[0] + } + d := pixel.V(sb.displacement, 0) + sb.backgrounds[0].Draw(win, pixel.IM.Moved(sb.positions[0].Add(d))) + sb.backgrounds[1].Draw(win, pixel.IM.Moved(sb.positions[1].Add(d))) + sb.displacement += sb.speed * dt +}