Richard Boegli's CnC_Generals_Zero_Hour Fork WIP
This is documentation of Richard Boegil's Zero Hour Fork
 
Loading...
Searching...
No Matches
hermitespline.cpp
Go to the documentation of this file.
1/*
2** Command & Conquer Generals Zero Hour(tm)
3** Copyright 2025 Electronic Arts Inc.
4**
5** This program is free software: you can redistribute it and/or modify
6** it under the terms of the GNU General Public License as published by
7** the Free Software Foundation, either version 3 of the License, or
8** (at your option) any later version.
9**
10** This program is distributed in the hope that it will be useful,
11** but WITHOUT ANY WARRANTY; without even the implied warranty of
12** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13** GNU General Public License for more details.
14**
15** You should have received a copy of the GNU General Public License
16** along with this program. If not, see <http://www.gnu.org/licenses/>.
17*/
18
19/***********************************************************************************************
20 *** C O N F I D E N T I A L --- W E S T W O O D S T U D I O S ***
21 ***********************************************************************************************
22 * *
23 * Project Name : WWMath *
24 * *
25 * $Archive:: /VSS_Sync/wwmath/hermitespline.cpp $*
26 * *
27 * Author:: Greg Hjelstrom *
28 * *
29 * $Modtime:: 6/13/01 2:18p $*
30 * *
31 * $Revision:: 11 $*
32 * *
33 *---------------------------------------------------------------------------------------------*
34 * Functions: *
35 * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
36
37
38#include "hermitespline.h"
39#include "wwmathids.h"
40#include "persistfactory.h"
41#include "wwhack.h"
42
43
44/*
45** Force-Link this module because the linker can't detect that we actually need it...
46*/
47DECLARE_FORCE_LINK(hermitespline);
48
49/*
50** Save-Load stuff
51*/
54
55enum
56{
57 // ID's used by HermiteSpline3D
60
61 // ID's used by HermiteSpline1D
64};
65
66
67/*
68** Hermite Spline
69*/
71{
72 //
73 // This is included for completeness only, it basically
74 // implements the default bitwise copy operator.
75 //
77 Tangents = that.Tangents;
79 return (*this);
80}
81
83{
84 if (onoff != IsLooping) {
86 TangentsDirty = true;
87 }
88}
89
90void HermiteSpline3DClass::Evaluate(float time,Vector3 * set_val)
91{
92 // if we're outside the range, return the start or end...
93 if (time < Keys[0].Time) {
94 *set_val = Keys[0].Point;
95 return;
96 }
97
98 if (time > Keys[Keys.Count() - 1].Time) {
99 *set_val = Keys[Keys.Count() - 1].Point;
100 return;
101 }
102
103 // if the tangents are marked dirty, give derived classes a chance to recompute them
104 if (TangentsDirty) {
106 }
107
108 // ok find the segment
109 int i0,i1;
110 float t;
111 Find_Interval(time,&i0,&i1,&t);
112
113 float t2 = t*t;
114 float t3 = t2*t;
115
116 // hermite basis functions:
117 float h0 = 2*t3 - 3*t2 + 1;
118 float h1 = -2*t3 + 3*t2;
119 float h2 = t3 - 2*t2 + t;
120 float h3 = t3 - t2;
121
122 set_val->X = h0*Keys[i0].Point.X + h1*Keys[i1].Point.X +
123 h2*Tangents[i0].OutTangent.X + h3*Tangents[i1].InTangent.X;
124
125 set_val->Y = h0*Keys[i0].Point.Y + h1*Keys[i1].Point.Y +
126 h2*Tangents[i0].OutTangent.Y + h3*Tangents[i1].InTangent.Y;
127
128 set_val->Z = h0*Keys[i0].Point.Z + h1*Keys[i1].Point.Z +
129 h2*Tangents[i0].OutTangent.Z + h3*Tangents[i1].InTangent.Z;
130}
131
133{
134 // if we're outside the range, return the value for the start or end...
135 float min_time = Keys[0].Time;
136 float max_time = Keys[Keys.Count() - 1].Time;
137 time = MAX(time, min_time);
138 time = MIN(time, max_time);
139
140 // if the tangents are marked dirty, give derived classes a chance to recompute them
141 if (TangentsDirty) {
143 }
144
145 // ok find the segment
146 int i0,i1;
147 float t;
148 Find_Interval(time,&i0,&i1,&t);
149
150 float t2 = t*t;
151
152 // derivatives of hermite basis functions:
153 float dh0 = 6*t2 - 6*t;
154 float dh1 = -6*t2 + 6*t;
155 float dh2 = 3*t2 - 4*t + 1;
156 float dh3 = 3*t2 - 2*t;
157
158 set_val->X = dh0*Keys[i0].Point.X + dh1*Keys[i1].Point.X +
159 dh2*Tangents[i0].OutTangent.X + dh3*Tangents[i1].InTangent.X;
160
161 set_val->Y = dh0*Keys[i0].Point.Y + dh1*Keys[i1].Point.Y +
162 dh2*Tangents[i0].OutTangent.Y + dh3*Tangents[i1].InTangent.Y;
163
164 set_val->Z = dh0*Keys[i0].Point.Z + dh1*Keys[i1].Point.Z +
165 dh2*Tangents[i0].OutTangent.Z + dh3*Tangents[i1].InTangent.Z;
166}
167
168void HermiteSpline3DClass::Set_Key(int i,const Vector3 & point)
169{
170 Curve3DClass::Set_Key(i,point);
171 TangentsDirty = true;
172}
173
174int HermiteSpline3DClass::Add_Key(const Vector3 & point,float t)
175{
176 int index = Curve3DClass::Add_Key(point,t);
177 TangentsDirty = true;
178 TangentsClass tan;
179 tan.InTangent.Set(0,0,0);
180 tan.OutTangent.Set(0,0,0);
181 Tangents.Insert(index,tan);
182 return index;
183}
184
186{
187 Tangents.Delete(i);
189 TangentsDirty = true;
190}
191
193{
194 Tangents.Clear();
196 TangentsDirty = true;
197}
198
199void HermiteSpline3DClass::Set_Tangents(int i,const Vector3 & in_tan,const Vector3 & out_tan)
200{
201 assert(i>=0);
202 assert(i<Keys.Count());
203 Tangents[i].InTangent = in_tan;
204 Tangents[i].OutTangent = out_tan;
205}
206
208{
209 assert(i>=0);
210 assert(i<Keys.Count());
211 *set_in = Tangents[i].InTangent;
212 *set_out = Tangents[i].OutTangent;
213}
214
219
221{
223 Curve3DClass::Save(csave);
224 csave.End_Chunk();
225
227 for (int i=0; i<Tangents.Count(); i++) {
228 csave.Write(&(Tangents[i].InTangent),sizeof(Tangents[i].InTangent));
229 csave.Write(&(Tangents[i].OutTangent),sizeof(Tangents[i].OutTangent));
230 }
231 csave.End_Chunk();
232 return true;
233}
234
236{
237 int i;
238 TangentsClass newtangent;
239
240 // reset the array of tangents
241 Tangents.Delete_All();
242
243 // read in the chunks
244 while (cload.Open_Chunk()) {
245
246 switch(cload.Cur_Chunk_ID())
247 {
249 Curve3DClass::Load(cload);
250 break;
251
253 for (i=0; i<Keys.Count(); i++) {
254 cload.Read(&(newtangent.InTangent),sizeof(newtangent.InTangent));
255 cload.Read(&(newtangent.OutTangent),sizeof(newtangent.OutTangent));
256 Tangents.Add(newtangent);
257 }
258 break;
259
260 default:
261 WWDEBUG_SAY(("Unhandled Chunk: 0x%X File: %s Line: %d\r\n",__FILE__,__LINE__));
262 break;
263 }
264 cload.Close_Chunk();
265 }
266
267 WWASSERT(Keys.Count() == Tangents.Count());
268 return true;
269}
270
271
272
273
274/*
275** 1-Dimensional Hermite Spline
276*/
278{
279 if (onoff != IsLooping) {
281 TangentsDirty = true;
282 }
283}
284
285void HermiteSpline1DClass::Evaluate(float time,float * set_val)
286{
287 if (Keys.Count() == 1)
288 {
289 *set_val = Keys[0].Point;
290 return;
291 }
292
293 if (!IsLooping)
294 {
295 // if we're outside the range, return the start or end...
296 if (time < Keys[0].Time) {
297 *set_val = Keys[0].Point;
298 return;
299 }
300
301 if (time > Keys[Keys.Count() - 1].Time) {
302 *set_val = Keys[Keys.Count() - 1].Point;
303 return;
304 }
305 }
306
307 // if the tangents are marked dirty, give derived classes a chance to recompute them
308 if (TangentsDirty) {
310 }
311
312 // ok find the segment
313 int i0,i1;
314 float t;
315 Find_Interval(time,&i0,&i1,&t);
316
317 float t2 = t*t;
318 float t3 = t2*t;
319
320 // hermite basis functions:
321 float h0 = 2*t3 - 3*t2 + 1;
322 float h1 = -2*t3 + 3*t2;
323 float h2 = t3 - 2*t2 + t;
324 float h3 = t3 - t2;
325
326 *set_val = h0*Keys[i0].Point + h1*Keys[i1].Point +
327 h2*Tangents[i0].OutTangent + h3*Tangents[i1].InTangent;
328}
329
330void HermiteSpline1DClass::Set_Key(int i,float point,unsigned int extra)
331{
332 Curve1DClass::Set_Key(i,point,extra);
333 TangentsDirty = true;
334}
335
336int HermiteSpline1DClass::Add_Key(float point,float t,unsigned int extra)
337{
338 int index = Curve1DClass::Add_Key(point,t,extra);
339 TangentsDirty = true;
340 TangentsClass tan;
341 tan.InTangent = 0.0f;
342 tan.OutTangent = 0.0f;
343 Tangents.Insert(index,tan);
344 return index;
345}
346
348{
349 Tangents.Delete(i);
351 TangentsDirty = true;
352}
353
355{
356 Tangents.Clear();
358 TangentsDirty = true;
359}
360
361void HermiteSpline1DClass::Set_Tangents(int i,float in_tan,float out_tan)
362{
363 assert(i>=0);
364 assert(i<Keys.Count());
365 Tangents[i].InTangent = in_tan;
366 Tangents[i].OutTangent = out_tan;
367}
368
369void HermiteSpline1DClass::Get_Tangents(int i,float * set_in,float * set_out)
370{
371 assert(i>=0);
372 assert(i<Keys.Count());
373 *set_in = Tangents[i].InTangent;
374 *set_out = Tangents[i].OutTangent;
375}
376
381
383{
384 if (TangentsDirty) {
386 }
387
389 Curve1DClass::Save(csave);
390 csave.End_Chunk();
391
393 for (int i=0; i<Tangents.Count(); i++) {
394 csave.Write(&(Tangents[i].InTangent),sizeof(Tangents[i].InTangent));
395 csave.Write(&(Tangents[i].OutTangent),sizeof(Tangents[i].OutTangent));
396 }
397 csave.End_Chunk();
398 return true;
399}
400
402{
403 int i;
404 TangentsClass newtangent;
405
406 // reset the tangents array
407 Tangents.Delete_All();
408
409 // read in the chunks
410 while (cload.Open_Chunk()) {
411
412 switch(cload.Cur_Chunk_ID())
413 {
415 Curve1DClass::Load(cload);
416 break;
417
419 for (i=0; i<Keys.Count(); i++) {
420 cload.Read(&(newtangent.InTangent),sizeof(newtangent.InTangent));
421 cload.Read(&(newtangent.OutTangent),sizeof(newtangent.OutTangent));
422 Tangents.Add(newtangent);
423 }
424 TangentsDirty = false;
425 break;
426
427 default:
428 WWDEBUG_SAY(("Unhandled Chunk: 0x%X File: %s Line: %d\r\n",__FILE__,__LINE__));
429 break;
430 }
431 cload.Close_Chunk();
432 }
433
434 WWASSERT(Keys.Count() == Tangents.Count());
435 return true;
436}
437
#define WWASSERT
#define MIN(a, b)
Definition always.h:189
#define MAX(a, b)
Definition always.h:185
bool Close_Chunk()
Definition chunkio.cpp:448
uint32 Cur_Chunk_ID()
Definition chunkio.cpp:484
uint32 Read(void *buf, uint32 nbytes)
Definition chunkio.cpp:692
bool Open_Chunk()
Definition chunkio.cpp:412
uint32 Write(const void *buf, uint32 nbytes)
Definition chunkio.cpp:264
bool Begin_Chunk(uint32 id)
Definition chunkio.cpp:108
bool End_Chunk()
Definition chunkio.cpp:148
virtual void Clear_Keys(void)
Definition curve.cpp:431
void Find_Interval(float time, int *i0, int *i1, float *t)
Definition curve.cpp:436
virtual bool Load(ChunkLoadClass &cload)
Definition curve.cpp:488
bool IsLooping
Definition curve.h:162
virtual void Set_Key(int i, float point, unsigned int extra=0)
Definition curve.cpp:399
virtual int Add_Key(float point, float t, unsigned int extra=0)
Definition curve.cpp:408
virtual void Remove_Key(int i)
Definition curve.cpp:424
virtual bool Save(ChunkSaveClass &csave)
Definition curve.cpp:468
DynamicVectorClass< KeyClass > Keys
Definition curve.h:163
virtual void Set_Looping(bool onoff)
Definition curve.cpp:356
virtual void Remove_Key(int i)
Definition curve.cpp:176
virtual void Clear_Keys(void)
Definition curve.cpp:183
virtual void Set_Key(int i, const Vector3 &point)
Definition curve.cpp:153
bool IsLooping
Definition curve.h:103
void Find_Interval(float time, int *i0, int *i1, float *t)
Definition curve.cpp:188
virtual bool Load(ChunkLoadClass &cload)
Definition curve.cpp:221
Curve3DClass & operator=(const Curve3DClass &that)
Definition curve.cpp:101
virtual void Set_Looping(bool onoff)
Definition curve.cpp:113
virtual bool Save(ChunkSaveClass &csave)
Definition curve.cpp:202
virtual int Add_Key(const Vector3 &point, float t)
Definition curve.cpp:161
DynamicVectorClass< KeyClass > Keys
Definition curve.h:104
DynamicVectorClass< TangentsClass > Tangents
virtual void Set_Key(int i, float point, unsigned int extra=0)
virtual int Add_Key(float point, float t, unsigned int extra=0)
virtual void Clear_Keys(void)
virtual const PersistFactoryClass & Get_Factory(void) const
virtual void Set_Looping(bool onoff)
virtual void Evaluate(float time, float *set_val)
virtual void Set_Tangents(int i, float in_tan, float out_tan)
virtual void Get_Tangents(int i, float *set_in, float *set_out)
virtual bool Load(ChunkLoadClass &cload)
virtual void Update_Tangents(void)
virtual bool Save(ChunkSaveClass &csave)
virtual void Remove_Key(int i)
virtual bool Save(ChunkSaveClass &csave)
virtual void Set_Tangents(int i, const Vector3 &in_tan, const Vector3 &out_tan)
virtual void Remove_Key(int i)
virtual const PersistFactoryClass & Get_Factory(void) const
virtual void Evaluate(float time, Vector3 *set_val)
const HermiteSpline3DClass & operator=(const HermiteSpline3DClass &that)
virtual void Set_Key(int i, const Vector3 &point)
virtual void Update_Tangents(void)
virtual void Clear_Keys(void)
virtual bool Load(ChunkLoadClass &cload)
virtual void Evaluate_Derivative(float time, Vector3 *set_val)
DynamicVectorClass< TangentsClass > Tangents
virtual void Get_Tangents(int i, Vector3 *set_in, Vector3 *set_out)
virtual int Add_Key(const Vector3 &point, float t)
virtual void Set_Looping(bool onoff)
float X
Definition vector3.h:90
float Z
Definition vector3.h:92
float Y
Definition vector3.h:91
WWINLINE void Set(float x, float y, float z)
Definition vector3.h:103
SimplePersistFactoryClass< HermiteSpline1DClass, WWMATH_CHUNKID_HERMITESPLINE1D > _HermiteSpline1DFactory
@ HERMITE1D_CHUNK_CURVE1D
@ HERMITE3D_CHUNK_TANGENTS
@ HERMITE1D_CHUNK_TANGENTS
@ HERMITE3D_CHUNK_CURVE3D
SimplePersistFactoryClass< HermiteSpline3DClass, WWMATH_CHUNKID_HERMITESPLINE3D > _HermiteSpline3DFactory
#define WWDEBUG_SAY(x)
Definition wwdebug.h:114
#define DECLARE_FORCE_LINK(module)
Definition wwhack.h:48