From 3a17d7380b5f024992b032dcdcad2c2aa16df99e Mon Sep 17 00:00:00 2001 From: Philip J Freeman Date: Wed, 1 Jan 2020 15:04:34 -0800 Subject: spiro: spirograph emulator This commit adds a module that emulates a spirograph --- configure.ac | 1 + src/Makefile.am | 2 +- src/modules/Makefile.am | 2 +- src/modules/spiro/Makefile.am | 3 + src/modules/spiro/draw.h | 16 +++++ src/modules/spiro/spiro.c | 155 ++++++++++++++++++++++++++++++++++++++++++ src/rototiller.c | 2 + 7 files changed, 179 insertions(+), 2 deletions(-) create mode 100644 src/modules/spiro/Makefile.am create mode 100644 src/modules/spiro/draw.h create mode 100644 src/modules/spiro/spiro.c diff --git a/configure.ac b/configure.ac index 091b6e5..872acec 100644 --- a/configure.ac +++ b/configure.ac @@ -52,6 +52,7 @@ AC_CONFIG_FILES([ src/modules/rtv/Makefile src/modules/snow/Makefile src/modules/sparkler/Makefile + src/modules/spiro/Makefile src/modules/stars/Makefile src/modules/submit/Makefile src/modules/swab/Makefile diff --git a/src/Makefile.am b/src/Makefile.am index 5446acd..43c79e7 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -4,4 +4,4 @@ rototiller_SOURCES = fb.c fb.h fps.c fps.h rototiller.c rototiller.h sdl_fb.c se if ENABLE_DRM rototiller_SOURCES += drm_fb.c endif -rototiller_LDADD = modules/flui2d/libflui2d.a modules/julia/libjulia.a modules/meta2d/libmeta2d.a modules/montage/libmontage.a modules/pixbounce/libpixbounce.a modules/plasma/libplasma.a modules/ray/libray.a modules/roto/libroto.a modules/rtv/librtv.a modules/snow/libsnow.a modules/sparkler/libsparkler.a modules/stars/libstars.a modules/submit/libsubmit.a modules/swab/libswab.a libs/grid/libgrid.a libs/ray/libray.a libs/txt/libtxt.a libs/ascii/libascii.a libs/din/libdin.a -lm +rototiller_LDADD = modules/flui2d/libflui2d.a modules/julia/libjulia.a modules/meta2d/libmeta2d.a modules/montage/libmontage.a modules/pixbounce/libpixbounce.a modules/plasma/libplasma.a modules/ray/libray.a modules/roto/libroto.a modules/rtv/librtv.a modules/snow/libsnow.a modules/sparkler/libsparkler.a modules/spiro/libspiro.a modules/stars/libstars.a modules/submit/libsubmit.a modules/swab/libswab.a libs/grid/libgrid.a libs/ray/libray.a libs/txt/libtxt.a libs/ascii/libascii.a libs/din/libdin.a -lm diff --git a/src/modules/Makefile.am b/src/modules/Makefile.am index a4ff9e7..958d835 100644 --- a/src/modules/Makefile.am +++ b/src/modules/Makefile.am @@ -1 +1 @@ -SUBDIRS = flui2d julia meta2d montage pixbounce plasma ray roto rtv snow sparkler stars submit swab +SUBDIRS = flui2d julia meta2d montage pixbounce plasma ray roto rtv snow sparkler spiro stars submit swab diff --git a/src/modules/spiro/Makefile.am b/src/modules/spiro/Makefile.am new file mode 100644 index 0000000..f03d8cd --- /dev/null +++ b/src/modules/spiro/Makefile.am @@ -0,0 +1,3 @@ +noinst_LIBRARIES = libspiro.a +libspiro_a_SOURCES = draw.h spiro.c +libspiro_a_CPPFLAGS = -I@top_srcdir@/src diff --git a/src/modules/spiro/draw.h b/src/modules/spiro/draw.h new file mode 100644 index 0000000..0b68c00 --- /dev/null +++ b/src/modules/spiro/draw.h @@ -0,0 +1,16 @@ +#ifndef _DRAW_H +#define _DRAW_H + +#include + +/* helper for scaling rgb colors and packing them into an pixel */ +static inline uint32_t makergb(uint32_t r, uint32_t g, uint32_t b, float intensity) +{ + r = (((float)intensity) * r); + g = (((float)intensity) * g); + b = (((float)intensity) * b); + + return (((r & 0xff) << 16) | ((g & 0xff) << 8) | (b & 0xff)); +} + +#endif diff --git a/src/modules/spiro/spiro.c b/src/modules/spiro/spiro.c new file mode 100644 index 0000000..f6aeddc --- /dev/null +++ b/src/modules/spiro/spiro.c @@ -0,0 +1,155 @@ +#include +#include +#include +#include +#include + +#include "draw.h" +#include "fb.h" +#include "rototiller.h" + +/* Copyright (C) 2020 Philip J. Freeman */ + +/* + +Spirograph Emulator + + refs: + + - https://en.wikipedia.org/wiki/Spirograph#Mathematical_basis + - https://en.wikipedia.org/wiki/Unit_circle#Trigonometric_functions_on_the_unit_circle +*/ + +typedef struct spiro_context_t { + float r; + int r_dir; + float p; + int p_dir; +} spiro_context_t; + + +static void * spiro_create_context(unsigned num_cpus) +{ + spiro_context_t *ctxt; + float z; + + ctxt = malloc(sizeof(spiro_context_t)); + if (!ctxt) + return NULL; + + srand(time(NULL) + getpid()); + + ctxt->r=.25f+(rand()/(float)RAND_MAX)*.5f; + if(ctxt->r>.5f) + ctxt->r_dir=-1; + else + ctxt->r_dir=1; + ctxt->p=(rand()/(float)RAND_MAX)*ctxt->r; + ctxt->p_dir=ctxt->r_dir*-1; +#ifdef DEBUG + printf("spiro: initial context: r=%f, dir=%i, p=%f, dir=%i\n", ctxt->r, ctxt->r_dir, ctxt->p, ctxt->p_dir); +#endif + return ctxt; +} + +static void spiro_destroy_context(void *context) +{ + spiro_context_t *ctxt = context; + + free(context); +} + + +static void spiro_render_fragment(void *context, unsigned cpu, fb_fragment_t *fragment) +{ + spiro_context_t *ctxt = context; + + int width = fragment->width, height = fragment->height; + + int display_R, display_origin_x, display_origin_y; + + /* Based on the fragment's dimensions, calculate the origin and radius of the fixed outer + circle, C0. */ + + if(width>=height) { // landscape or square aspect ratio + display_R=(height-1)*0.5f; + display_origin_x=((width-height)*.5f)+display_R; + display_origin_y=display_R; + } else { // portrait + display_R=(width-1)*.5f; + display_origin_x=display_R; + display_origin_y=((height-width)*.5f)+display_R; + } + + /* blank the fragment */ + fb_fragment_zero(fragment); + + /* plot one spirograph run */ + float l=ctxt->p/ctxt->r; + float k=ctxt->r; + for(float t=0.f; t<128*2*M_PI; t+= M_PI/display_R) { + float my_x=((1.f-k)*cosf(t))+(l*k*cosf(((1.f-k)/k)*t)); + float my_y=((1.f-k)*sinf(t))-(l*k*sinf(((1.f-k)/k)*t)); + int pos_x=display_origin_x+(my_x*display_R); + int pos_y=display_origin_y+(my_y*display_R); + fb_fragment_put_pixel_unchecked(fragment, pos_x, pos_y, + makergb(sinf(M_1_PI*t)*127+128, + sinf(M_1_PI*t+(2*M_PI*.333333333333f))*127+128, + sinf(M_1_PI*t+(4*M_PI*.333333333333f))*127+128, + 0.76)); + } + +#ifdef DEBUG + /* plot the origin point */ + fb_fragment_put_pixel_unchecked(fragment, display_origin_x, display_origin_y, + makergb(0xFF, 0xFF, 0x00, 1)); + + /* plot the fixed outer circle C0 */ + for(float a=0.f; a<2*M_PI; a+= M_PI_2/display_R) { + int pos_x=display_origin_x+(cosf(a)*display_R); + int pos_y=display_origin_y+(sinf(a)*display_R); + fb_fragment_put_pixel_unchecked(fragment, pos_x, pos_y, + makergb(0xFF, 0xFF, 0x00, 1)); + } + + /* plot inner circle Ci */ + fb_fragment_put_pixel_unchecked(fragment, display_origin_x+display_R-(ctxt->r*display_R), + display_origin_y, makergb(0xFF, 0xFF, 0x00, 1)); + + for(float a=0.f; a<2*M_PI; a+= M_PI_2/display_R) { + int pos_x=display_origin_x+display_R-(ctxt->r*display_R)+ + (cosf(a)*ctxt->r*display_R); + int pos_y=display_origin_y+(sinf(a)*ctxt->r*display_R); + fb_fragment_put_pixel_unchecked(fragment, pos_x, pos_y, + makergb(0xFF, 0xFF, 0x00, 1)); + } + + /* plot p */ + fb_fragment_put_pixel_unchecked(fragment, display_origin_x+display_R-(ctxt->r*display_R)+ + (ctxt->p*display_R), display_origin_y, makergb(0xFF, 0xFF, 0x00, 1)); +#endif + + /* check bounds and increment r & p */ + float next_r=ctxt->r+(.00001f*ctxt->r_dir); + if(next_r >= 1.f || next_r <= 0.f || next_r <= ctxt->p) + ctxt->r_dir=ctxt->r_dir*-1; + else + ctxt->r=ctxt->r+(.00001f*ctxt->r_dir); + + float next_p=ctxt->p+(.0003f*ctxt->p_dir); + if(next_p >= ctxt->r || next_p <= 0) + ctxt->p_dir=ctxt->p_dir*-1; + else + ctxt->p=ctxt->p+(.0003f*ctxt->p_dir); + +} + +rototiller_module_t spiro_module = { + .create_context = spiro_create_context, + .destroy_context = spiro_destroy_context, + .render_fragment = spiro_render_fragment, + .name = "spiro", + .description = "Spirograph Emulator", + .author = "Philip J Freeman ", + .license = "GPLv2", +}; diff --git a/src/rototiller.c b/src/rototiller.c index d8fa665..644013b 100644 --- a/src/rototiller.c +++ b/src/rototiller.c @@ -43,6 +43,7 @@ extern rototiller_module_t roto_module; extern rototiller_module_t rtv_module; extern rototiller_module_t snow_module; extern rototiller_module_t sparkler_module; +extern rototiller_module_t spiro_module; extern rototiller_module_t stars_module; extern rototiller_module_t submit_module; extern rototiller_module_t swab_module; @@ -59,6 +60,7 @@ static const rototiller_module_t *modules[] = { &rtv_module, &snow_module, &sparkler_module, + &spiro_module, &stars_module, &submit_module, &swab_module, -- cgit v1.2.1