package main import ( "fmt" "log" "math" "math/rand" "os" "time" "github.com/gen2brain/raylib-go/raylib" "github.com/ojrac/opensimplex-go" ) const ( targetWidth = 1000 targetHeight = 1000 sourceScale = 8 snapshotsDir = "snapshots" ) type TextureCam struct { SourceWidth int SourceHeight int LookAt rl.Vector2 Zoom float32 } func main() { sourceWidth := sourceScale * targetWidth sourceHeight := sourceScale * targetHeight os.MkdirAll(snapshotsDir, 0755) log := log.New(os.Stdout, "", log.Ldate|log.Ltime|log.Lshortfile) storage, err := NewStorage(snapshotsDir) if err != nil { log.Printf("Error loading storage: %v\n", err) os.Exit(1) } rl.SetConfigFlags(rl.FlagMsaa4xHint) rl.InitWindow(targetWidth, targetHeight, "sumi sierpinski arrow") // point at source center // put source center at center of screen var camera = TextureCam { LookAt: rl.Vector2 { X: float32(sourceWidth) / 2.0, Y: float32(sourceHeight) / 2.0 }, Zoom: 1.0, SourceWidth: sourceWidth, SourceHeight: sourceHeight, } rl.SetTargetFPS(60) t0 := time.Now() /* */ imageField := NewImageField("/home/d/Dropbox/art/passage/data/david.png") field := TranslateField{ x: -float32(sourceWidth/2.0), y: -float32(sourceHeight/2.0), field: &ScaleField { scale: 5.0, field: &imageField, }, } rng := rand.New(rand.NewSource(0)) contourLayer := NewContourLayer(rng, &field, sourceWidth, sourceHeight) sketch := NewSketch() //sketch.CreateLayer("testPattern", &TestPattern{}, int32(sourceWidth), int32(sourceHeight)) //sketch.CreateLayer("actors", &contourLayer, int32(sourceWidth), int32(sourceHeight)) sketch.CreateLayer("field", &FieldLayer { field: &field, dirty: true }, int32(sourceWidth), int32(sourceHeight)) sketch.CreateLayer("contours", &contourLayer, int32(sourceWidth), int32(sourceHeight)) ports := MakePorts() ports["sierpinskiArrowAngle"] = Sine { Amp: 120, Bias: 100, Freq: 0.1, } for !rl.WindowShouldClose() { // begin drawing t := time.Since(t0).Seconds() // set up RenderCtx renderCtx := &RenderCtx{ TargetWidth: int32(targetWidth), TargetHeight: int32(targetHeight), SourceWidth: int32(sourceWidth), SourceHeight: int32(sourceHeight), Time: t, Ports: ports.Eval(t), Cam: &camera, } sketch.Update(renderCtx) /** * MAIN DRAWING */ rl.BeginDrawing() rl.ClearBackground(rl.Blank) sketch.Draw(renderCtx) if rl.IsKeyDown(rl.KeySpace) { if _, err := storage.Save(); err != nil { log.Printf("Error saving snapshot: %v\n", err) } } rl.DrawText("Mouse right button drag to move, mouse wheel to zoom", 10, 10, 20, rl.White) rl.EndDrawing() for ch := rl.GetCharPressed(); ch != 0; ch = rl.GetCharPressed() { c := rune(ch) if c == 'c' { resetCamera(&camera) } else if c >= '1' && c <= '9' { zoom := 1 << int(ch - '0') camera.Zoom = float32(zoom) } } //rl.EndMode2D() // HUD } rl.CloseWindow() } func resetCamera(cam *TextureCam) { cam.LookAt = rl.Vector2 { X: float32(cam.SourceWidth) / 2.0, Y: float32(cam.SourceHeight) / 2.0 } cam.Zoom = 1.0 } type FieldLayer struct { field Field dirty bool } func (s *FieldLayer) Update(ctx *RenderCtx) { ; } func (s *FieldLayer) Draw(ctx *RenderCtx) { for x := range ctx.SourceWidth { for y := range ctx.SourceHeight { v := s.field.Get(float32(x), float32(y)) clr := GrayCurve(v, 1.0) rl.DrawPixel(x, y, clr) } } s.dirty = false } func (s *FieldLayer) IsDirty() bool { return s.dirty } type ContourLayer struct { field Field actors []*Actor } func NewContourLayer(rng *rand.Rand, field Field, sourceWidth int, sourceHeight int) ContourLayer { actors := make([]*Actor, 20000) for i := range len(actors) { x := rng.Int() % sourceWidth y := rng.Int() % sourceHeight actors[i] = &Actor{ position: rl.Vector2 { X: float32(x), Y: float32(y) }, field: field, stepSize: 1, color: rl.NewColor(11, 35, 176, 100), } } return ContourLayer{ actors: actors, } } func (s *ContourLayer) Update(ctx *RenderCtx) { ; } func (s *ContourLayer) Draw(ctx *RenderCtx) { rl.BeginBlendMode(rl.BlendAdditive) for _, actor := range s.actors { actor.Draw() } rl.EndBlendMode() } func (s *ContourLayer) IsDirty() bool { return true } type Actor struct { position rl.Vector2 field Field stepSize float32 color rl.Color } func (a *Actor) Draw() { v := a.field.Get(a.position.X, a.position.Y) rad := rl.Remap(v, 0, 1, 0, 3*math.Pi) nextPosition := rl.Vector2{X: a.position.X + a.stepSize*float32(math.Cos(float64(rad))), Y: a.position.Y + a.stepSize*float32(math.Sin(float64(rad)))} rl.DrawLineV(a.position, nextPosition, a.color) //fmt.Printf("position %v -> nextPosition %v \n", a.position, nextPosition) a.position = nextPosition } func RandRadialVec(rng *rand.Rand, minRadius float32, maxRadius float32, loAngle float32, hiAngle float32) rl.Vector2 { r := float64(rl.Remap(rng.Float32(), 0, 1, minRadius, maxRadius)) deg := float64(rl.Remap(rng.Float32(), 0, 1, loAngle, hiAngle)) rad := rl.Deg2rad * deg return rl.Vector2{X: float32(r * math.Cos(rad)), Y: float32(r * math.Sin(rad))} } type Worm struct { position rl.Vector2 angles []float32 angleIndex int stepSize int renderPct float32 } func (w *Worm) Draw(ctx *RenderCtx) { rl.PushMatrix() rl.Translatef(w.position.X, w.position.Y, 0) lastAngle := float32(0.0) stepCount := 0 nudged := false for i := range w.angles { ii := (i + w.angleIndex) % len(w.angles) angle := w.angles[ii] deltaAngle := angle - lastAngle if !nudged { rad := float64(deltaAngle * math.Pi / 180.0) nudge := rl.Vector2{X: float32(w.stepSize) * float32(math.Cos(rad)), Y: float32(w.stepSize) * float32(math.Sin(rad))} w.position = rl.Vector2Add(w.position, nudge) nudged = true } rl.Rotatef(deltaAngle, 0, 0, 1) rl.DrawLine(0, 0, int32(w.stepSize), 0, rl.NewColor(184, 187, 38, 50)) rl.Translatef(float32(w.stepSize), 0, 0) lastAngle = angle stepCount++ if stepCount > int(float32(len(w.angles))*w.renderPct) { break } } rl.PopMatrix() w.angleIndex = (w.angleIndex + 1) % len(w.angles) } type SierpinskiArrow struct{} func (s *SierpinskiArrow) Draw(ctx *RenderCtx) { sierpinskiArrow(ctx, int(ctx.Ports["sierpinskiArrowDepth"]), ctx.Ports["sierpinskiArrowLength"]) } func sierpinskiArrow(ctx *RenderCtx, order int, length float64) { if order == 0 { curve(ctx, order, length, ctx.Ports["sierpinskiArrowAngle"]) } else { rl.Rotatef(float32(ctx.Ports["sierpinskiArrowAngle"]), 0, 0, 1) curve(ctx, order, length, -ctx.Ports["sierpinskiArrowAngle"]) } } func curve(ctx *RenderCtx, order int, length float64, angle float64) { if order == 0 { len := int32(length) rl.DrawLine(0, 0, len, 0, rl.Black) rl.Translatef(float32(length), 0, 0) } else { curve(ctx, order-1, length/2, -angle) rl.Rotatef(float32(angle), 0, 0, 1) curve(ctx, order-1, length/2, angle) rl.Rotatef(float32(angle), 0, 0, 1) curve(ctx, order-1, length/2, -angle) } } func main2() { angles := make([]float32, 1000) noise := opensimplex.NewNormalized(0) for i := range len(angles) { angles[i] = float32(noise.Eval2(float64(i)*0.05, 0.00))*0.1 - 0.05 } frameNum := 0 for !rl.WindowShouldClose() { frameNum++ // initial transform by halfway again through angle array angleIndex := (frameNum / 10) % len(angles) angle := angles[angleIndex] initAngle := angles[(angleIndex+len(angles)/2)%len(angles)] rl.Rotatef(2500*initAngle, 0, 0, 1) rl.Translatef(100*initAngle, 100*initAngle, 0) fmt.Printf("%.3f", angle) rl.EndMode2D() } }