diff options
Diffstat (limited to 'hacks/glx/stonerview-osc.h')
-rw-r--r-- | hacks/glx/stonerview-osc.h | 175 |
1 files changed, 175 insertions, 0 deletions
diff --git a/hacks/glx/stonerview-osc.h b/hacks/glx/stonerview-osc.h new file mode 100644 index 0000000..b8c0778 --- /dev/null +++ b/hacks/glx/stonerview-osc.h @@ -0,0 +1,175 @@ +/* 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. +*/ + +#ifndef __STONERVIEW_OSC_H__ +#define __STONERVIEW_OSC_H__ + +/* This defines the osc_t object, which generates a stream of + numbers. It is the heart of the StonerSound/StonerView engine. + + The idea is simple; an osc_t represents some function f(), which + can be evaluated to generate an infinite stream of integers (f(0), + f(1), f(2), f(3)...). Some of these functions are defined in + terms of other osc_t functions: f(i) = g(h(i)) or some such thing. + + To simplify the code, we don't try to calculate f(i) for any + arbitrary i. Instead, we start with i=0. Calling osc_get(f) + returns f(0) for all osc_t's in the system. When we're ready, we + call osc_increment(), which advances every osc_t to i=1; + thereafter, calling osc_get(f) returns f(1). When you call + osc_increment() again, you get f(2). And so on. You can't go + backwards, or move forwards more than 1 at a time, or move some + osc_t's without moving others. This is a very restricted model, but + it's exactly what's needed for this system. + + Now, there's an additional complication. To get the rippling + effect, we don't pull out single values, but *sets* of N elements + at a time. (N is defined by NUM_ELS below.) So f(i) is really an + ordered N-tuple (f(i,0), f(i,1), f(i,2), f(i,3), f(i,4)). And f() + generates an infinite stream of these N-tuples. The osc_get() call + really has two parameters; you call osc_get(f, n) to find the n'th + element of the current N-tuple. Remember, n must be between 0 and + n-1. + + (Do *not* try to get an infinite stream f(i) by calling + osc_get(f, i) for i ranging to infinity! Use osc_increment() to + advance to the next N-tuple in the stream.) +*/ + +#define NUM_ELS (40) /* Forty polygons at a time. */ + +#define NUM_PHASES (4) /* Some of the osc functions switch between P + alternatives. We arbitrarily choose P=4. */ + +/* Here are the functions which are available. + Constant: f(i,n) = k. Always the same value. Very simple. + Wrap: f(i,n) slides up or down as i increases. There's a minimum and maximum + value, and a step. When the current value reaches the min or max, it jumps + to the other end and keeps moving the same direction. + Bounce: f(i,n) slides up and down as i increases. There's a minimum and + maximum value, and a step. When the current value reaches the min or max, + the step is flipped to move the other way. + Phaser: f(i,n) = floor(i / phaselen) modulo 4. That is, it generates + phaselen 0 values, and then phaselen 1 values, then phaselen 2 values, + then phaselen 3 values, then back to 0. (Phaselen is a parameter you + supply when you create the phaser.) As you see, this is much the same as + the Wrap function, with a minimum of 0, a maximum of 3, and a step of + 1/phaselen. But since this code uses integer math, fractional steps + aren't possible; it's easier to write a separate function. + RandPhaser: The same as Phaser, but the phaselen isn't fixed. It varies + randomly between a minimum and maximum value you supply. + Multiplex: There are five subsidiary functions within a multiplex function: + g0, g1, g2, g3, and a selector function s. Then: + f(i,n) = gX(i,n), where X = s(i,n). (Obviously s must generate only values + in the range 0 to 3. This is what the phaser functions are designed for, + but you can use anything.) + Linear: There are two subsidiary functions within this, a and b. Then: + f(i,n) = a(i,n) + n*b(i,n). This is an easy way to make an N-tuple that + forms a linear sequence, such as (41, 43, 45, 47, 49). + Buffer: This takes a subsidiary function g, and computes: + f(i,n) = g(i-n,0). That is, the 0th element of the N-tuple is the + *current* value of g; the 1st element is the *previous* value of g; the + 2nd element is the second-to-last value, and so on back in time. This + is a weird idea, but it causes exactly the rippling-change effect that + we want. + + Note that Buffer only looks up g(i,0) -- it only uses the 0th elements of + the N-tuples that g generates. This saves time and memory, but it means + that certain things don't work. For example, if you try to build + Buffer(Linear(A,B)), B will have no effect, because Linear computes + a(i,n) + n*b(i,n), and inside the Buffer, n is always zero. On the other + hand, Linear(Buffer(A),Buffer(B)) works fine, and is probably what you + wanted anyway. + Similarly, Buffer(Buffer(A)) is the same as Buffer(A). Proof left as an + exercise. +*/ + +#define otyp_Constant (1) +#define otyp_Bounce (2) +#define otyp_Wrap (3) +#define otyp_Phaser (4) +#define otyp_RandPhaser (5) +#define otyp_VeloWrap (7) +#define otyp_Linear (6) +#define otyp_Buffer (8) +#define otyp_Multiplex (9) + +/* The osc_t structure itself. */ +typedef struct osc_struct { + int type; /* An otyp_* constant. */ + + struct osc_struct *next; /* osc.c uses this to maintain a private linked list + of all osc_t objects created. */ + + /* Union of the data used by all the possible osc_t functions. */ + union { + struct { + int val; + } oconstant; + struct owrap_struct { + int min, max, step; + int val; + } owrap; + struct obounce_struct { + int min, max, step; + int val; + } obounce; + struct omultiplex_struct { + struct osc_struct *sel; + struct osc_struct *val[NUM_PHASES]; + } omultiplex; + struct ophaser_struct { + int phaselen; + int count; + int curphase; + } ophaser; + struct orandphaser_struct { + int minphaselen, maxphaselen; + int count; + int curphaselen; + int curphase; + } orandphaser; + struct ovelowrap_struct { + int min, max; + struct osc_struct *step; + int val; + } ovelowrap; + struct olinear_struct { + struct osc_struct *base; + struct osc_struct *diff; + } olinear; + struct obuffer_struct { + struct osc_struct *val; + int firstel; + int el[NUM_ELS]; + } obuffer; + } u; +} osc_t; + +extern osc_t *new_osc_constant(stonerview_state *, int val); +extern osc_t *new_osc_bounce(stonerview_state *, int min, int max, int step); +extern osc_t *new_osc_wrap(stonerview_state *, int min, int max, int step); +extern osc_t *new_osc_phaser(stonerview_state *, int phaselen); +extern osc_t *new_osc_randphaser(stonerview_state *, + int minphaselen, int maxphaselen); +extern osc_t *new_osc_velowrap(stonerview_state *, + int min, int max, osc_t *step); +extern osc_t *new_osc_linear(stonerview_state *, osc_t *base, osc_t *diff); +extern osc_t *new_osc_buffer(stonerview_state *st, osc_t *val); +extern osc_t *new_osc_multiplex(stonerview_state *, + osc_t *sel, osc_t *ox0, osc_t *ox1, + osc_t *ox2, osc_t *ox3); + +extern int osc_get(stonerview_state *, osc_t *osc, int el); +extern void osc_increment(stonerview_state *); + +#endif /* __STONERVIEW_OSC_H__ */ |