diff --git a/field.go b/field.go index a6b6bef..68f1406 100644 --- a/field.go +++ b/field.go @@ -1,6 +1,7 @@ package main import ( + "fmt" rl "github.com/gen2brain/raylib-go/raylib" "github.com/ojrac/opensimplex-go" ) @@ -46,7 +47,7 @@ func (f *SimplexNoiseField) Get(x, y float32) float32 { type ImageField struct { image *rl.Image pixels ImagePixels - offsetX, offsetY float32 + offsetX, offsetY int } type ImagePixels struct { @@ -66,14 +67,15 @@ func (p *ImagePixels) Get(x, y int) rl.Color { func NewImageField(path string) ImageField { image := rl.LoadImage(path) + fmt.Printf("loaded image from %s\n", path) colors := rl.LoadImageColors(image) pixels := ImagePixels{ w: int(image.Width), h: int(image.Height), colors: colors, } - offsetX := float32(image.Width / 2) - offsetY := float32(image.Height / 2) + offsetX := int(image.Width)/2 + offsetY := int(image.Height)/2 return ImageField{ image: image, pixels: pixels, @@ -82,8 +84,9 @@ func NewImageField(path string) ImageField { } } +// zero centered func (f *ImageField) Get(x, y float32) float32 { // todo : blend colors - c := f.pixels.Get(int(x+f.offsetX), int(y+f.offsetY)) + c := f.pixels.Get(int(x+float32(f.offsetX)), int(y+float32(f.offsetY))) return Brightness(c) } diff --git a/main.go b/main.go index e0fd15e..f6e8866 100644 --- a/main.go +++ b/main.go @@ -13,9 +13,9 @@ import ( ) const ( - targetWidth = 800 - targetHeight = 600 - sourceScale = 10 + targetWidth = 1000 + targetHeight = 1000 + sourceScale = 8 snapshotsDir = "snapshots" ) @@ -42,11 +42,6 @@ func main() { rl.SetConfigFlags(rl.FlagMsaa4xHint) rl.InitWindow(targetWidth, targetHeight, "sumi sierpinski arrow") - log.Printf("screen=%dx%d render=%dx%d", - rl.GetScreenWidth(), rl.GetScreenHeight(), - rl.GetRenderWidth(), rl.GetRenderHeight(), - ) - // point at source center // put source center at center of screen var camera = TextureCam { @@ -56,36 +51,35 @@ func main() { SourceHeight: sourceHeight, } - /* - field := - ScaleField { - Scale: 50.0, - Field: &SimplexNoiseField { - Noise: opensimplex.NewNormalized32(0), - }, - } - imgf := NewImageField("/home/d/Dropbox/art/passage/data/david.png") - imageField := - ScaleField{ - field: &imgf, - scale: 0.5, - } - */ - - //rng := rand.New(rand.NewSource(0)) - - //contourSketch := NewContourLayer(rng, &imageField) - - sketch := NewSketch() - sketch.CreateLayer("testPattern", &TestPattern{}, int32(sourceWidth), int32(sourceHeight)) - rl.SetTargetFPS(60) - t0 := time.Now() - ports := MakePorts() + /* + */ - ports["sierpinskiArrowAngle"] = Sine{ + 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, @@ -110,20 +104,30 @@ func main() { sketch.Update(renderCtx) /** - MAIN DRAWING - **/ + * 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() - if rl.IsKeyDown(rl.KeySpace) { - if _, err := storage.Save(); err != nil { - log.Printf("Error saving snapshot: %v\n", err) + 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) } } @@ -135,38 +139,50 @@ func main() { rl.CloseWindow() } -type FieldSketch struct { - Field Field +func resetCamera(cam *TextureCam) { + cam.LookAt = rl.Vector2 { X: float32(cam.SourceWidth) / 2.0, Y: float32(cam.SourceHeight) / 2.0 } + cam.Zoom = 1.0 } -/* -func (s *FieldSketch) Draw(ctx *RenderCtx) { - fmt.Printf("drawing field") - for x := range ctx.TargetWidth { - for y := range ctx.TargetHeight { - screen := rl.Vector2{X: float32(x), Y: float32(y)} - world := rl.GetScreenToWorld2D(screen, ctx.Cam) - v := s.Field.Get(world.X, world.Y) +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.DrawPixelV(world, clr) + 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) ContourLayer { +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: RandRadialVec(rng, 0, 500, 0, 360), - field: field, + position: rl.Vector2 { X: float32(x), Y: float32(y) }, + field: field, stepSize: 1, color: rl.NewColor(11, 35, 176, 100), } @@ -177,10 +193,20 @@ func NewContourLayer(rng *rand.Rand, field Field) ContourLayer { } } +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 { diff --git a/sketch.go b/sketch.go index f9d7420..7e6f020 100644 --- a/sketch.go +++ b/sketch.go @@ -7,31 +7,37 @@ import ( type Sketch struct { layerTools map[string]LayerTools + layerToolsOrdered []LayerTools } func NewSketch() Sketch { return Sketch{ layerTools: make(map[string]LayerTools), + layerToolsOrdered: []LayerTools {}, } } func (s *Sketch) CreateLayer(name string, layer Layer, sourceWidth int32, sourceHeight int32) { texture := rl.LoadRenderTexture(sourceWidth, sourceHeight) - s.layerTools[name] = LayerTools{ + layerTools := LayerTools { name: name, texture: &texture, layer: layer, } + s.layerToolsOrdered = append(s.layerToolsOrdered, layerTools) + s.layerTools[name] = layerTools } func (s *Sketch) Draw(ctx *RenderCtx) { // render onto all layer textures - for _, instance := range s.layerTools { - layer := instance.layer - rl.BeginTextureMode(*instance.texture) - rl.ClearBackground(rl.Blank) - layer.Draw(ctx) - rl.EndTextureMode() + for _, instance := range s.layerToolsOrdered { + instance.layer.Update(ctx) + if instance.layer.IsDirty() { + layer := instance.layer + rl.BeginTextureMode(*instance.texture) + layer.Draw(ctx) + rl.EndTextureMode() + } } // composite all layers to screen @@ -45,7 +51,7 @@ func (s *Sketch) Draw(ctx *RenderCtx) { viewport := s.CalcViewport(ctx) - for _, instance := range s.layerTools { + for _, instance := range s.layerToolsOrdered { rl.DrawTexturePro(instance.texture.Texture, viewport, screen, rl.Vector2{}, 0, rl.White) } @@ -101,20 +107,17 @@ type LayerTools struct { /** Layer **/ type Layer interface { + Update(ctx *RenderCtx) Draw(ctx *RenderCtx) + IsDirty() bool } -type TestPattern struct{} +type TestPattern struct{ + dirty bool +} -func DrawGrid(spacing int32, halfExtent int32) { - col := rl.Color{R: 220, G: 220, B: 220, A: 255} - - for x := -halfExtent; x <= halfExtent; x += spacing { - rl.DrawLine(x, -halfExtent, x, halfExtent, col) - } - for y := -halfExtent; y <= halfExtent; y += spacing { - rl.DrawLine(-halfExtent, y, halfExtent, y, col) - } +func (tp *TestPattern) Update(ctx *RenderCtx) { + ; } func (tp *TestPattern) Draw(ctx *RenderCtx) { @@ -137,6 +140,12 @@ func (tp *TestPattern) Draw(ctx *RenderCtx) { rl.DrawLine(0, -10000, 0, 10000, rl.Green) rl.DrawRectangleLines(-50, -50, 100, 100, rl.Magenta) rl.PopMatrix() + + tp.dirty = false +} + +func (tp *TestPattern) IsDirty() bool { + return tp.dirty } /** Ports **/ diff --git a/sumi b/sumi new file mode 100755 index 0000000..b44d27a Binary files /dev/null and b/sumi differ