diff --git a/common/blend.go b/common/blend.go new file mode 100644 index 0000000..23dede2 --- /dev/null +++ b/common/blend.go @@ -0,0 +1,62 @@ +package common + +import ( + "image" + "image/color" +) + +type BlendMode int + +const ( + Add BlendMode = iota +) + +func Blend(src, dest *image.RGBA, mode BlendMode) *image.RGBA { + img := image.NewRGBA(src.Bounds()) + + for i := 0; i b{ + return a + } + return b +} + // Remap re-maps a number from one range to another. func Remap(n, start1, stop1, start2, stop2 float64) float64 { newval := (n-start1)/(stop1-start1)*(stop2-start2) + start2 diff --git a/common/calculation_test.go b/common/calculation_test.go new file mode 100644 index 0000000..f52acdc --- /dev/null +++ b/common/calculation_test.go @@ -0,0 +1,51 @@ +package common + +import "testing" + +func TestConstrain(t *testing.T) { + type args struct { + val float64 + low float64 + high float64 + } + tests := []struct { + name string + args args + want float64 + }{ + {name: "testcase1", args: args{val: 1.0, low:0.5, high: 1.5}, want: 1.0}, + {name: "testcase2", args: args{val: 0.4, low:0.5, high: 1.5}, want: 0.5}, + {name: "testcase3", args: args{val: -1.0, low:-3.5, high: 1.5}, want: -1.0}, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + if got := Constrain(tt.args.val, tt.args.low, tt.args.high); got != tt.want { + t.Errorf("Constrain() = %v, want %v", got, tt.want) + } + }) + } +} + +func TestConstrainInt(t *testing.T) { + type args struct { + val int + low int + high int + } + tests := []struct { + name string + args args + want int + }{ + {name: "testcase1", args: args{val: 256, low: 0, high: 255}, want: 255}, + {name: "testcase2", args: args{val: -1, low: 0, high: 255}, want: 0}, + {name: "testcase3", args: args{val: 100, low: 0, high: 255}, want: 100}, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + if got := ConstrainInt(tt.args.val, tt.args.low, tt.args.high); got != tt.want { + t.Errorf("ConstrainInt() = %v, want %v", got, tt.want) + } + }) + } +} \ No newline at end of file diff --git a/example/example_solarflare.go b/example/example_solarflare.go new file mode 100644 index 0000000..0d661ba --- /dev/null +++ b/example/example_solarflare.go @@ -0,0 +1,19 @@ +package main + +import ( + "github.com/jdxyw/generativeart" + "github.com/jdxyw/generativeart/common" + "image/color" + "math/rand" + "time" +) + +func main() { + rand.Seed(time.Now().Unix()) + c := generativeart.NewCanva(500, 500) + c.SetBackground(common.Black) + c.FillBackground() + c.SetLineColor(color.RGBA{255, 64, 8, 128}) + c.Draw(generativeart.NewSolarFlare()) + c.ToPNG("solarflare.png") +} diff --git a/solarflare.go b/solarflare.go new file mode 100644 index 0000000..e112276 --- /dev/null +++ b/solarflare.go @@ -0,0 +1,65 @@ +package generativeart + +import ( + "github.com/fogleman/gg" + "github.com/jdxyw/generativeart/common" + "image" + "image/color" + "image/draw" + "math" +) + +type solarFlare struct { +} + +func NewSolarFlare() *solarFlare { + return &solarFlare{} +} + + +// Generative draws a solar flare images. +func (o *solarFlare) Generative(c *canva) { + var xOffset, yOffset float64 + var offsetInc = 0.006 + var inc = 1.0 + var r = 1.0 + var m = 1.005 + noise := common.NewPerlinNoise() + + + for r < 200 { + for i :=0; i <10; i++ { + nPoints := int(2*math.Pi*r) + nPoints = common.MinInt(nPoints, 500) + + img := image.NewRGBA(image.Rect(0, 0, c.width, c.height)) + draw.Draw(img, img.Bounds(), &image.Uniform{color.RGBA{0,0,0,255}}, image.ZP, draw.Src) + ctex := gg.NewContextForRGBA(img) + + ctex.Push() + ctex.Translate(float64(c.width/2), float64(c.height/2)) + ctex.SetLineWidth(1.0) + ctex.SetColor(c.opts.lineColor) + + for j :=0.0; j