Skip to content

Instantly share code, notes, and snippets.

@peterhellberg
Last active April 2, 2019 21:08
Show Gist options
  • Star 4 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save peterhellberg/80df53fa909a2012f5acc00e2b908fc0 to your computer and use it in GitHub Desktop.
Save peterhellberg/80df53fa909a2012f5acc00e2b908fc0 to your computer and use it in GitHub Desktop.
Tunnel effects in Go
package main
import (
"image"
"math"
"time"
"github.com/faiface/pixel"
"github.com/faiface/pixel/pixelgl"
"github.com/peterhellberg/plasma"
"github.com/peterhellberg/plasma/palette"
)
const (
size = 256
fsize = float64(size)
w = 640
fw = float64(w)
h = 480
fh = float64(h)
)
func run() {
win, err := pixelgl.NewWindow(pixelgl.WindowConfig{
Bounds: pixel.R(0, 0, float64(w), float64(h)),
VSync: true,
Undecorated: true,
Resizable: false,
})
if err != nil {
panic(err)
}
win.SetSmooth(true)
texture := plasmaImage(size, size)
buffer := image.NewRGBA(image.Rect(0, 0, w, h))
bufferPicture := pixel.PictureDataFromImage(buffer)
distanceTable := [h][w]int{}
angleTable := [h][w]int{}
ratio := 32.0
for y := 0; y < h; y++ {
for x := 0; x < w; x++ {
fx, fy := float64(x), float64(y)
distance := int(ratio*size/math.Sqrt((fx-fw/2.0)*(fx-fw/2.0)+(fy-fh/2.0)*(fy-fh/2.0))) % size
angle := int(0.5 * size * math.Atan2(fy-fh/2.0, fx-fw/2.0) / math.Pi)
distanceTable[y][x] = distance
angleTable[y][x] = angle
}
}
centerMatrix := pixel.IM.Moved(win.Bounds().Center()).Scaled(
win.Bounds().Center(), 1,
)
start := time.Now()
go func() {
for range time.Tick(32 * time.Millisecond) {
animation := time.Since(start).Seconds()
shiftX := int(fsize * 1.2 * animation)
shiftY := int(fsize * 0.10 * animation)
for y := 0; y < h; y++ {
for x := 0; x < w; x++ {
buffer.Set(x, y, texture.At(
int(uint(distanceTable[y][x]+shiftX)%size),
int(uint(angleTable[y][x]+shiftY)%size),
))
}
}
bufferPicture = pixel.PictureDataFromImage(buffer)
}
}()
for !win.Closed() {
win.SetClosed(win.JustPressed(pixelgl.KeyEscape) || win.JustPressed(pixelgl.KeyQ))
bs := pixel.NewSprite(bufferPicture, bufferPicture.Bounds())
bs.SetMatrix(centerMatrix)
bs.Draw(win)
win.Update()
}
}
func plasmaImage(w, h int) image.Image {
return plasma.New(w, h, 64).Image(w, h, 12, palette.DefaultGradient)
}
func main() {
pixelgl.Run(run)
}
package main
import (
"image"
"image/color"
"math"
"time"
"github.com/faiface/pixel"
"github.com/faiface/pixel/pixelgl"
"github.com/peterhellberg/plasma"
"github.com/peterhellberg/plasma/palette"
)
const (
size = 256
fsize = float64(size)
w = 640
fw = float64(w)
h = 480
fh = float64(h)
)
func run() {
win, err := pixelgl.NewWindow(pixelgl.WindowConfig{
Bounds: pixel.R(0, 0, float64(w), float64(h)),
VSync: true,
Undecorated: true,
Resizable: false,
})
if err != nil {
panic(err)
}
win.SetSmooth(true)
texture1 := xorImage(size, size)
texture2 := plasmaImage(size, size)
buffer := image.NewRGBA(image.Rect(0, 0, w, h))
bufferPicture := pixel.PictureDataFromImage(buffer)
distanceTable := [h][w]int{}
angleTable := [h][w]int{}
ratio := 32.0
for y := 0; y < h; y++ {
for x := 0; x < w; x++ {
fx, fy := float64(x), float64(y)
distance := int(ratio*size/math.Sqrt((fx-fw/2.0)*(fx-fw/2.0)+(fy-fh/2.0)*(fy-fh/2.0))) % size
angle := int(0.5 * size * math.Atan2(fy-fh/2.0, fx-fw/2.0) / math.Pi)
distanceTable[y][x] = distance
angleTable[y][x] = angle
}
}
centerMatrix := pixel.IM.Moved(win.Bounds().Center()).Scaled(
win.Bounds().Center(), 1,
)
start := time.Now()
go func() {
for range time.Tick(32 * time.Millisecond) {
animation := time.Since(start).Seconds()
shiftX := int(fsize * 1.2 * animation)
shiftY := int(fsize * 0.10 * animation)
for y := 0; y < h; y++ {
for x := 0; x < w; x++ {
texture := texture1
if int(animation)%2 == 0 {
texture = texture2
}
buffer.Set(x, y, texture.At(
int(uint(distanceTable[y][x]+shiftX)%size),
int(uint(angleTable[y][x]+shiftY)%size),
))
}
}
bufferPicture = pixel.PictureDataFromImage(buffer)
}
}()
for !win.Closed() {
win.SetClosed(win.JustPressed(pixelgl.KeyEscape) || win.JustPressed(pixelgl.KeyQ))
bs := pixel.NewSprite(bufferPicture, bufferPicture.Bounds())
bs.SetMatrix(centerMatrix)
bs.Draw(win)
win.Update()
}
}
func plasmaImage(w, h int) image.Image {
return plasma.New(w, h, 64).Image(w, h, 12, palette.DefaultGradient)
}
func xorImage(w, h int) image.Image {
m := image.NewRGBA(image.Rect(0, 0, w, h))
for x := 0; x < w; x++ {
for y := 0; y < h; y++ {
u := uint8(x ^ y)
c := color.RGBA{
(u) % 192,
24,
(u & uint8(y)) % 128,
200,
}
m.Set(x, y, c)
}
}
return m
}
func main() {
pixelgl.Run(run)
}
package main
import (
"image"
"image/color"
"math"
"time"
"github.com/faiface/pixel"
"github.com/faiface/pixel/pixelgl"
)
const (
size = 256
fsize = float64(size)
w = 640
fw = float64(w)
h = 480
fh = float64(h)
)
func run() {
win, err := pixelgl.NewWindow(pixelgl.WindowConfig{
Bounds: pixel.R(0, 0, float64(w), float64(h)),
VSync: true,
Undecorated: true,
Resizable: false,
})
if err != nil {
panic(err)
}
win.SetSmooth(true)
texture := xorImage(size, size)
buffer := image.NewRGBA(image.Rect(0, 0, w, h))
bufferPicture := pixel.PictureDataFromImage(buffer)
distanceTable := [h][w]int{}
angleTable := [h][w]int{}
ratio := 32.0
for y := 0; y < h; y++ {
for x := 0; x < w; x++ {
fx, fy := float64(x), float64(y)
distance := int(ratio*size/math.Sqrt((fx-fw/2.0)*(fx-fw/2.0)+(fy-fh/2.0)*(fy-fh/2.0))) % size
angle := int(0.5 * size * math.Atan2(fy-fh/2.0, fx-fw/2.0) / math.Pi)
distanceTable[y][x] = distance
angleTable[y][x] = angle
}
}
centerMatrix := pixel.IM.Moved(win.Bounds().Center()).Scaled(
win.Bounds().Center(), 1,
)
start := time.Now()
go func() {
for range time.Tick(32 * time.Millisecond) {
animation := time.Since(start).Seconds()
shiftX := int(fsize * 1.2 * animation)
shiftY := int(fsize * 0.10 * animation)
for y := 0; y < h; y++ {
for x := 0; x < w; x++ {
buffer.Set(x, y, texture.At(
int(uint(distanceTable[y][x]+shiftX)%size),
int(uint(angleTable[y][x]+shiftY)%size),
))
}
}
bufferPicture = pixel.PictureDataFromImage(buffer)
}
}()
for !win.Closed() {
win.SetClosed(win.JustPressed(pixelgl.KeyEscape) || win.JustPressed(pixelgl.KeyQ))
bs := pixel.NewSprite(bufferPicture, bufferPicture.Bounds())
bs.SetMatrix(centerMatrix)
bs.Draw(win)
win.Update()
}
}
func xorImage(w, h int) image.Image {
m := image.NewRGBA(image.Rect(0, 0, w, h))
for x := 0; x < w; x++ {
for y := 0; y < h; y++ {
u := uint8(x ^ y)
c := color.RGBA{
(u) % 192,
24,
(u & uint8(y)) % 128,
200,
}
m.Set(x, y, c)
}
}
return m
}
func main() {
pixelgl.Run(run)
}
@peterhellberg
Copy link
Author

peterhellberg commented Apr 27, 2017

xor-tunnel

xor-tunnel-animation

plasma-tunnel

@peterhellberg
Copy link
Author

Using the new canvas.SetPixels

package main

import (
	"image"
	"image/color"
	"math"
	"time"

	"github.com/faiface/pixel"
	"github.com/faiface/pixel/pixelgl"
)

const (
	w, h, size    = 640, 480, 256
	fw, fh, fsize = float64(w), float64(h), float64(size)
)

var (
	start         = time.Now()
	texture       = xorImage(size, size)
	distanceTable = [h][w]int{}
	angleTable    = [h][w]int{}
	ratio         = 32.0
)

func run() {
	win, err := pixelgl.NewWindow(pixelgl.WindowConfig{
		Bounds:      pixel.R(0, 0, float64(w), float64(h)),
		VSync:       true,
		Undecorated: true,
	})
	if err != nil {
		panic(err)
	}

	win.SetSmooth(true)

	canvas := pixelgl.NewCanvas(win.Bounds())

	for y := 0; y < h; y++ {
		for x := 0; x < w; x++ {
			fx, fy := float64(x), float64(y)

			distance := int(ratio*size/math.Sqrt((fx-fw/2.0)*(fx-fw/2.0)+(fy-fh/2.0)*(fy-fh/2.0))) % size
			angle := int(0.5 * size * math.Atan2(fy-fh/2.0, fx-fw/2.0) / math.Pi)

			distanceTable[y][x] = distance
			angleTable[y][x] = angle
		}
	}

	for !win.Closed() {
		win.SetClosed(win.JustPressed(pixelgl.KeyEscape) || win.JustPressed(pixelgl.KeyQ))

		drawFrame(canvas)

		canvas.Draw(win)

		win.Update()
	}
}

func drawFrame(canvas *pixelgl.Canvas) {
	animation := time.Since(start).Seconds()

	shiftX := int(fsize * 0.9 * animation)
	shiftY := int(fsize * 0.10 * animation)

	buffer := image.NewRGBA(image.Rect(0, 0, w, h))

	for y := 0; y < h; y++ {
		for x := 0; x < w; x++ {
			buffer.Set(x, y, texture.At(
				int(uint(distanceTable[y][x]+shiftX)%size),
				int(uint(angleTable[y][x]+shiftY)%size),
			))
		}
	}

	canvas.SetPixels(buffer.Pix)
}

func xorImage(w, h int) image.Image {
	m := image.NewRGBA(image.Rect(0, 0, w, h))

	for x := 0; x < w; x++ {
		for y := 0; y < h; y++ {
			u := uint8(x ^ y)

			c := color.RGBA{
				(u) % 192,
				24,
				(u & uint8(y)) % 128,
				200,
			}

			m.Set(x, y, c)
		}
	}

	return m
}

func main() {
	pixelgl.Run(run)
}

@peterhellberg
Copy link
Author

peterhellberg commented Apr 28, 2017

Looking around in the tunnel

package main

import (
	"image"
	"math"
	"time"

	"github.com/faiface/pixel"
	"github.com/faiface/pixel/pixelgl"
	"github.com/peterhellberg/plasma"
	"github.com/peterhellberg/plasma/palette"
)

const (
	w, h, size    = 640, 480, 128
	fw, fh, fsize = float64(w), float64(h), float64(size)
)

var (
	start         = time.Now()
	texture       = plasmaImage(size, size, 1)
	distanceTable = [h * 2][w * 2]int{}
	angleTable    = [h * 2][w * 2]int{}
	ratio         = 32.0
)

func run() {
	win, err := pixelgl.NewWindow(pixelgl.WindowConfig{
		Bounds:      pixel.R(0, 0, float64(w), float64(h)),
		VSync:       true,
		Undecorated: true,
	})
	if err != nil {
		panic(err)
	}

	win.SetSmooth(true)

	canvas := pixelgl.NewCanvas(win.Bounds())

	go func() {
		s := 1
		for range time.Tick(32 * time.Millisecond) {
			s++

			texture = plasmaImage(size, size, s)
		}
	}()

	for y := 0; y < h*2; y++ {
		for x := 0; x < w*2; x++ {
			fx, fy := float64(x), float64(y)

			distance := int(ratio*size/math.Sqrt((fx-fw)*(fx-fw)+(fy-fh)*(fy-fh))) % size
			angle := int(0.5 * size * math.Atan2(fy-fh, fx-fw) / math.Pi)

			distanceTable[y][x] = distance
			angleTable[y][x] = angle
		}
	}

	for !win.Closed() {
		win.SetClosed(win.JustPressed(pixelgl.KeyEscape) || win.JustPressed(pixelgl.KeyQ))

		drawFrame(canvas)

		canvas.Draw(win)

		win.Update()
	}
}

func drawFrame(canvas *pixelgl.Canvas) {
	animation := time.Since(start).Seconds()

	shiftX := int(fsize * 0.2 * animation)
	shiftY := int(fsize * 0.05 * animation)

	shiftLookX := int(fw/2 + float64(int(fw/2*math.Sin(animation))))
	shiftLookY := int(fh/2 + float64(int(fh/2*math.Sin(animation*1.6))))

	buffer := image.NewRGBA(image.Rect(0, 0, w, h))

	for y := 0; y < h; y++ {
		for x := 0; x < w; x++ {
			buffer.Set(x, y, texture.At(
				int(uint(distanceTable[y+shiftLookY][x+shiftLookX]+shiftX)%size),
				int(uint(angleTable[y+shiftLookY][x+shiftLookX]+shiftY)%size),
			))
		}
	}

	canvas.SetPixels(buffer.Pix)
}

func plasmaImage(w, h, s int) image.Image {
	return plasma.New(w, h, 4).Image(w, h, s, palette.DefaultGradient)
}

func main() {
	pixelgl.Run(run)
}

ezgif-3-277362b85f

@peterhellberg
Copy link
Author

Smaller animation:

looking-around-plasma-tunnel-small

@peterhellberg
Copy link
Author

This code is heavily based on http://lodev.org/cgtutor/tunnel.html#The_code

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment