Skip to content

Instantly share code, notes, and snippets.

@SoulFireMage
Created October 13, 2015 11:40
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save SoulFireMage/6ec1ddb5b04b77345b7e to your computer and use it in GitHub Desktop.
Save SoulFireMage/6ec1ddb5b04b77345b7e to your computer and use it in GitHub Desktop.
Random art with folder creation
//Most of this is Phil Trelford's code!!
//Gisted to keep it to hand. Add folder creation.
//No other dependencies except what is here.
open System.IO
open System
open System.Drawing
type expr =
| VariableX
| VariableY
| Constant
| Sum of expr * expr
| Product of expr * expr
| Mod of expr * expr
| Well of expr
| Tent of expr
| Sin of expr
| Level of expr * expr * expr
| Mix of expr * expr * expr
let random = System.Random()
let next () = random.NextDouble()
let average (c1,c2,w) =
let r1,g1,b1 = c1
let r2,g2,b2 = c2
let r = w * r1 + (1.0 - w) * r2
let g = w * g1 + (1.0 - w) * g2
let b = w * b1 + (1.0 - w) * b2
r,g,b
let well x = 1.0 - 2.0 / (1.0 + x * x) ** 8.0
let tent x = 1.0 - 2.0 * abs x
let rec eval = function
| VariableX -> fun (x,y) -> (x,x,x)
| VariableY -> fun (x,y) -> (y,y,y)
| Constant ->
let r,g,b = next(),next(),next()
fun (x,y) -> (r,g,b)
| Sum(e1,e2) ->
let f1,f2 = eval e1, eval e2
fun (x,y) ->
average(f1(x,y),f2(x,y),0.5)
| Product(e1,e2) ->
let f1,f2 = eval e1, eval e2
fun (x,y) ->
let r1,g1,b1 = f1(x,y)
let r2,g2,b2 = f2(x,y)
r1*r2, g1*g2, b1*b2
| Mod(e1,e2) ->
let f1,f2 = eval e1, eval e2
fun (x,y) ->
let r1,g1,b1 = f1(x,y)
let r2,g2,b2 = f2(x,y)
r1 % r2, g1 % g2, b1 % b2
| Well(e) ->
let f = eval e
fun (x,y) ->
let r,g,b = f(x,y)
well r, well g, well b
| Tent(e) ->
let f = eval e
fun (x,y) ->
let r,g,b = f(x,y)
tent r, tent g, tent b
| Sin(e) ->
let f = eval e
let phase = next() * System.Math.PI
let freq = (next()*5.0)+1.0
fun (x,y) ->
let r,g,b = f(x,y)
sin(phase + r*freq),sin(phase+g*freq),sin (phase+b*freq)
| Level(e1,e2,e3) ->
let f1,f2,f3 = eval e1, eval e2, eval e3
let threshold = (next()*2.0) - 1.0
fun (x,y) ->
let r1,g1,b1 = f1(x,y)
let r2,g2,b2 = f2(x,y)
let r3,g3,b3 = f3(x,y)
let r = if r1 < threshold then r2 else r3
let g = if g1 < threshold then g2 else g3
let b = if b1 < threshold then b2 else b3
r,g,b
| Mix(e1,e2,e3) ->
let f1,f2,f3 = eval e1, eval e2, eval e3
let threshold = (next()*2.0) - 1.0
fun (x,y) ->
let n, _, _ = f1(x,y)
let w = 0.5 * (n + 1.0)
let c1 = f2(x,y)
let c2 = f3(x,y)
average(c1,c2,w)
let rec gen k =
if k <= 0 || next() < 0.01 then
let terminals = [VariableX; VariableY;Constant]
terminals.[random.Next(terminals.Length)]
else
let n () = random.Next(k)
let operators = [
fun () -> Sum(gen (n()), gen(n()))
fun () -> Product(gen (n()), gen(n()))
fun () -> Mod(gen (n()), gen(n()))
fun () -> Well(gen (n()))
fun () -> Tent(gen (n()))
fun () -> Sin(gen (n()))
fun () -> Level(gen (n()), gen (n()), gen(n()))
fun () -> Mix(gen (n()), gen (n()), gen(n()))
]
operators.[random.Next(operators.Length)]()
#if INTERACTIVE
#r "System.Drawing.dll"
#endif
let rgb (r,g,b) =
let r = max 0 (min 255 (int (128.0 * (r + 1.0))))
let g = max 0 (min 255 (int (128.0 * (g + 1.0))))
let b = max 0 (min 255 (int (128.0 * (b + 1.0))))
r,g,b
let width, height = 1024, 768
let draw f n =
let image = new Bitmap(width, height)
use graphics = Graphics.FromImage(image)
[|for y in 0..n..height-n do
for x in 0..n..width-n -> x,y
|]
|> Array.Parallel.map (fun (x,y) ->
let x' = -1.0 + (((float x+(float n/2.0))*2.0)/float width)
let y' = -1.0 + (((float y+(float n/2.0))*2.0)/float height)
let r,g,b = f(x',y')
let r,g,b = rgb(r,g,b)
x,y,r,g,b
)
|> Array.iter (fun (x,y,r,g,b) ->
use pen = new SolidBrush(Color.FromArgb(r,g,b))
graphics.FillRectangle(pen, x, y, n, n)
)
image
//Quick hack to make random folders in order not to overwrite prior ones!
let p = new System.Random()
let pname = (sprintf @"c:\temp\ArtWork%d\" <| p.Next(1,99999))
let rec pathname (f :DirectoryInfo) = if f.Exists = true then
pathname (new System.IO.DirectoryInfo(pname))
else
f.Create()
f
let name = pname |> fun x -> new System.IO.DirectoryInfo(x) |> pathname
//Figure out a gradient of colours checker and eliminate black ones.
let save n =
let e = gen 50
let f = eval e
let image = draw f 1
let savename = sprintf@"%sRandom%04d.png" name.FullName n
image.Save(savename,Imaging.ImageFormat.Png)
for i = 1 to 1000 do save i
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment