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