Skip to content

Instantly share code, notes, and snippets.

@nasser
Last active February 9, 2019 02:37
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 nasser/c8c3e15b2733e68a5397bbcfabf14e02 to your computer and use it in GitHub Desktop.
Save nasser/c8c3e15b2733e68a5397bbcfabf14e02 to your computer and use it in GitHub Desktop.
Mandelbrot Renderer Script in Jn
;; based on https://rosettacode.org/wiki/Mandelbrot_set#C.23
;; no idea why System.Drawing.dll is not normally findable, this should be
;; (import "System.Drawing")
(import-from "/lib/mono/gac/System.Drawing/4.0.0.0__b03f5f7f11d50a3a/System.Drawing.dll")
(use "System.Drawing")
(use "System.Drawing.Imaging")
;; should be in stdlib
(defn jn.core/- [^Double a ^Double b]
(cil* Double (ldarg-0) (ldarg-1) (sub)))
(defn jn.core/- [^Double a ^Int32 b]
(cil* Double (ldarg-0) (ldarg-1) (conv-r8) (sub)))
(defn jn.core/- [^Int32 a ^Double b]
(cil* Double (ldarg-0) (conv-r8) (ldarg-1) (sub)))
(defn jn.core/multiply [^Double x ^Int32 y]
(cil* Double (ldarg-0) (ldarg-1) (conv-r8) (mul)))
(defn jn.core/multiply [^Int64 x ^Double y]
(cil* Double (ldarg-0) (conv-r8) (ldarg-1) (mul)))
;; blah name resolution on / is being weird, so just div for now
(defn div [^Int64 a ^Int64 b]
(cil* Double (ldarg-0) (conv-r8) (ldarg-1) (conv-r8) (div)))
(defn div [^Int32 a ^Int32 b]
(cil* Double (ldarg-0) (conv-r8) (ldarg-1) (conv-r8) (div)))
(defn div [^Double a ^Double b]
(cil* Double (ldarg-0) (ldarg-1) (div)))
(defn div [^Double a ^Int32 b]
(cil* Double (ldarg-0) (ldarg-1) (conv-r8) (div)))
(defn int [^Double x]
(cil* Int32 (ldarg-0) (conv-i4)))
(defn clamp [^Double x ^Double min ^Double max]
(cond
(< x min) min
(< max x) max
x))
;; complex type + methods
(def complex (type [^Double re ^Double im]))
(defn jn.core/add [^complex x ^complex y]
(complex (+ (.re x) (.re y))
(+ (.im x) (.im y))))
(defn jn.core/multiply [^complex x ^complex y]
(complex (- (* (.re x) (.re y))
(* (.im x) (.im y)))
(+ (* (.re x) (.im y))
(* (.im x) (.re y)))))
(defn norm [^complex c]
(+ (* (.re c) (.re c))
(* (.im c) (.im c))))
;; mandelbrot algorithms
(defn mandelbrot-color [^complex c]
(let [iterations 1000
max-extent 2.
max-norm (* max-extent max-extent)
max-color 255.
contrast .2]
(loop [z (complex) iteration 0]
(cond
(and (< (norm z) max-norm) (< iteration iterations))
(recur (+ (* z z) c) (inc iteration))
(< iteration iterations)
(let [v (div iteration iterations)]
(Color/FromArgb
(int (* max-color (- 1. (Math/Pow v .25))))
0i
(int (* max-color (Math/Pow v contrast)))))
Color/Black))))
;; whoa this kind of sucks. let and loop dont have macros that handle
;; the implicit do yet, and a built in forloop/dotimes macro is maybe not a
;; bad idea either
(defn render [^Int32 width ^Int32 height]
(let [bmp (Bitmap width height)
max-extent 2.
scale (* 2 (div max-extent (Math/Min width height)))]
(do
(loop [i 0i]
(let [y (* scale (- (div height 2i) i))]
(do
(loop [j 0i]
(do
(let [x (* scale (- j (div width 2i)))
c (mandelbrot-color (complex x y))]
(.SetPixel bmp j i c))
(when (< j width) (recur (inc j)))))
(when (< i height) (recur (inc i))))))
bmp)))
(let [bmp (render 500i 500i)]
(.Save bmp "/home/nasser/projects/jn/fs/out.png" ImageFormat/Png))
using jn;
using Jn;
using System;
using System.Drawing;
using System.Drawing.Imaging;
using System.Reflection;
using System.Runtime.InteropServices;
[assembly: System.Reflection.AssemblyVersion("0.0.0.0")]
public static class user
{
[System.Runtime.InteropServices.StructLayout(LayoutKind.Auto)]
public struct complex
{
public readonly double re;
public readonly double im;
public complex(double re, double im)
{
this.re = re;
this.im = im;
}
}
static user()
{
// Note: this type is marked as 'beforefieldinit'.
Journal.importAssembly(System.Reflection.Assembly.LoadFile("/lib/mono/gac/System.Drawing/4.0.0.0__b03f5f7f11d50a3a/System.Drawing.dll"));
core.use("System.Drawing");
core.use("System.Drawing.Imaging");
Bitmap bitmap = user.render(500, 500);
bitmap.Save("/home/nasser/projects/jn/fs/out.png", ImageFormat.Png);
}
public static double div(long a, long b)
{
return (double)a / (double)b;
}
public static double div(int a, int b)
{
return (double)a / (double)b;
}
public static double div(double a, double b)
{
return a / b;
}
public static double div(double a, int b)
{
return a / (double)b;
}
public static int @int(double x)
{
return (int)x;
}
public static double clamp(double x, double min, double max)
{
return (x >= min) ? ((max >= x) ? x : max) : min;
}
public static double norm(user.complex c)
{
return c.re * c.re + c.im * c.im;
}
public static Color mandelbrot-color(user.complex c)
{
long num = 1000L;
double num2 = 2.0;
double num3 = num2 * num2;
double num4 = 255.0;
double y = 0.2;
user.complex complex = default(user.complex);
long num5 = 0L;
while (core.and(user.norm(complex) < num3, num5 < num))
{
user.complex arg_66_0 = jn.core.add(jn.core.multiply(complex, complex), c);
num5 += 1L;
complex = arg_66_0;
}
Color arg_B3_0;
if (num5 < num)
{
double x = user.div(num5, num);
arg_B3_0 = Color.FromArgb((int)(num4 * (1.0 - System.Math.Pow(x, 0.25))), 0, (int)(num4 * System.Math.Pow(x, y)));
}
else
{
arg_B3_0 = Color.Black;
}
return arg_B3_0;
}
public static Bitmap render(int width, int height)
{
Bitmap bitmap = new Bitmap(width, height);
double num = 2.0;
double num2 = jn.core.multiply(2L, num / (double)System.Math.Min(width, height));
int num3 = 0;
while (true)
{
double im = num2 * (user.div(height, 2) - (double)num3);
int num4 = 0;
while (true)
{
double re = num2 * jn.core.-(num4, user.div(width, 2));
Color color = user.mandelbrot-color(new user.complex(re, im));
bitmap.SetPixel(num4, num3, color);
if (num4 >= width)
{
break;
}
num4++;
}
if (num3 >= height)
{
break;
}
num3++;
}
return bitmap;
}
}
public static class jn
{
public static class core
{
public static double -(double a, double b)
{
return a - b;
}
public static double -(double a, int b)
{
return a - (double)b;
}
public static double -(int a, double b)
{
return (double)a - b;
}
public static double multiply(double x, int y)
{
return x * (double)y;
}
public static double multiply(long x, double y)
{
return (double)x * y;
}
public static user.complex add(user.complex x, user.complex y)
{
return new user.complex(x.re + y.re, x.im + y.im);
}
public static user.complex multiply(user.complex x, user.complex y)
{
return new user.complex(x.re * y.re - x.im * y.im, x.re * y.im + x.im * y.re);
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment