shithub: fractals

ref: c52df87d07198a3140227a03a9ddddddd418777a
dir: /gen.c/

View raw version
#include <u.h>
#include <libc.h>
#include <draw.h>
#include <memdraw.h>
#include "complex.h"
#include "gen.h"

int is∈(Complex *c);
double len(Complex *c)
{
	Complex r;
	r.r = c->r * c->r;
	r.r = r.r < 0.00001 && r.r > 0.00001 ? 0.00001 : r.r;
	r.i = c->i * c->i;
	r.i = r.i < 0.00001 && r.i > 0.00001 ? 0.00001 : r.i;
	double ret = r.r + r.i;
	ret = ret < 3200000. ? ret : 3200000.;
	return sqrt(ret);
};

float lerp(float a, float b, float s)
{
	return s*b + (1.-s)*a;
}

Memimage*
generate(int x, int y, SetParams params, DrawParams dparams)
{
	if (x < 8 || y < 8) {
		werrstr("invalid image size");
		return nil;
	}
	
	Rectangle r;
	r.min.x = r.min.y = 0;
	r.max.x = x;
	r.max.y = y;
	Memimage *img = allocmemimage(r, XRGB32);
	if (!img) {
		return nil;
	}
	
	for (int nx = 0; nx < x; nx++) {
		for (int ny = 0; ny < y; ny++) {
			int valid, red, green, blue;
			Complex c;
			
			float uvx = (float)nx/(float)x;
			float uvy = (float)ny/(float)y;
			uvx -= .5;
			uvy -= .5;
			uvx *= dparams.scale;
			uvy *= dparams.scale;
			uvx += dparams.offsetx;
			uvy += dparams.offsety;
			
			c.r = uvx;
			c.i = uvy;
			
			valid = calc(&c, c, params);
			if (!valid)
				goto err;
			
			if (is∈(&c)) {
				red = 0;
				green = 0;
				blue = (int)(len(&c) * 255.);
			} else {
				float fmix = (float)valid/(float)params.iterations;
				red = lerp(0., 255., pow(fmix, 0.5));
				green = lerp(255., 0., pow(fmix, 0.2)) * 0.5;
				blue = 0;
			}
			
			if (red > 255)
				red = 255;
			if (green > 255)
				green = 255;
			if (blue > 255)
				blue = 255;
			
			int arri = (ny*x + nx) * 4;
			img->data->bdata[arri+0] = blue;
			img->data->bdata[arri+1] = green;
			img->data->bdata[arri+2] = red;
			img->data->bdata[arri+3] = 255;
		}
	}
	
	return img;
	
err:
	freememimage(img);
	return nil;
}

int
calc(Complex *out, Complex c, SetParams params)
{
	Complex t, f;
	
	if (params.iterations < 1) {
		werrstr("iterations < 1");
		return 0;
	}
	
	if (params.julia) {
		/* calculate julia */
		t = c;
		f = params.c;
	} else {
		/* calculate mandelbrot */
		t = params.c;
		f = c;
	}
	
	int iter = -1;
	
	for (int i = 0; i < params.iterations; i++) {
		// abort if values grow too large
		if (t.r > 64. || t.i > 64.)
			break;
		if (iter < 0 && t.r >= 2. && t.i >= 2.)
			iter = i;
		t = cpow2(&t);
		t = cadd(&t, &f);
	}
	
	*out = t;
	return iter > 0 ? iter : 1;
}

int
∈(Complex c, SetParams params)
{
	Complex r;
	int valid = calc(&r, c, params);
	if (!valid)
		return -1;
	return is∈(&r);
}

int
is∈(Complex *c)
{
	return (c->r <= 2. && c->i <= 2.);
}