1 /* StonerView: An eccentric visual toy.
2 Copyright 1998-2001 by Andrew Plotkin (erkyrath@eblong.com)
4 Permission to use, copy, modify, distribute, and sell this software and its
5 documentation for any purpose is hereby granted without fee, provided that
6 the above copyright notice appear in all copies and that both that
7 copyright notice and this permission notice appear in supporting
8 documentation. No representations are made about the suitability of this
9 software for any purpose. It is provided "as is" without express or
13 #ifndef __STONERVIEW_OSC_H__
14 #define __STONERVIEW_OSC_H__
16 /* This defines the osc_t object, which generates a stream of
17 numbers. It is the heart of the StonerSound/StonerView engine.
19 The idea is simple; an osc_t represents some function f(), which
20 can be evaluated to generate an infinite stream of integers (f(0),
21 f(1), f(2), f(3)...). Some of these functions are defined in
22 terms of other osc_t functions: f(i) = g(h(i)) or some such thing.
24 To simplify the code, we don't try to calculate f(i) for any
25 arbitrary i. Instead, we start with i=0. Calling osc_get(f)
26 returns f(0) for all osc_t's in the system. When we're ready, we
27 call osc_increment(), which advances every osc_t to i=1;
28 thereafter, calling osc_get(f) returns f(1). When you call
29 osc_increment() again, you get f(2). And so on. You can't go
30 backwards, or move forwards more than 1 at a time, or move some
31 osc_t's without moving others. This is a very restricted model, but
32 it's exactly what's needed for this system.
34 Now, there's an additional complication. To get the rippling
35 effect, we don't pull out single values, but *sets* of N elements
36 at a time. (N is defined by NUM_ELS below.) So f(i) is really an
37 ordered N-tuple (f(i,0), f(i,1), f(i,2), f(i,3), f(i,4)). And f()
38 generates an infinite stream of these N-tuples. The osc_get() call
39 really has two parameters; you call osc_get(f, n) to find the n'th
40 element of the current N-tuple. Remember, n must be between 0 and
43 (Do *not* try to get an infinite stream f(i) by calling
44 osc_get(f, i) for i ranging to infinity! Use osc_increment() to
45 advance to the next N-tuple in the stream.)
48 #define NUM_ELS (40) /* Forty polygons at a time. */
50 #define NUM_PHASES (4) /* Some of the osc functions switch between P
51 alternatives. We arbitrarily choose P=4. */
53 /* Here are the functions which are available.
54 Constant: f(i,n) = k. Always the same value. Very simple.
55 Wrap: f(i,n) slides up or down as i increases. There's a minimum and maximum
56 value, and a step. When the current value reaches the min or max, it jumps
57 to the other end and keeps moving the same direction.
58 Bounce: f(i,n) slides up and down as i increases. There's a minimum and
59 maximum value, and a step. When the current value reaches the min or max,
60 the step is flipped to move the other way.
61 Phaser: f(i,n) = floor(i / phaselen) modulo 4. That is, it generates
62 phaselen 0 values, and then phaselen 1 values, then phaselen 2 values,
63 then phaselen 3 values, then back to 0. (Phaselen is a parameter you
64 supply when you create the phaser.) As you see, this is much the same as
65 the Wrap function, with a minimum of 0, a maximum of 3, and a step of
66 1/phaselen. But since this code uses integer math, fractional steps
67 aren't possible; it's easier to write a separate function.
68 RandPhaser: The same as Phaser, but the phaselen isn't fixed. It varies
69 randomly between a minimum and maximum value you supply.
70 Multiplex: There are five subsidiary functions within a multiplex function:
71 g0, g1, g2, g3, and a selector function s. Then:
72 f(i,n) = gX(i,n), where X = s(i,n). (Obviously s must generate only values
73 in the range 0 to 3. This is what the phaser functions are designed for,
74 but you can use anything.)
75 Linear: There are two subsidiary functions within this, a and b. Then:
76 f(i,n) = a(i,n) + n*b(i,n). This is an easy way to make an N-tuple that
77 forms a linear sequence, such as (41, 43, 45, 47, 49).
78 Buffer: This takes a subsidiary function g, and computes:
79 f(i,n) = g(i-n,0). That is, the 0th element of the N-tuple is the
80 *current* value of g; the 1st element is the *previous* value of g; the
81 2nd element is the second-to-last value, and so on back in time. This
82 is a weird idea, but it causes exactly the rippling-change effect that
85 Note that Buffer only looks up g(i,0) -- it only uses the 0th elements of
86 the N-tuples that g generates. This saves time and memory, but it means
87 that certain things don't work. For example, if you try to build
88 Buffer(Linear(A,B)), B will have no effect, because Linear computes
89 a(i,n) + n*b(i,n), and inside the Buffer, n is always zero. On the other
90 hand, Linear(Buffer(A),Buffer(B)) works fine, and is probably what you
92 Similarly, Buffer(Buffer(A)) is the same as Buffer(A). Proof left as an
96 #define otyp_Constant (1)
97 #define otyp_Bounce (2)
99 #define otyp_Phaser (4)
100 #define otyp_RandPhaser (5)
101 #define otyp_VeloWrap (7)
102 #define otyp_Linear (6)
103 #define otyp_Buffer (8)
104 #define otyp_Multiplex (9)
106 /* The osc_t structure itself. */
107 typedef struct osc_struct {
108 int type; /* An otyp_* constant. */
110 struct osc_struct *next; /* osc.c uses this to maintain a private linked list
111 of all osc_t objects created. */
113 /* Union of the data used by all the possible osc_t functions. */
118 struct owrap_struct {
122 struct obounce_struct {
126 struct omultiplex_struct {
127 struct osc_struct *sel;
128 struct osc_struct *val[NUM_PHASES];
130 struct ophaser_struct {
135 struct orandphaser_struct {
136 int minphaselen, maxphaselen;
141 struct ovelowrap_struct {
143 struct osc_struct *step;
146 struct olinear_struct {
147 struct osc_struct *base;
148 struct osc_struct *diff;
150 struct obuffer_struct {
151 struct osc_struct *val;
158 extern osc_t *new_osc_constant(stonerview_state *, int val);
159 extern osc_t *new_osc_bounce(stonerview_state *, int min, int max, int step);
160 extern osc_t *new_osc_wrap(stonerview_state *, int min, int max, int step);
161 extern osc_t *new_osc_phaser(stonerview_state *, int phaselen);
162 extern osc_t *new_osc_randphaser(stonerview_state *,
163 int minphaselen, int maxphaselen);
164 extern osc_t *new_osc_velowrap(stonerview_state *,
165 int min, int max, osc_t *step);
166 extern osc_t *new_osc_linear(stonerview_state *, osc_t *base, osc_t *diff);
167 extern osc_t *new_osc_buffer(stonerview_state *st, osc_t *val);
168 extern osc_t *new_osc_multiplex(stonerview_state *,
169 osc_t *sel, osc_t *ox0, osc_t *ox1,
170 osc_t *ox2, osc_t *ox3);
172 extern int osc_get(stonerview_state *, osc_t *osc, int el);
173 extern void osc_increment(stonerview_state *);
175 #endif /* __STONERVIEW_OSC_H__ */