add lights example
This commit is contained in:
parent
37b0f0956b
commit
411ad7c27d
|
@ -0,0 +1,210 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"image"
|
||||
"math"
|
||||
"os"
|
||||
"time"
|
||||
|
||||
_ "image/jpeg"
|
||||
_ "image/png"
|
||||
|
||||
"github.com/faiface/pixel"
|
||||
"github.com/faiface/pixel/imdraw"
|
||||
"github.com/faiface/pixel/pixelgl"
|
||||
)
|
||||
|
||||
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
|
||||
}
|
||||
|
||||
type drawer interface {
|
||||
Draw(pixel.Target)
|
||||
}
|
||||
|
||||
type colorlight struct {
|
||||
color pixel.RGBA
|
||||
point pixel.Vec
|
||||
angle float64
|
||||
radius float64
|
||||
dust float64
|
||||
|
||||
spread float64
|
||||
|
||||
imd *imdraw.IMDraw
|
||||
}
|
||||
|
||||
func (cl *colorlight) apply(src, noise drawer, tmp, dst *pixelgl.Canvas) {
|
||||
// create the light arc if not created already
|
||||
if cl.imd == nil {
|
||||
imd := imdraw.New(nil)
|
||||
imd.Color(pixel.Alpha(1))
|
||||
imd.Push(0)
|
||||
imd.Color(pixel.Alpha(0))
|
||||
for angle := -cl.spread / 2; angle <= cl.spread/2; angle += cl.spread / 64 {
|
||||
imd.Push(pixel.X(1).Rotated(angle))
|
||||
}
|
||||
imd.Polygon(0)
|
||||
cl.imd = imd
|
||||
}
|
||||
|
||||
// draw the light arc
|
||||
tmp.Clear(pixel.Alpha(0))
|
||||
tmp.SetMatrix(pixel.IM.Scaled(0, cl.radius).Rotated(0, cl.angle).Moved(cl.point))
|
||||
tmp.SetColorMask(pixel.Alpha(1))
|
||||
tmp.SetComposeMethod(pixel.ComposeCopy)
|
||||
cl.imd.Draw(tmp)
|
||||
|
||||
// draw the noise inside the light
|
||||
tmp.SetMatrix(pixel.IM)
|
||||
tmp.SetComposeMethod(pixel.ComposeIn)
|
||||
noise.Draw(tmp)
|
||||
|
||||
// draw an image inside the noisy light
|
||||
tmp.SetColorMask(cl.color)
|
||||
tmp.SetComposeMethod(pixel.ComposeIn)
|
||||
src.Draw(tmp)
|
||||
|
||||
// draw the light reflected from the dust
|
||||
tmp.SetMatrix(pixel.IM.Scaled(0, cl.radius).Rotated(0, cl.angle).Moved(cl.point))
|
||||
tmp.SetColorMask(cl.color.Mul(pixel.Alpha(cl.dust)))
|
||||
tmp.SetComposeMethod(pixel.ComposeOver)
|
||||
cl.imd.Draw(tmp)
|
||||
|
||||
// draw the result to the dst
|
||||
dst.SetColorMask(pixel.Alpha(1))
|
||||
dst.SetComposeMethod(pixel.ComposePlus)
|
||||
tmp.Draw(dst)
|
||||
}
|
||||
|
||||
func run() {
|
||||
pandaPic, err := loadPicture("panda.png")
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
noisePic, err := loadPicture("noise.png")
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
cfg := pixelgl.WindowConfig{
|
||||
Title: "Color Light",
|
||||
Bounds: pixel.R(0, 0, 1024, 768),
|
||||
VSync: true,
|
||||
}
|
||||
win, err := pixelgl.NewWindow(cfg)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
panda := pixel.NewSprite(pandaPic, pandaPic.Bounds())
|
||||
panda.SetMatrix(pixel.IM.Moved(win.Bounds().Center()))
|
||||
noise := pixel.NewSprite(noisePic, noisePic.Bounds())
|
||||
noise.SetMatrix(pixel.IM.Moved(win.Bounds().Center()))
|
||||
|
||||
colors := []pixel.RGBA{
|
||||
pixel.RGB(1, 0, 0),
|
||||
pixel.RGB(0, 1, 0),
|
||||
pixel.RGB(0, 0, 1),
|
||||
pixel.RGB(1/math.Sqrt2, 1/math.Sqrt2, 0),
|
||||
}
|
||||
|
||||
points := []pixel.Vec{
|
||||
pixel.V(win.Bounds().Min.X(), win.Bounds().Min.Y()),
|
||||
pixel.V(win.Bounds().Max.X(), win.Bounds().Min.Y()),
|
||||
pixel.V(win.Bounds().Max.X(), win.Bounds().Max.Y()),
|
||||
pixel.V(win.Bounds().Min.X(), win.Bounds().Max.Y()),
|
||||
}
|
||||
|
||||
angles := []float64{
|
||||
math.Pi / 4,
|
||||
math.Pi/4 + math.Pi/2,
|
||||
math.Pi/4 + 2*math.Pi/2,
|
||||
math.Pi/4 + 3*math.Pi/2,
|
||||
}
|
||||
|
||||
lights := make([]colorlight, 4)
|
||||
for i := range lights {
|
||||
lights[i] = colorlight{
|
||||
color: colors[i],
|
||||
point: points[i],
|
||||
angle: angles[i],
|
||||
radius: 800,
|
||||
dust: 0.3,
|
||||
spread: math.Pi / math.E,
|
||||
}
|
||||
}
|
||||
|
||||
speed := []float64{11.0 / 23, 13.0 / 23, 17.0 / 23, 19.0 / 23}
|
||||
|
||||
tmp := pixelgl.NewCanvas(win.Bounds())
|
||||
dst := pixelgl.NewCanvas(win.Bounds())
|
||||
|
||||
var (
|
||||
frames = 0
|
||||
second = time.Tick(time.Second)
|
||||
fps30 = time.Tick(time.Second / 30)
|
||||
)
|
||||
|
||||
start := time.Now()
|
||||
for !win.Closed() {
|
||||
if win.Pressed(pixelgl.KeyW) {
|
||||
for i := range lights {
|
||||
lights[i].dust += 0.05
|
||||
if lights[i].dust > 1 {
|
||||
lights[i].dust = 1
|
||||
}
|
||||
}
|
||||
}
|
||||
if win.Pressed(pixelgl.KeyS) {
|
||||
for i := range lights {
|
||||
lights[i].dust -= 0.05
|
||||
if lights[i].dust < 0 {
|
||||
lights[i].dust = 0
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
since := time.Since(start).Seconds()
|
||||
for i := range lights {
|
||||
lights[i].angle = angles[i] + math.Sin(since*speed[i])*math.Pi/8
|
||||
}
|
||||
|
||||
win.Clear(pixel.RGB(0, 0, 0))
|
||||
dst.Clear(pixel.Alpha(0))
|
||||
|
||||
dst.SetColorMask(pixel.Alpha(0.4))
|
||||
dst.SetComposeMethod(pixel.ComposeOver)
|
||||
panda.Draw(dst)
|
||||
|
||||
for i := range lights {
|
||||
lights[i].apply(panda, noise, tmp, dst)
|
||||
}
|
||||
|
||||
dst.Draw(win)
|
||||
win.Update()
|
||||
|
||||
<-fps30 // maintain 30 fps, because my computer couldn't handle 60 here
|
||||
frames++
|
||||
select {
|
||||
case <-second:
|
||||
win.SetTitle(fmt.Sprintf("%s | FPS: %d", cfg.Title, frames))
|
||||
frames = 0
|
||||
default:
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func main() {
|
||||
pixelgl.Run(run)
|
||||
}
|
Binary file not shown.
After Width: | Height: | Size: 838 KiB |
Binary file not shown.
After Width: | Height: | Size: 1.2 MiB |
Loading…
Reference in New Issue