]> icculus.org git repositories - taylor/freespace2.git/blob - src/math/spline.cpp
Initial revision
[taylor/freespace2.git] / src / math / spline.cpp
1 /*
2  * $Logfile: /Freespace2/code/Math/spline.cpp $
3  * $Revision$
4  * $Date$
5  * $Author$
6  *
7  *
8  * $Log$
9  * Revision 1.1  2002/05/03 03:28:09  root
10  * Initial revision
11  *
12  * 
13  * 3     7/08/99 10:53a Dave
14  * New multiplayer interpolation scheme. Not 100% done yet, but still
15  * better than the old way.
16  * 
17  * 2     7/06/99 4:24p Dave
18  * Mid-level checkin. Starting on some potentially cool multiplayer
19  * smoothness crap.
20  *  
21  *
22  * $NoKeywords: $
23  */
24
25 #include "vecmat.h"
26 #include "2d.h"
27 #include "3d.h"
28 #include "alphacolors.h"
29 #include "spline.h"
30
31 // -------------------------------------------------------------------------------------------------
32 // SPLINE DEFINES/VARS
33 //
34
35
36 // -------------------------------------------------------------------------------------------------
37 // SPLINE FUNCTIONS
38 //
39
40 // integer factorial. =o
41 int bez_fact(int n)
42 {
43         int idx;
44         int product = 1;
45
46         // do eet
47         for(idx=1; idx<=n; idx++){
48                 product *= idx;
49         }
50
51         return product;
52 }
53
54 // bez constructor
55 bez_spline::bez_spline()
56 {
57         int idx;
58
59         // zero all points
60         for(idx=0; idx<MAX_BEZ_PTS; idx++){
61                 pts[idx] = vmd_zero_vector;             
62         }
63         num_pts = 0;
64 }
65
66 // bez constructor
67 bez_spline::bez_spline(int _num_pts, vector *_pts[MAX_BEZ_PTS])
68 {
69         bez_set_points(_num_pts, _pts); 
70 }
71
72 // set control points
73 void bez_spline::bez_set_points(int _num_pts, vector *_pts[MAX_BEZ_PTS])
74 {
75         int idx;
76
77         // store the points
78         num_pts = _num_pts;
79         for(idx=0; idx<_num_pts; idx++){
80                 Assert(_pts[idx] != NULL);
81                 if(_pts[idx] != NULL){
82                         pts[idx] = *_pts[idx];
83                 }
84         }
85 }
86
87 // blend function
88 #define COMB(_n, _k)            ( (float)bez_fact(_n) / (float)(bez_fact(_k) * bez_fact(_n - _k)) )
89 float bez_spline::BEZ(int k, int n, float u)
90 {
91         float a = (float)COMB(n, k);
92         float b = (float)pow(u, (float)k);
93         float c = (float)pow(1.0f - u, (float)(n - k));
94
95         return a * b * c;
96 }
97
98 // get a point on the curve
99 void bez_spline::bez_get_point(vector *out, float u)
100 {       
101         int idx;
102         float bez_val;
103
104         Assert(out != NULL);
105         if(out == NULL){
106                 return;
107         }
108
109         // calc
110         out->x = 0.0f;
111         out->y = 0.0f;
112         out->z = 0.0f;
113         for(idx=0; idx<num_pts; idx++){
114                 // bez val
115                 bez_val = BEZ(idx, num_pts-1, u);
116
117                 // x component
118                 out->x += pts[idx].x * bez_val;
119
120                 // y component
121                 out->y += pts[idx].y * bez_val;
122
123                 // z component
124                 out->z += pts[idx].z * bez_val;
125         }
126 }       
127
128 // render a bezier
129 void bez_spline::bez_render(int divs, color *c)
130 {
131         float inc;
132         int idx;
133         vertex a, b;
134         vector pt;
135
136         // bleh
137         if(divs <= 0){
138                 return;
139         }
140         inc = 1.0f / (float)divs;
141
142         // draw in red
143         gr_set_color_fast(c);
144
145         // draw that many divisions
146         bez_get_point(&pt, 0.0f);
147         g3_rotate_vertex(&a, &pt);
148         for(idx=1; idx<=divs; idx++){
149                 // second point
150                 bez_get_point(&pt, (float)idx * inc);
151                 g3_rotate_vertex(&b, &pt);
152
153                 // draw the line
154                 g3_draw_line(&a, &b);
155
156                 // store b
157                 a = b;
158         }
159
160         // draw the control points
161         gr_set_color_fast(&Color_bright_green);
162         for(idx=0; idx<num_pts; idx++){
163                 g3_draw_sphere_ez(&pts[idx], 0.75f);
164         }
165 }
166
167
168 // --------------------------------------------------------------------------
169 // HERMITE splines
170
171 // constructor
172 herm_spline::herm_spline()
173 {
174         int idx;
175
176         // zero all points
177         for(idx=0; idx<MAX_HERM_PTS; idx++){
178                 pts[idx] = vmd_zero_vector;
179                 d_pts[idx] = vmd_zero_vector;
180         }
181         num_pts = 0;
182 }
183
184 // constructor
185 herm_spline::herm_spline(int _num_pts, vector *_pts[MAX_HERM_PTS], vector *_d_pts[MAX_HERM_PTS])
186 {       
187         herm_set_points(_num_pts, _pts, _d_pts);
188 }
189
190 // set the points
191 void herm_spline::herm_set_points(int _num_pts, vector *_pts[MAX_HERM_PTS], vector *_d_pts[MAX_HERM_PTS])
192 {
193         int idx;
194
195         // store the points
196         num_pts = _num_pts;
197         for(idx=0; idx<_num_pts; idx++){
198                 Assert(_pts[idx] != NULL);
199                 if(_pts[idx] != NULL){
200                         pts[idx] = *_pts[idx];
201                 }
202                 Assert(_d_pts[idx] != NULL);
203                 if(_d_pts[idx] != NULL){
204                         d_pts[idx] = *_d_pts[idx];
205                 }
206         }
207 }
208         
209 // get a point on the hermite curve.
210 void herm_spline::herm_get_point(vector *out, float u, int k)
211 {
212         float a = ( (2.0f * u * u * u) - (3.0f * u * u) + 1 );
213         float b = ( (-2.0f * u * u * u) + (3.0f * u * u) );
214         float c = ( (u * u * u) - (2.0f * u * u) + u );
215         float d = ( (u * u * u) - (u * u) );
216
217         vector va;
218         vm_vec_copy_scale(&va, &pts[k], a);
219
220         vector vb;
221         vm_vec_copy_scale(&vb, &pts[k+1], b);
222
223         vector vc;
224         vm_vec_copy_scale(&vc, &d_pts[k], c);
225
226         vector vd;
227         vm_vec_copy_scale(&vd, &d_pts[k+1], d);
228
229         vm_vec_add(out, &va, &vb);
230         vm_vec_add2(out, &vc);
231         vm_vec_add2(out, &vd);
232 }
233
234 // the derivative of a point on the hermite curve
235 void herm_spline::herm_get_deriv(vector *deriv, float u, int k)
236 {
237         float a = ( (6.0f * u * u) - (6.0f * u) );
238         float b = ( (-6.0f * u * u) + (6.0f * u) );
239         float c = ( (3.0f * u * u) - (4.0f * u) + 1 );
240         float d = ( (3.0f * u * u) - (2.0f * u) );
241
242         vector va;
243         vm_vec_copy_scale(&va, &pts[k], a);
244
245         vector vb;
246         vm_vec_copy_scale(&vb, &pts[k+1], b);
247
248         vector vc;
249         vm_vec_copy_scale(&vc, &d_pts[k], c);
250
251         vector vd;
252         vm_vec_copy_scale(&vd, &d_pts[k+1], d);
253
254         vm_vec_add(deriv, &va, &vb);
255         vm_vec_add2(deriv, &vc);
256         vm_vec_add2(deriv, &vd);
257 }
258
259 // render a bezier
260 void herm_spline::herm_render(int divs, color *clc)
261 {
262         int idx;
263         int s_idx;
264         float inc = 1.0f / (float)divs;
265
266         vertex a, b, c;
267         vector pt, d_pt;
268
269         // draw in red
270         gr_set_color_fast(clc);
271
272         // render each section
273         for(idx=0; idx<num_pts-1; idx++){
274                 // render this piece
275                 herm_get_point(&pt, 0.0f, idx);         
276                 g3_rotate_vertex(&a, &pt);
277                 
278                 // draw the deriv
279                 herm_get_deriv(&d_pt, 0.0f, idx);
280                 vm_vec_add2(&d_pt, &pt);
281                 g3_rotate_vertex(&c, &d_pt);
282                 g3_draw_line(&a, &c);
283
284                 for(s_idx=1; s_idx<divs * 2; s_idx++){
285                         // second point
286                         herm_get_point(&pt, (float)s_idx * inc, idx);                   
287                         
288                         // 2nd point on the line
289                         g3_rotate_vertex(&b, &pt);
290
291                         // draw the line
292                         g3_draw_line(&a, &b);
293
294                         // draw the deriv line
295                         herm_get_deriv(&d_pt, (float)s_idx * inc, idx);                 
296                         vm_vec_add2(&d_pt, &pt);
297                         g3_rotate_vertex(&c, &d_pt);
298                         g3_draw_line(&b, &c);
299
300                         // store b
301                         a = b;
302                 }               
303         }       
304
305         // draw the control points
306         gr_set_color_fast(&Color_bright_green);
307         for(idx=0; idx<num_pts; idx++){
308                 g3_draw_sphere_ez(&pts[idx], 0.75f);
309         }
310 }