summaryrefslogtreecommitdiffstats
path: root/hacks/glx/stonerview-osc.c
diff options
context:
space:
mode:
Diffstat (limited to 'hacks/glx/stonerview-osc.c')
-rw-r--r--hacks/glx/stonerview-osc.c341
1 files changed, 341 insertions, 0 deletions
diff --git a/hacks/glx/stonerview-osc.c b/hacks/glx/stonerview-osc.c
new file mode 100644
index 0000000..1b79a23
--- /dev/null
+++ b/hacks/glx/stonerview-osc.c
@@ -0,0 +1,341 @@
+/* StonerView: An eccentric visual toy.
+ Copyright 1998-2001 by Andrew Plotkin (erkyrath@eblong.com)
+
+ Permission to use, copy, modify, distribute, and sell this software and its
+ documentation for any purpose is hereby granted without fee, provided that
+ the above copyright notice appear in all copies and that both that
+ copyright notice and this permission notice appear in supporting
+ documentation. No representations are made about the suitability of this
+ software for any purpose. It is provided "as is" without express or
+ implied warranty.
+*/
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "yarandom.h"
+#include "stonerview.h"
+
+
+/* Return a random number between min and max, inclusive. */
+static int rand_range(int min, int max)
+{
+ int res;
+ unsigned int diff = (max+1) - min;
+ if (diff <= 1)
+ return min;
+ res = random() % diff;
+ return min+res;
+}
+
+
+/* Create a new, blank osc_t. The caller must fill in the type data. */
+static osc_t *create_osc(stonerview_state *st, int type)
+{
+ osc_t *osc = (osc_t *)malloc(sizeof(osc_t));
+ if (!osc)
+ return NULL;
+
+ osc->type = type;
+ osc->next = NULL;
+
+ *st->osctail = osc;
+ st->osctail = &(osc->next);
+
+ return osc;
+}
+
+/* Creation functions for all the osc_t types. These are all pretty obvious
+ in their construction. */
+
+osc_t *new_osc_constant(stonerview_state *st, int val)
+{
+ osc_t *osc = create_osc(st, otyp_Constant);
+ if (!osc)
+ return NULL;
+
+ osc->u.oconstant.val = val;
+ return osc;
+}
+
+osc_t *new_osc_bounce(stonerview_state *st, int min, int max, int step)
+{
+ int diff;
+ osc_t *osc = create_osc(st, otyp_Bounce);
+ if (!osc)
+ return NULL;
+
+ osc->u.obounce.min = min;
+ osc->u.obounce.max = max;
+ osc->u.obounce.step = step;
+
+ /* Pick a random initial value between min and max. */
+ if (step < 0)
+ step = (-step);
+ diff = (max-min) / step;
+ osc->u.obounce.val = min + step * rand_range(0, diff-1);
+
+ return osc;
+}
+
+osc_t *new_osc_wrap(stonerview_state *st, int min, int max, int step)
+{
+ int diff;
+ osc_t *osc = create_osc(st, otyp_Wrap);
+ if (!osc)
+ return NULL;
+
+ osc->u.owrap.min = min;
+ osc->u.owrap.max = max;
+ osc->u.owrap.step = step;
+
+ /* Pick a random initial value between min and max. */
+ if (step < 0)
+ step = (-step);
+ diff = (max-min) / step;
+ osc->u.owrap.val = min + step * rand_range(0, diff-1);
+
+ return osc;
+}
+
+osc_t *new_osc_velowrap(stonerview_state *st, int min, int max, osc_t *step)
+{
+ osc_t *osc = create_osc(st, otyp_VeloWrap);
+ if (!osc)
+ return NULL;
+
+ osc->u.ovelowrap.min = min;
+ osc->u.ovelowrap.max = max;
+ osc->u.ovelowrap.step = step;
+
+ /* Pick a random initial value between min and max. */
+ osc->u.ovelowrap.val = rand_range(min, max);
+
+ return osc;
+}
+
+osc_t *new_osc_multiplex(stonerview_state *st,
+ osc_t *sel, osc_t *ox0,
+ osc_t *ox1, osc_t *ox2,
+ osc_t *ox3)
+{
+ osc_t *osc = create_osc(st, otyp_Multiplex);
+ if (!osc)
+ return NULL;
+
+ osc->u.omultiplex.sel = sel;
+ osc->u.omultiplex.val[0] = ox0;
+ osc->u.omultiplex.val[1] = ox1;
+ osc->u.omultiplex.val[2] = ox2;
+ osc->u.omultiplex.val[3] = ox3;
+
+ return osc;
+}
+
+osc_t *new_osc_phaser(stonerview_state *st, int phaselen)
+{
+ osc_t *osc = create_osc(st, otyp_Phaser);
+ if (!osc)
+ return NULL;
+
+ osc->u.ophaser.phaselen = phaselen;
+
+ osc->u.ophaser.count = 0;
+ /* Pick a random phase to start in. */
+ osc->u.ophaser.curphase = rand_range(0, NUM_PHASES-1);
+
+ return osc;
+}
+
+osc_t *new_osc_randphaser(stonerview_state *st,
+ int minphaselen, int maxphaselen)
+{
+ osc_t *osc = create_osc(st, otyp_RandPhaser);
+ if (!osc)
+ return NULL;
+
+ osc->u.orandphaser.minphaselen = minphaselen;
+ osc->u.orandphaser.maxphaselen = maxphaselen;
+
+ osc->u.orandphaser.count = 0;
+ /* Pick a random phaselen to start with. */
+ osc->u.orandphaser.curphaselen = rand_range(minphaselen, maxphaselen);
+ /* Pick a random phase to start in. */
+ osc->u.orandphaser.curphase = rand_range(0, NUM_PHASES-1);
+
+ return osc;
+}
+
+osc_t *new_osc_linear(stonerview_state *st, osc_t *base, osc_t *diff)
+{
+ osc_t *osc = create_osc(st, otyp_Linear);
+ if (!osc)
+ return NULL;
+
+ osc->u.olinear.base = base;
+ osc->u.olinear.diff = diff;
+
+ return osc;
+}
+
+osc_t *new_osc_buffer(stonerview_state *st, osc_t *val)
+{
+ int ix;
+ osc_t *osc = create_osc(st, otyp_Buffer);
+ if (!osc)
+ return NULL;
+
+ osc->u.obuffer.val = val;
+ osc->u.obuffer.firstel = st->num_els-1;
+
+ /* The last N values are stored in a ring buffer, which we must initialize
+ here. */
+ for (ix=0; ix<st->num_els; ix++) {
+ osc->u.obuffer.el[ix] = osc_get(st, val, 0);
+ }
+
+ return osc;
+}
+
+/* Compute f(i,el) for the current i. */
+int osc_get(stonerview_state *st, osc_t *osc, int el)
+{
+ if (!osc)
+ return 0;
+
+ switch (osc->type) {
+
+ case otyp_Constant:
+ return osc->u.oconstant.val;
+
+ case otyp_Bounce:
+ return osc->u.obounce.val;
+
+ case otyp_Wrap:
+ return osc->u.owrap.val;
+
+ case otyp_VeloWrap:
+ return osc->u.ovelowrap.val;
+
+ case otyp_Linear:
+ return osc_get(st, osc->u.olinear.base, el)
+ + el * osc_get(st, osc->u.olinear.diff, el);
+
+ case otyp_Multiplex: {
+ struct omultiplex_struct *ox = &(osc->u.omultiplex);
+ int sel = osc_get(st, ox->sel, el);
+ return osc_get(st, ox->val[sel % NUM_PHASES], el);
+ }
+
+ case otyp_Phaser: {
+ struct ophaser_struct *ox = &(osc->u.ophaser);
+ return ox->curphase;
+ }
+
+ case otyp_RandPhaser: {
+ struct orandphaser_struct *ox = &(osc->u.orandphaser);
+ return ox->curphase;
+ }
+
+ case otyp_Buffer: {
+ struct obuffer_struct *ox = &(osc->u.obuffer);
+ return ox->el[(ox->firstel + el) % st->num_els];
+ }
+
+ default:
+ return 0;
+ }
+}
+
+/* Increment i. This affects all osc_t objects; we go down the linked list to
+ get them all. */
+void osc_increment(stonerview_state *st)
+{
+ osc_t *osc;
+
+ for (osc = st->oscroot; osc; osc = osc->next) {
+ switch (osc->type) {
+
+ case otyp_Bounce: {
+ struct obounce_struct *ox = &(osc->u.obounce);
+ ox->val += ox->step;
+ if (ox->val < ox->min && ox->step < 0) {
+ ox->step = -(ox->step);
+ ox->val = ox->min + (ox->min - ox->val);
+ }
+ if (ox->val > ox->max && ox->step > 0) {
+ ox->step = -(ox->step);
+ ox->val = ox->max + (ox->max - ox->val);
+ }
+ break;
+ }
+
+ case otyp_Wrap: {
+ struct owrap_struct *ox = &(osc->u.owrap);
+ ox->val += ox->step;
+ if (ox->val < ox->min && ox->step < 0) {
+ ox->val += (ox->max - ox->min);
+ }
+ if (ox->val > ox->max && ox->step > 0) {
+ ox->val -= (ox->max - ox->min);
+ }
+ break;
+ }
+
+ case otyp_VeloWrap: {
+ struct ovelowrap_struct *ox = &(osc->u.ovelowrap);
+ int diff = (ox->max - ox->min);
+ ox->val += osc_get(st, ox->step, 0);
+ while (ox->val < ox->min)
+ ox->val += diff;
+ while (ox->val > ox->max)
+ ox->val -= diff;
+ break;
+ }
+
+ case otyp_Phaser: {
+ struct ophaser_struct *ox = &(osc->u.ophaser);
+ ox->count++;
+ if (ox->count >= ox->phaselen) {
+ ox->count = 0;
+ ox->curphase++;
+ if (ox->curphase >= NUM_PHASES)
+ ox->curphase = 0;
+ }
+ break;
+ }
+
+ case otyp_RandPhaser: {
+ struct orandphaser_struct *ox = &(osc->u.orandphaser);
+ ox->count++;
+ if (ox->count >= ox->curphaselen) {
+ ox->count = 0;
+ ox->curphaselen = rand_range(ox->minphaselen, ox->maxphaselen);
+ ox->curphase++;
+ if (ox->curphase >= NUM_PHASES)
+ ox->curphase = 0;
+ }
+ break;
+ }
+
+ case otyp_Buffer: {
+ struct obuffer_struct *ox = &(osc->u.obuffer);
+ ox->firstel--;
+ if (ox->firstel < 0)
+ ox->firstel += st->num_els;
+ ox->el[ox->firstel] = osc_get(st, ox->val, 0);
+ /* We can assume that ox->val has already been incremented, since it
+ was created first. This is why new objects are put on the end
+ of the linked list... yeah, it's gross. */
+ break;
+ }
+
+ default:
+ break;
+ }
+ }
+}