317 lines
7.4 KiB
Go
317 lines
7.4 KiB
Go
package main
|
|
|
|
import (
|
|
"fmt"
|
|
"log"
|
|
"math"
|
|
"math/rand"
|
|
"os"
|
|
"time"
|
|
|
|
"github.com/gen2brain/raylib-go/raylib"
|
|
"github.com/ojrac/opensimplex-go"
|
|
)
|
|
|
|
const (
|
|
screenWidth = 1400
|
|
screenHeight = 700
|
|
displayScale = 2
|
|
snapshotsDir = "snapshots"
|
|
)
|
|
|
|
func main() {
|
|
|
|
os.MkdirAll(snapshotsDir, 0755)
|
|
|
|
//rng := rand.New(rand.NewSource(0))
|
|
|
|
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.FlagWindowHighdpi)
|
|
rl.InitWindow(screenWidth, screenHeight, "sumi sierpinski arrow")
|
|
|
|
log.Printf("screen=%dx%d render=%dx%d",
|
|
rl.GetScreenWidth(), rl.GetScreenHeight(),
|
|
rl.GetRenderWidth(), rl.GetRenderHeight(),
|
|
)
|
|
|
|
w := rl.GetRenderWidth()
|
|
h := rl.GetRenderHeight()
|
|
|
|
var camera = rl.Camera2D{
|
|
Target: rl.Vector2{X: 0, Y: 0},
|
|
Offset: rl.Vector2{X: float32(w) / 2, Y: float32(h) / 2},
|
|
Rotation: 0,
|
|
Zoom: 1.0,
|
|
}
|
|
|
|
field :=
|
|
ScaleField {
|
|
Scale: 100.0,
|
|
Field: &SimplexNoiseField {
|
|
Noise: opensimplex.NewNormalized32(0),
|
|
},
|
|
}
|
|
|
|
rng := rand.New(rand.NewSource(0))
|
|
|
|
contourSketch := NewContourSketch(rng, &field)
|
|
|
|
sketches := []Sketch {
|
|
//&FieldSketch { Field: &field },
|
|
&contourSketch,
|
|
}
|
|
|
|
rl.SetTargetFPS(60)
|
|
|
|
t0 := time.Now()
|
|
|
|
ports := MakePorts()
|
|
|
|
ports["sierpinskiArrowAngle"] = Sine{
|
|
Amp: 120,
|
|
Bias: 100,
|
|
Freq: 0.1,
|
|
}
|
|
|
|
for !rl.WindowShouldClose() {
|
|
updateCamera(&camera)
|
|
|
|
// begin drawing
|
|
rl.BeginDrawing()
|
|
//rl.ClearBackground(rl.Black)
|
|
rl.BeginMode2D(camera)
|
|
|
|
t := time.Since(t0).Seconds()
|
|
|
|
// set up RenderCtx
|
|
renderCtx := &RenderCtx{
|
|
Width: int32(w),
|
|
Height: int32(h),
|
|
Time: t,
|
|
Ports: ports.Eval(t),
|
|
Cam: camera,
|
|
}
|
|
|
|
/**
|
|
MAIN DRAWING
|
|
**/
|
|
|
|
for _, s := range sketches {
|
|
rl.PushMatrix()
|
|
s.Draw(renderCtx)
|
|
rl.PopMatrix()
|
|
}
|
|
|
|
if rl.IsKeyDown(rl.KeySpace) {
|
|
if _, err := storage.Save(); err != nil {
|
|
log.Printf("Error saving snapshot: %v\n", err)
|
|
}
|
|
}
|
|
|
|
rl.EndMode2D()
|
|
|
|
// HUD
|
|
rl.DrawText("Mouse right button drag to move, mouse wheel to zoom", 10, 10, 20, rl.Black)
|
|
rl.EndDrawing()
|
|
}
|
|
|
|
rl.CloseWindow()
|
|
}
|
|
|
|
type FieldSketch struct {
|
|
Field Field
|
|
}
|
|
|
|
func (s *FieldSketch) Draw(ctx *RenderCtx) {
|
|
fmt.Printf("drawing field")
|
|
for x := range ctx.Width {
|
|
for y := range ctx.Height {
|
|
//screen := rl.Vector2 { X: float32(x) - float32(ctx.Width) / 2.0, Y: float32(y) - float32(ctx.Height) / 2.0 }
|
|
screen := rl.Vector2 { X: float32(x), Y: float32(y) }
|
|
world := rl.GetScreenToWorld2D(screen, ctx.Cam)
|
|
//fmt.Printf("screen -> %v, world -> %v\n", screen, world)
|
|
v := s.Field.Get(world.X, world.Y)
|
|
//fmt.Printf("%.3f\n", v)
|
|
clr := GrayCurve(v, 1.0)
|
|
rl.DrawPixelV(world, clr)
|
|
}
|
|
}
|
|
}
|
|
|
|
type ContourSketch struct {
|
|
field Field
|
|
actors []*Actor
|
|
}
|
|
|
|
func NewContourSketch(rng *rand.Rand, field Field) ContourSketch {
|
|
|
|
actors := make([]*Actor, 10000)
|
|
for i := range len(actors) {
|
|
actors[i] =
|
|
&Actor {
|
|
position: RandRadialVec(rng, 0, 500, 0, 360),
|
|
field: field,
|
|
}
|
|
}
|
|
|
|
return ContourSketch {
|
|
actors: actors,
|
|
}
|
|
}
|
|
|
|
func (s *ContourSketch) Draw(ctx *RenderCtx) {
|
|
for _, actor := range s.actors {
|
|
actor.Draw()
|
|
}
|
|
}
|
|
|
|
|
|
type Actor struct {
|
|
position rl.Vector2
|
|
field Field
|
|
}
|
|
|
|
func (a *Actor) Draw() {
|
|
v := a.field.Get(a.position.X, a.position.Y)
|
|
rad := rl.Remap(v, 0, 1, 0, 2 * math.Pi)
|
|
stepSize := float32(2.0)
|
|
nextPosition := rl.Vector2 { X: a.position.X + stepSize*float32(math.Cos(float64(rad))), Y: a.position.Y + stepSize*float32(math.Sin(float64(rad))) }
|
|
rl.DrawLineV(a.position, nextPosition, rl.NewColor(255, 255, 255, 25))
|
|
//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)) }
|
|
}
|
|
|
|
func updateCamera(camera *rl.Camera2D) {
|
|
// Get the world point that is under the mouse
|
|
mouseVec2 := rl.GetMousePosition()
|
|
|
|
if rl.IsMouseButtonDown(rl.MouseRightButton) {
|
|
// get mouse delta from last frame
|
|
delta := rl.GetMouseDelta()
|
|
// compute the amount to move scaled by the camera zoom
|
|
delta = rl.Vector2Scale(delta, -1.0/camera.Zoom)
|
|
camera.Target = rl.Vector2Add(camera.Target, delta)
|
|
}
|
|
// Zoom based on mouse wheel
|
|
wheel := rl.GetMouseWheelMove()
|
|
if wheel != 0 {
|
|
mouseWorldPos := rl.GetScreenToWorld2D(mouseVec2, *camera)
|
|
|
|
// Set the offset to where the mouse is
|
|
camera.Offset = mouseVec2
|
|
|
|
// Set the target to match, so that the camera maps the world space point
|
|
// under the cursor to the screen space point under the cursor at any zoom
|
|
camera.Target = mouseWorldPos
|
|
|
|
// Zoom increment
|
|
const zoomIncrement float32 = 0.125
|
|
|
|
camera.Zoom += (wheel * zoomIncrement)
|
|
if camera.Zoom < zoomIncrement {
|
|
camera.Zoom = zoomIncrement
|
|
}
|
|
}
|
|
}
|
|
|
|
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()
|
|
}
|
|
}
|