catmullromspline.cpp 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354
  1. /*
  2. ** Command & Conquer Renegade(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. *** 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 ***
  20. ***********************************************************************************************
  21. * *
  22. * Project Name : WWMath *
  23. * *
  24. * $Archive:: /Commando/Code/wwmath/catmullromspline.cpp $*
  25. * *
  26. * Author:: Greg Hjelstrom *
  27. * *
  28. * $Modtime:: 3/08/00 8:50p $*
  29. * *
  30. * $Revision:: 6 $*
  31. * *
  32. *---------------------------------------------------------------------------------------------*
  33. * Functions: *
  34. * CatmullRomSpline3DClass::Update_Tangents -- computes the tangents at each key *
  35. * CatmullRomSpline3DClass::Get_Factory -- returns the factory for CatmullRomSpline3D *
  36. * CatmullRomSpline3DClass::Save -- save this curve *
  37. * CatmullRomSpline3DClass::Load -- load this curve *
  38. * CatmullRomSpline1DClass::Update_Tangents -- Computes the tangents at each key *
  39. * CatmullRomSpline1DClass::Get_Factory -- returns the factory for CatmullRomSpline1D *
  40. * CatmullRomSpline1DClass::Save -- Save this curve *
  41. * CatmullRomSpline1DClass::Load -- Load this curve *
  42. * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
  43. #include "catmullromspline.h"
  44. #include "persistfactory.h"
  45. #include "wwmathids.h"
  46. #include "wwhack.h"
  47. /*
  48. ** Force-Link this module because the linker can't detect that we actually need it...
  49. */
  50. DECLARE_FORCE_LINK(catmullromspline);
  51. /*
  52. ** Save-Load stuff
  53. */
  54. SimplePersistFactoryClass<CatmullRomSpline3DClass,WWMATH_CHUNKID_CATMULLROMSPLINE3D> _CatmullRomSpline3DFactory;
  55. SimplePersistFactoryClass<CatmullRomSpline1DClass,WWMATH_CHUNKID_CATMULLROMSPLINE1D> _CatmullRomSpline1DFactory;
  56. enum
  57. {
  58. // ID's used by CatmullRomSpline3D
  59. CATMULLROM3D_CHUNK_HERMITE3D = 0x00020727,
  60. // ID's used by CatmullRomSpline1D
  61. CATMULLROM1D_CHUNK_HERMITE1D = 0x00020729,
  62. };
  63. /*
  64. ** Catmull-Rom 3D spline implementation
  65. */
  66. /***********************************************************************************************
  67. * CatmullRomSpline3DClass::Update_Tangents -- computes the tangents at each key *
  68. * *
  69. * INPUT: *
  70. * *
  71. * OUTPUT: *
  72. * *
  73. * WARNINGS: *
  74. * I'm not sure about the tangents for the endpoints of the curve. *
  75. * *
  76. * HISTORY: *
  77. * 3/7/2000 gth : Created. *
  78. *=============================================================================================*/
  79. void CatmullRomSpline3DClass::Update_Tangents(void)
  80. {
  81. if (Keys.Count() < 2) {
  82. for (int i=0; i<Keys.Count(); i++) {
  83. Tangents[0].InTangent.Set(0,0,0);
  84. Tangents[0].OutTangent.Set(0,0,0);
  85. }
  86. }
  87. // first and last knot
  88. int end = Keys.Count() - 1;
  89. Tangents[0].InTangent.Set(0,0,0);
  90. Tangents[end].OutTangent.Set(0,0,0);
  91. if (IsLooping) {
  92. // This really only works if the start and end points have the same position...
  93. Tangents[0].OutTangent.X = 0.5f*(Keys[1].Point.X - Keys[end-1].Point.X);
  94. Tangents[0].OutTangent.Y = 0.5f*(Keys[1].Point.Y - Keys[end-1].Point.Y);
  95. Tangents[0].OutTangent.Z = 0.5f*(Keys[1].Point.Z - Keys[end-1].Point.Z);
  96. Tangents[end].InTangent = Tangents[0].OutTangent;
  97. } else {
  98. // TODO: second derivative = 0... what is formula? I'm making this up...
  99. Tangents[0].OutTangent.X = 0.25f*(Keys[1].Point.X - Keys[0].Point.X);
  100. Tangents[0].OutTangent.Y = 0.25f*(Keys[1].Point.Y - Keys[0].Point.Y);
  101. Tangents[0].OutTangent.Z = 0.25f*(Keys[1].Point.Z - Keys[0].Point.Z);
  102. Tangents[end].InTangent.X = 0.25f*(Keys[end].Point.X - Keys[end-1].Point.X);
  103. Tangents[end].InTangent.Y = 0.25f*(Keys[end].Point.Y - Keys[end-1].Point.Y);
  104. Tangents[end].InTangent.Z = 0.25f*(Keys[end].Point.Z - Keys[end-1].Point.Z);
  105. }
  106. float total_time = (Keys[1].Time - Keys[0].Time) + (Keys[end].Time - Keys[end-1].Time);
  107. float in_factor = 2.0f * (Keys[end].Time - Keys[end-1].Time) / total_time;
  108. float out_factor = 2.0f * (Keys[1].Time - Keys[0].Time) / total_time;
  109. Tangents[end].InTangent *= in_factor;
  110. Tangents[0].OutTangent *= out_factor;
  111. // inner knots
  112. for (int i=1; i<Keys.Count()-1; i++) {
  113. Tangents[i].InTangent.X = 0.5f*(Keys[i+1].Point.X - Keys[i-1].Point.X);
  114. Tangents[i].InTangent.Y = 0.5f*(Keys[i+1].Point.Y - Keys[i-1].Point.Y);
  115. Tangents[i].InTangent.Z = 0.5f*(Keys[i+1].Point.Z - Keys[i-1].Point.Z);
  116. Tangents[i].OutTangent = Tangents[i].InTangent;
  117. float in_factor = 2.0f * (Keys[i].Time - Keys[i-1].Time) / (Keys[i+1].Time - Keys[i-1].Time);
  118. float out_factor = 2.0f * (Keys[i+1].Time - Keys[i].Time) / (Keys[i+1].Time - Keys[i-1].Time);
  119. Tangents[i].InTangent *= in_factor; // compensating for the un-even keys
  120. Tangents[i].OutTangent *= out_factor;
  121. }
  122. TangentsDirty = false;
  123. }
  124. /***********************************************************************************************
  125. * CatmullRomSpline3DClass::Get_Factory -- returns the factory for CatmullRomSpline3D *
  126. * *
  127. * INPUT: *
  128. * *
  129. * OUTPUT: *
  130. * *
  131. * WARNINGS: *
  132. * *
  133. * HISTORY: *
  134. * 3/7/2000 gth : Created. *
  135. *=============================================================================================*/
  136. const PersistFactoryClass & CatmullRomSpline3DClass::Get_Factory(void) const
  137. {
  138. return _CatmullRomSpline3DFactory;
  139. }
  140. /***********************************************************************************************
  141. * CatmullRomSpline3DClass::Save -- save this curve *
  142. * *
  143. * INPUT: *
  144. * *
  145. * OUTPUT: *
  146. * *
  147. * WARNINGS: *
  148. * *
  149. * HISTORY: *
  150. * 3/7/2000 gth : Created. *
  151. *=============================================================================================*/
  152. bool CatmullRomSpline3DClass::Save(ChunkSaveClass &csave)
  153. {
  154. csave.Begin_Chunk(CATMULLROM3D_CHUNK_HERMITE3D);
  155. HermiteSpline3DClass::Save(csave);
  156. csave.End_Chunk();
  157. return true;
  158. }
  159. /***********************************************************************************************
  160. * CatmullRomSpline3DClass::Load -- load this curve *
  161. * *
  162. * INPUT: *
  163. * *
  164. * OUTPUT: *
  165. * *
  166. * WARNINGS: *
  167. * *
  168. * HISTORY: *
  169. * 3/7/2000 gth : Created. *
  170. *=============================================================================================*/
  171. bool CatmullRomSpline3DClass::Load(ChunkLoadClass &cload)
  172. {
  173. while (cload.Open_Chunk()) {
  174. switch(cload.Cur_Chunk_ID())
  175. {
  176. case CATMULLROM3D_CHUNK_HERMITE3D:
  177. HermiteSpline3DClass::Load(cload);
  178. break;
  179. default:
  180. WWDEBUG_SAY(("Unhandled Chunk: 0x%X File: %s Line: %d\r\n",__FILE__,__LINE__));
  181. break;
  182. }
  183. cload.Close_Chunk();
  184. }
  185. return true;
  186. }
  187. /*
  188. ** The 1D Catmull-Rom implementation.
  189. */
  190. /***********************************************************************************************
  191. * CatmullRomSpline1DClass::Update_Tangents -- Computes the tangents at each key *
  192. * *
  193. * INPUT: *
  194. * *
  195. * OUTPUT: *
  196. * *
  197. * WARNINGS: *
  198. * *
  199. * HISTORY: *
  200. * 3/7/2000 gth : Created. *
  201. *=============================================================================================*/
  202. void CatmullRomSpline1DClass::Update_Tangents(void)
  203. {
  204. if (Keys.Count() < 2) {
  205. for (int i=0; i<Keys.Count(); i++) {
  206. Tangents[i].InTangent = 0.0f;
  207. Tangents[i].OutTangent = 0.0f;
  208. }
  209. return;
  210. }
  211. // first and last knot
  212. int end = Keys.Count() - 1;
  213. Tangents[0].InTangent = 0.0f;
  214. Tangents[end].OutTangent = 0.0f;
  215. if (IsLooping) {
  216. // This really only works if the start and end points have the same position...
  217. Tangents[0].OutTangent = 0.5f*(Keys[1].Point - Keys[end-1].Point);
  218. Tangents[end].InTangent = Tangents[0].OutTangent;
  219. } else {
  220. // TODO: second derivative = 0... what is formula? I'm making this up...
  221. Tangents[0].OutTangent = 0.25f*(Keys[1].Point - Keys[0].Point);
  222. Tangents[end].InTangent = 0.25f*(Keys[end].Point - Keys[end-1].Point);
  223. }
  224. float total_time = (Keys[1].Time - Keys[0].Time) + (Keys[end].Time - Keys[end-1].Time);
  225. float in_factor = 2.0f * (Keys[end].Time - Keys[end-1].Time) / total_time;
  226. float out_factor = 2.0f * (Keys[1].Time - Keys[0].Time) / total_time;
  227. Tangents[end].InTangent *= in_factor;
  228. Tangents[0].OutTangent *= out_factor;
  229. // inner knots
  230. for (int i=1; i<Keys.Count()-1; i++) {
  231. Tangents[i].InTangent = 0.5f*(Keys[i+1].Point - Keys[i-1].Point);
  232. Tangents[i].OutTangent = Tangents[i].InTangent;
  233. float in_factor = 2.0f * (Keys[i].Time - Keys[i-1].Time) / (Keys[i+1].Time - Keys[i-1].Time);
  234. float out_factor = 2.0f * (Keys[i+1].Time - Keys[i].Time) / (Keys[i+1].Time - Keys[i-1].Time);
  235. Tangents[i].InTangent *= in_factor; // compensating for the un-even keys
  236. Tangents[i].OutTangent *= out_factor;
  237. }
  238. TangentsDirty = false;
  239. }
  240. /***********************************************************************************************
  241. * CatmullRomSpline1DClass::Get_Factory -- returns the factory for CatmullRomSpline1D *
  242. * *
  243. * INPUT: *
  244. * *
  245. * OUTPUT: *
  246. * *
  247. * WARNINGS: *
  248. * *
  249. * HISTORY: *
  250. * 3/7/2000 gth : Created. *
  251. *=============================================================================================*/
  252. const PersistFactoryClass & CatmullRomSpline1DClass::Get_Factory(void) const
  253. {
  254. return _CatmullRomSpline1DFactory;
  255. }
  256. /***********************************************************************************************
  257. * CatmullRomSpline1DClass::Save -- Save this curve *
  258. * *
  259. * INPUT: *
  260. * *
  261. * OUTPUT: *
  262. * *
  263. * WARNINGS: *
  264. * *
  265. * HISTORY: *
  266. * 3/7/2000 gth : Created. *
  267. *=============================================================================================*/
  268. bool CatmullRomSpline1DClass::Save(ChunkSaveClass &csave)
  269. {
  270. csave.Begin_Chunk(CATMULLROM1D_CHUNK_HERMITE1D);
  271. HermiteSpline1DClass::Save(csave);
  272. csave.End_Chunk();
  273. return true;
  274. }
  275. /***********************************************************************************************
  276. * CatmullRomSpline1DClass::Load -- Load this curve *
  277. * *
  278. * INPUT: *
  279. * *
  280. * OUTPUT: *
  281. * *
  282. * WARNINGS: *
  283. * *
  284. * HISTORY: *
  285. * 3/7/2000 gth : Created. *
  286. *=============================================================================================*/
  287. bool CatmullRomSpline1DClass::Load(ChunkLoadClass &cload)
  288. {
  289. while (cload.Open_Chunk()) {
  290. switch(cload.Cur_Chunk_ID())
  291. {
  292. case CATMULLROM1D_CHUNK_HERMITE1D:
  293. HermiteSpline1DClass::Load(cload);
  294. break;
  295. default:
  296. WWDEBUG_SAY(("Unhandled Chunk: 0x%X File: %s Line: %d\r\n",__FILE__,__LINE__));
  297. break;
  298. }
  299. cload.Close_Chunk();
  300. }
  301. return true;
  302. }