github.com/egonelbre/exp@v0.0.0-20240430123955-ed1d3aa93911/pixel/cmc/main.go (about)

     1  package main
     2  
     3  import (
     4  	"image/color"
     5  	"math/rand"
     6  	"time"
     7  
     8  	"github.com/faiface/pixel"
     9  	"github.com/faiface/pixel/pixelgl"
    10  )
    11  
    12  const Detail = 1 << 16
    13  
    14  func main() {
    15  	pixelgl.Run(run)
    16  }
    17  
    18  func run() {
    19  	cfg := pixelgl.WindowConfig{
    20  		Title:     "CMC!",
    21  		Bounds:    pixel.R(0, 0, 480, 320),
    22  		Resizable: true,
    23  		VSync:     true,
    24  	}
    25  
    26  	win, err := pixelgl.NewWindow(cfg)
    27  	if err != nil {
    28  		panic(err)
    29  	}
    30  
    31  	r := rand.New(rand.NewSource(0))
    32  
    33  	canvas := NewImage()
    34  	backbuffer := pixel.MakePictureData(pixel.R(0, 0, 64, 64))
    35  	for i := range backbuffer.Pix {
    36  		backbuffer.Pix[i] = color.RGBA{0xFF, 0x00, 0x00, 0xFF}
    37  	}
    38  
    39  	now := time.Now()
    40  	tt := float32(0.0)
    41  	brightness := float32(1.0)
    42  	for !win.Closed() {
    43  		win.SetClosed(win.JustPressed(pixelgl.KeyEscape))
    44  
    45  		next := time.Now()
    46  		dt := next.Sub(now).Seconds()
    47  		now = next
    48  		if dt > 1.0/15.0 {
    49  			dt = 1.0 / 15.0
    50  		}
    51  		tt += float32(dt)
    52  
    53  		winsize := win.Bounds().Size()
    54  		if canvas.SetSize(int(winsize.X), int(winsize.Y)) {
    55  			backbuffer = pixel.MakePictureData(
    56  				pixel.R(0, 0, float64(canvas.Width), float64(canvas.Height)),
    57  			)
    58  		}
    59  		canvas.Clear()
    60  
    61  		{
    62  			os := Sin(float32(tt))
    63  
    64  			size := V{float32(winsize.X) * 0.5, float32(winsize.Y) * 0.5, 0}
    65  			for i := 0; i < Detail; i++ {
    66  				p := V{r.Float32() - 0.5, r.Float32() - 0.5, r.Float32() - 0.5}
    67  				p = N(p, 17)
    68  				h := Atan2(p.Y, p.X)
    69  				p = T0(tt, os, p)
    70  				p = Rx(Ry(p, tt), os)
    71  				canvas.Put(P(p, size), HL{h, 0.1})
    72  			}
    73  		}
    74  		canvas.Smear()
    75  
    76  		if backbuffer.Stride != canvas.Width {
    77  			panic("invalid stride")
    78  		}
    79  
    80  		max, total, nz := float32(0.0), float32(0.0), 0
    81  		for _, v := range canvas.Pix {
    82  			if v.L == 0 {
    83  				continue
    84  			}
    85  			nz++
    86  			total += v.L
    87  			if v.L > max {
    88  				max = v.L
    89  			}
    90  		}
    91  		average := total / float32(nz)
    92  		brightness = Lerp(brightness, Lerp(average, max, 0.1), 0.01)
    93  		scale := 1 / brightness
    94  
    95  		for i, v := range canvas.Pix {
    96  			backbuffer.Pix[i] = v.RGBA(scale)
    97  		}
    98  
    99  		sprite := pixel.NewSprite(backbuffer, backbuffer.Bounds())
   100  		sprite.Draw(win, pixel.IM.Moved(win.Bounds().Center()))
   101  
   102  		win.Update()
   103  	}
   104  }
   105  
   106  func F0(tt float32, v V) float32 { return Sin(tt+v.X+v.Z) * 3 }
   107  func F1(tt float32, v V) float32 { return Sin(tt+v.X/3+v.Y/3) + 1.5 }
   108  func T0(tt, os float32, v V) V {
   109  	return S(v, F1(tt, v)+os*F0(tt, v)/10+os)
   110  }