1 /*
2 ======================================================================
3 interp.c
4 
5 Interpolation (and extrapolation) of LightWave envelopes.
6 
7 Ernie Wright  16 Nov 00
8 
9 The LightWave plug-in SDK provides functions for evaluating envelopes
10 and channels at arbitrary times, which is what plug-ins should use.
11 This code shows how to evaluate envelopes in standalone programs.
12 ====================================================================== */
13 
14 #include "xr_envelope.h"
15 #include "xr_math.h"
16 
17 using namespace xray_re;
18 
range(float v,float lo,float hi,int * i=0)19 static float range(float v, float lo, float hi, int* i = 0)
20 {
21 	float r = hi - lo;
22 	if (r == 0) {
23 		if (i)
24 			*i = 0;
25 		return lo;
26 	}
27 	float v2 = lo + v - r*std::floor((v - lo)/r);
28 	if (i)
29 		*i = -(int)((v2 - v)/r + (v2 > v ? 0.5 : -0.5));
30 	return v2;
31 }
32 
hermite(float t,float * h1,float * h2,float * h3,float * h4)33 static void hermite(float t, float* h1, float* h2, float* h3, float* h4)
34 {
35 	float t2 = t*t, t3 = t2*t;
36 	*h2 = 3.f*t2 - t3 - t3;
37 	*h1 = 1.f - *h2;
38 	*h4 = t3 - t2;
39 	*h3 = *h4 - t2 + t;
40 }
41 
bezier(float x0,float x1,float x2,float x3,float t)42 static float bezier(float x0, float x1, float x2, float x3, float t)
43 {
44 	float t2 = t*t, t3 = t2*t;
45 
46 	float c = 3.f*(x1 - x0);
47 	float b = 3.f*(x2 - x1) - c;
48 	float a = x3 - x0 - c - b;
49 
50 	return a*t3 + b*t2 + c*t + x0;
51 }
52 
bez2_time(float x0,float x1,float x2,float x3,float time,float * t0,float * t1)53 static float bez2_time(float x0, float x1, float x2, float x3, float time,
54 		float* t0, float* t1)
55 {
56 	float t = *t0 + (*t1 - *t0)*0.5f;
57 	float v = bezier(x0, x1, x2, x3, t);
58 	if (std::abs(time - v) > 1e-4f) {
59 		if (v > time)
60 			*t1 = t;
61 		else
62 			*t0 = t;
63 		return bez2_time(x0, x1, x2, x3, time, t0, t1);
64 	} else {
65 		return t;
66 	}
67 }
68 
bez2(const xr_key * key0,const xr_key * key1,float time)69 static float bez2(const xr_key* key0, const xr_key* key1, float time)
70 {
71 	float x = (key0->shape == xr_key::SHAPE_BEZ2) ?
72 			key0->time + key0->param[2] :
73 			key0->time + (key1->time - key0->time)/3.f;
74 	float t0 = 0.f, t1 = 1.f;
75 	float t = bez2_time(key0->time, x, key1->time + key1->param[0], key1->time, time, &t0, &t1);
76 
77 	float y = (key0->shape == xr_key::SHAPE_BEZ2) ?
78 			key0->value + key0->param[3] :
79 			key0->value + key0->param[1]/3.f;
80 	return bezier(key0->value, y, key1->param[1] + key1->value, key1->value, t);
81 }
82 
outgoing(const xr_key * key0_prev,const xr_key * key0,const xr_key * key1)83 static float outgoing(const xr_key* key0_prev, const xr_key* key0, const xr_key* key1)
84 {
85 	float a, b, d, t, out;
86 	switch (key0->shape) {
87 	case xr_key::SHAPE_TCB:
88 		a = (1.f - key0->tension)*(1.f + key0->continuity)*(1.f + key0->bias);
89 		b = (1.f - key0->tension)*(1.f - key0->continuity)*(1.f - key0->bias);
90 		d = key1->value - key0->value;
91 		if (key0_prev) {
92 			t = (key1->time - key0->time)/(key1->time - key0_prev->time);
93 			out = t*(a*(key0->value - key0_prev->value) + b*d);
94 		} else {
95 			out = b*d;
96 		}
97 		break;
98 
99 	case xr_key::SHAPE_LINE:
100 		d = key1->value - key0->value;
101 		if (key0_prev) {
102 			t = (key1->time - key0->time)/(key1->time - key0_prev->time);
103 			out = t*(key0->value - key0_prev->value + d);
104 		} else {
105 			out = d;
106 		}
107 		break;
108 
109 	case xr_key::SHAPE_BEZI:
110 	case xr_key::SHAPE_HERM:
111 		out = key0->param[1];
112 		if (key0_prev)
113 			out *= (key1->time - key0->time)/(key1->time - key0_prev->time);
114 		break;
115 
116 	case xr_key::SHAPE_BEZ2:
117 		out = key0->param[3]*(key1->time - key0->time);
118 		if (std::abs(key0->param[2]) > 1e-5f)
119 			out /= key0->param[2];
120 		else
121 			out *= 1e+5f;
122 		break;
123 
124 	case xr_key::SHAPE_STEP:
125 	default:
126 		out = 0.f;
127 		break;
128 	}
129 	return out;
130 }
131 
incoming(const xr_key * key0,const xr_key * key1,const xr_key * key1_next)132 static float incoming(const xr_key* key0, const xr_key* key1, const xr_key* key1_next)
133 {
134 	float a, b, d, t, in;
135 	switch (key1->shape) {
136 	case xr_key::SHAPE_LINE:
137 		d = key1->value - key0->value;
138 		if (key1_next) {
139 			t = (key1->time - key0->time)/(key1_next->time - key0->time);
140 			in = t*(key1_next->value - key1->value + d);
141 		} else {
142 			in = d;
143 		}
144 		break;
145 
146 	case xr_key::SHAPE_TCB:
147 		a = (1.f - key1->tension)*(1.f - key1->continuity)*(1.f + key1->bias);
148 		b = (1.f - key1->tension)*(1.f + key1->continuity)*(1.f - key1->bias);
149 		d = key1->value - key0->value;
150 		if (key1_next) {
151 			t = (key1->time - key0->time)/(key1_next->time - key0->time);
152 			in = t*(b*(key1_next->value - key1->value) + a*d);
153 		} else {
154 			in = a*d;
155 		}
156 		break;
157 
158 	case xr_key::SHAPE_BEZI:
159 	case xr_key::SHAPE_HERM:
160 		in = key1->param[0];
161 		if (key1_next)
162 			in *= (key1->time - key0->time)/(key1_next->time - key0->time);
163 		break;
164 
165 	case xr_key::SHAPE_BEZ2:
166 		in = key1->param[1]*(key1->time - key0->time);
167 		if (std::abs(key1->param[0]) > 1e-5f)
168 			in /= key1->param[0];
169 		else
170 			in *= 1e+5f;
171 		break;
172 
173 	case xr_key::SHAPE_STEP:
174 	default:
175 		in = 0.f;
176 		break;
177 	}
178 	return in;
179 }
180 
evaluate(float time) const181 float xr_envelope::evaluate(float time) const
182 {
183 	if (m_keys.empty())
184 		return 0.f;
185 
186 	if (m_keys.size() == 1)
187 		return m_keys.front()->value;
188 
189 	int noff;
190 	float offset = 0;
191 
192 	xr_key* skey = m_keys.front();
193 	xr_key* ekey = m_keys.back();
194 	if (time < skey->time) {
195 		switch (m_behaviour0) {
196 		case BEH_RESET:
197 			return 0.f;
198 
199 		case BEH_CONSTANT:
200 			return skey->value;
201 
202 		case BEH_REPEAT:
203 			time = range(time, skey->time, ekey->time);
204 			break;
205 
206 		case BEH_OSCILLATE:
207 			time = range(time, skey->time, ekey->time, &noff);
208 			if (noff % 2)
209 				time = ekey->time - skey->time - time;
210 			break;
211 
212 		case BEH_OFFSET:
213 			time = range(time, skey->time, ekey->time, &noff);
214 			offset = noff*(ekey->value - skey->value);
215 			break;
216 
217 		case BEH_LINEAR: {
218 			xr_key* next = m_keys[1];
219 			return outgoing(0, skey, next)/(next->time - skey->time)*(time - skey->time) + skey->value;
220 			}
221 		}
222 	} else if (ekey->time < time) {
223 		switch (m_behaviour1) {
224 		case BEH_RESET:
225 			return 0.f;
226 
227 		case BEH_CONSTANT:
228 			return ekey->value;
229 
230 		case BEH_REPEAT:
231 			time = range(time, skey->time, ekey->time);
232 			break;
233 
234 		case BEH_OSCILLATE:
235 			time = range(time, skey->time, ekey->time, &noff);
236 			if (noff % 2)
237 				time = ekey->time - skey->time - time;
238 			break;
239 
240 		case BEH_OFFSET:
241 			time = range(time, skey->time, ekey->time, &noff);
242 			offset = noff*(ekey->value - skey->value);
243 			break;
244 
245 		case BEH_LINEAR: {
246 			xr_key* prev = *(m_keys.end() - 2);
247 			return incoming(prev, ekey, 0)/(ekey->time - prev->time)*(time - ekey->time) + ekey->value;
248 			}
249 		}
250 	}
251 
252 	xr_key_vec_cit it = m_keys.begin() + 1;
253 	// FIXME: use bisection
254 	while ((*it)->time < time)
255 		++it;
256 	xr_key* key0 = *(it - 1);
257 	xr_key* key1 = *it;
258 
259 	if (time == key0->time)
260 		return key0->value + offset;
261 	else if (time == key1->time)
262 		return key1->value + offset;
263 
264 	float t = (time - key0->time)/(key1->time - key0->time);
265 
266 	switch (key1->shape) {
267 	case xr_key::SHAPE_TCB:
268 	case xr_key::SHAPE_BEZI:
269 	case xr_key::SHAPE_HERM: {
270 		float out = outgoing(key0 == skey ? 0 : *(it - 2), key0, key1);
271 		float in = incoming(key0, key1, key1 == ekey ? 0 : *(it + 1));
272 		float h1, h2, h3, h4;
273 		hermite(t, &h1, &h2, &h3, &h4);
274 		return h1*key0->value + h2*key1->value + h3*out + h4*in + offset;
275 	}
276 	case xr_key::SHAPE_BEZ2:
277 		return bez2(key0, key1, time) + offset;
278 
279 	case xr_key::SHAPE_LINE:
280 		return key0->value + t*(key1->value - key0->value) + offset;
281 
282 	case xr_key::SHAPE_STEP:
283 		return key0->value + offset;
284 
285 	default:
286 		return offset;
287 	}
288 }
289