summaryrefslogtreecommitdiff
path: root/src/modules/julia/julia.c
blob: 1afb3cc2b559bdf3cae78825d3c145e56d687c0f (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
#include <stdint.h>
#include <inttypes.h>
#include <math.h>

#include "fb.h"
#include "rototiller.h"

/* Copyright (C) 2017 Vito Caputo <vcaputo@pengaru.com> */

/* Julia set renderer - see https://en.wikipedia.org/wiki/Julia_set, morphing just means to vary C. */

/* TODO: explore using C99 complex.h and its types? */

static inline unsigned julia_iter(float real, float imag, float creal, float cimag, unsigned max_iters)
{
	unsigned	i;
	float		newr, newi;

	for (i = 1; i < max_iters; i++) {
		newr = real * real - imag * imag;
		newi = imag * real;
		newi += newi;

		newr += creal;
		newi += cimag;

		if ((newr * newr + newi * newi) > 4.0)
			return i;

		real = newr;
		imag = newi;
	}

	return 0;
}

/* Draw a morphing Julia set */
static void julia(fb_fragment_t *fragment)
{
	static uint32_t	colors[] = {
				/* this palette is just something I slapped together, definitely needs improvement. TODO */
				0x000000,
				0x000044,
				0x000088,
				0x0000aa,
				0x0000ff,
				0x0044ff,
				0x0088ff,
				0x00aaff,
				0x00ffff,
				0x44ffaa,
				0x88ff88,
				0xaaff44,
				0xffff00,
				0xffaa00,
				0xff8800,
				0xff4400,
				0xff0000,
				0xaa0000,
				0x880000,
				0x440000,
				0x440044,
				0x880088,
				0xaa00aa,
				0xff00ff,
				0xff4400,
				0xff8800,
				0xffaa00,
				0xffff00,
				0xaaff44,
				0x88ff88,
				0x44ffaa,
				0x00ffff,
				0x00aaff,
				0x0088ff,
				0xff4400,
				0xff00ff,
				0xaa00aa,
				0x880088,
				0x440044,

			};
	static float	rr;

	unsigned	x, y;
	unsigned	stride = fragment->stride / 4, width = fragment->width, height = fragment->height;
	uint32_t	*buf = fragment->buf;
	float		real, imag;
	float		realstep = 3.6f / (float)width, imagstep = 3.6f / (float)height;

			/* Rather than just sweeping creal,cimag from -2.0-+2.0, I try to keep things confined
			 * to an interesting (visually) range.  TODO: could certainly use refinement.
			 */
	float		realscale = 0.01f * cosf(rr) + 0.01f;
	float		imagscale = 0.01f * sinf(rr * 3.0f) + 0.01f;
	float		creal = (1.01f + (realscale * cosf(1.5f*M_PI+rr) + realscale)) * cosf(rr * .3f);
	float		cimag = (1.01f + (imagscale * sinf(rr * 3.0f) + imagscale)) * sinf(rr);

	/* Complex plane confined to {-1.8 - 1.8} on both axis (slightly zoomed), no dynamic zooming is performed. */
	for (imag = 1.8, y = 0; y < height; y++, imag += -imagstep) {
		for (real = -1.8, x = 0; x < width; x++, buf++, real += realstep) {
			*buf = colors[julia_iter(real, imag, creal, cimag, sizeof(colors) / sizeof(*colors))];
		}

		buf += stride;
	}

	rr += .01;
}

rototiller_renderer_t	julia_renderer = {
	.render = julia,
	.name = "julia",
	.description = "Julia set fractal morpher",
	.author = "Vito Caputo <vcaputo@pengaru.com>",
	.license = "GPLv2",
};
© All Rights Reserved