#include #include #include #include #include "til.h" #include "til_fb.h" #include "til_module_context.h" /* Copyright (C) 2017 Vito Caputo */ /* 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? */ typedef struct julia_context_t { til_module_context_t til_module_context; float rr; float realscale; float imagscale; float creal; float cimag; float threshold; } julia_context_t; 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 til_module_context_t * julia_create_context(unsigned seed, unsigned ticks, unsigned n_cpus, til_setup_t *setup) { julia_context_t *ctxt; ctxt = til_module_context_new(sizeof(julia_context_t), seed, ticks, n_cpus); if (!ctxt) return NULL; ctxt->rr = ((float)rand_r(&seed)) / (float)RAND_MAX * 100.f; return &ctxt->til_module_context; } static inline unsigned julia_iter(float real, float imag, float creal, float cimag, unsigned max_iters, float threshold) { 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) > threshold) return i; real = newr; imag = newi; } return 0; } /* Prepare a frame for concurrent drawing of fragment using multiple fragments */ static void julia_prepare_frame(til_module_context_t *context, unsigned ticks, til_fb_fragment_t *fragment, til_fragmenter_t *res_fragmenter) { julia_context_t *ctxt = (julia_context_t *)context; *res_fragmenter = til_fragmenter_slice_per_cpu; ctxt->rr += .01; /* 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. */ ctxt->realscale = 0.01f * cosf(ctxt->rr) + 0.01f; ctxt->imagscale = 0.01f * sinf(ctxt->rr * 3.0f) + 0.01f; ctxt->creal = (1.01f + (ctxt->realscale * cosf(1.5f * M_PI + ctxt->rr) + ctxt->realscale)) * cosf(ctxt->rr * .3f); ctxt->cimag = (1.01f + (ctxt->imagscale * sinf(ctxt->rr * 3.0f) + ctxt->imagscale)) * sinf(ctxt->rr); /* Vary the divergent threshold, this has been tuned to dwell around 1 a bit since it's * quite different looking, then shoot up to a very huge value approaching FLT_MAX which * is also interesting. */ ctxt->threshold = cosf(M_PI + ctxt->rr * .1f) * .5f + .5f; ctxt->threshold *= ctxt->threshold * ctxt->threshold; ctxt->threshold *= 35.f; ctxt->threshold = powf(10.f, ctxt->threshold); } /* Draw a morphing Julia set */ static void julia_render_fragment(til_module_context_t *context, unsigned ticks, unsigned cpu, til_fb_fragment_t *fragment) { julia_context_t *ctxt = (julia_context_t *)context; unsigned x, y; unsigned width = fragment->width, height = fragment->height; uint32_t *buf = fragment->buf; float real, imag; float realstep = 3.6f / (float)fragment->frame_width, imagstep = 3.6f / (float)fragment->frame_height; /* Complex plane confined to {-1.8 - 1.8} on both axis (slightly zoomed), no dynamic zooming is performed. */ for (imag = 1.8 + -(imagstep * (float)fragment->y), y = fragment->y; y < fragment->y + height; y++, imag += -imagstep) { for (real = -1.8 + realstep * (float)fragment->x, x = fragment->x; x < fragment->x + width; x++, buf++, real += realstep) { *buf = colors[julia_iter(real, imag, ctxt->creal, ctxt->cimag, sizeof(colors) / sizeof(*colors), ctxt->threshold)]; } buf += fragment->stride; } } til_module_t julia_module = { .create_context = julia_create_context, .prepare_frame = julia_prepare_frame, .render_fragment = julia_render_fragment, .name = "julia", .description = "Julia set fractal morpher (threaded)", .author = "Vito Caputo ", };