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