You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

578 lines
21 KiB

  1. unit ugluVectorExHelper;
  2. {$mode objfpc}{$H+}
  3. {$modeswitch typehelpers}
  4. interface
  5. uses
  6. Classes, SysUtils;
  7. type
  8. generic TgluVectorHelper<T> = class
  9. public type
  10. TBaseType = T;
  11. PBaseType = ^TBaseType;
  12. TVector2 = array[0..1] of T;
  13. TVector3 = array[0..2] of T;
  14. TVector4 = array[0..3] of T;
  15. PVector2 = ^TVector2;
  16. PVector3 = ^TVector3;
  17. PVector4 = ^TVector4;
  18. public
  19. class function Vector2(const x, y: T): TVector2; overload; inline;
  20. class function Vector3(const x, y, z: T): TVector3; overload; inline;
  21. class function Vector4(const x, y, z, w: T): TVector4; overload; inline;
  22. class function Equals(const v1: TVector2; const v2: TVector2): Boolean; overload; inline;
  23. class function Equals(const v1: TVector3; const v2: TVector3): Boolean; overload; inline;
  24. class function Equals(const v1: TVector4; const v2: TVector4): Boolean; overload; inline;
  25. class function ToString(const v: TVector2; const aRound: Integer = -3): String; overload;
  26. class function ToString(const v: TVector3; const aRound: Integer = -3): String; overload;
  27. class function ToString(const v: TVector4; const aRound: Integer = -3): String; overload;
  28. class function TryFromString(const s: String; out v: TVector2): Boolean; overload; inline;
  29. class function TryFromString(const s: String; out v: TVector3): Boolean; overload; inline;
  30. class function TryFromString(const s: String; out v: TVector4): Boolean; overload; inline;
  31. private
  32. class function TryFromString(const s: String; p: PBaseType; aCount: Integer): Boolean;
  33. end;
  34. generic TgluVectorHelperI<T> = class(specialize TgluVectorHelper<T>)
  35. public
  36. class function Length(const v: TVector2): Double; overload; inline;
  37. class function Length(const v: TVector3): Double; overload; inline;
  38. class function Length(const v: TVector4): Double; overload; inline;
  39. class function Multiply(const v: TVector2; const a: T): TVector2; overload; inline;
  40. class function Multiply(const v: TVector3; const a: T): TVector3; overload; inline;
  41. class function Multiply(const v: TVector4; const a: T): TVector4; overload; inline;
  42. class function Add(const v1, v2: TVector2): TVector2; overload; inline;
  43. class function Add(const v1, v2: TVector3): TVector3; overload; inline;
  44. class function Sub(const v1, v2: TVector2): TVector2; overload; inline;
  45. class function Sub(const v1, v2: TVector3): TVector3; overload; inline;
  46. end;
  47. generic TgluVectorHelperF<T> = class(specialize TgluVectorHelperI<T>)
  48. public
  49. class function Normalize(const v: TVector2): TVector2; overload; inline;
  50. class function Normalize(const v: TVector3): TVector3; overload; inline;
  51. class function Normalize(const v: TVector4): TVector4; overload; inline;
  52. class function Divide(const v: TVector2; const a: T): TVector2; overload; inline;
  53. class function Divide(const v: TVector3; const a: T): TVector3; overload; inline;
  54. class function Divide(const v: TVector4; const a: T): TVector4; overload; inline;
  55. class function Dot(const v1: TVector2; const v2: TVector2): T; overload; inline;
  56. class function Dot(const v1: TVector3; const v2: TVector3): T; overload; inline;
  57. class function Dot(const v1: TVector4; const v2: TVector4): T; overload; inline;
  58. class function Cross(const v1: TVector3; const v2: TVector3): TVector3; overload; inline;
  59. class function Angle(const v1: TVector2; const v2: TVector2): Double; overload; inline;
  60. class function Angle(const v1: TVector3; const v2: TVector3): Double; overload; inline;
  61. class function Angle2(const v1: TVector2; const v2: TVector2): Double; overload; inline;
  62. class function ClampVal(const v, aMin, aMax: T): T; overload; inline;
  63. class function Clamp(const v, aMin, aMax: TVector2): TVector2; overload; inline;
  64. class function Clamp(const v, aMin, aMax: TVector3): TVector3; overload; inline;
  65. class function Clamp(const v, aMin, aMax: TVector4): TVector4; overload; inline;
  66. class function Clamp(const v: TVector2; const aMin, aMax: T): TVector2; overload; inline;
  67. class function Clamp(const v: TVector3; const aMin, aMax: T): TVector3; overload; inline;
  68. class function Clamp(const v: TVector4; const aMin, aMax: T): TVector4; overload; inline;
  69. end;
  70. TgluVectorP = specialize TgluVectorHelper<Pointer>;
  71. TgluVectorE = specialize TgluVectorHelper<Cardinal>;
  72. TgluVectorI = specialize TgluVectorHelperI<Integer>;
  73. TgluVectorUS = specialize TgluVectorHelperI<Word>;
  74. TgluVectorUB = specialize TgluVectorHelperI<Byte>;
  75. TgluVectorF = specialize TgluVectorHelperF<Single>;
  76. TgluVectorD = specialize TgluVectorHelperF<Double>;
  77. implementation
  78. uses
  79. Math;
  80. type
  81. TPointerTypeHelper = type helper for Pointer
  82. function ToString(const aRound: Integer = -3): String;
  83. class function TryFromString(s: String; out v: Pointer): Boolean; static;
  84. end;
  85. TCardinalTypeHelper = type helper for Cardinal
  86. function ToString(const aRound: Integer = -3): String;
  87. class function TryFromString(s: String; out v: Cardinal): Boolean; static;
  88. end;
  89. TIntegerTypeHelper = type helper for Integer
  90. function ToString(const aRound: Integer = -3): String;
  91. class function TryFromString(s: String; out v: Integer): Boolean; static;
  92. end;
  93. TWordTypeHelper = type helper for Word
  94. function ToString(const aRound: Integer = -3): String;
  95. class function TryFromString(s: String; out v: Word): Boolean; static;
  96. end;
  97. TByteTypeHelper = type helper for Byte
  98. function ToString(const aRound: Integer = -3): String;
  99. class function TryFromString(s: String; out v: Byte): Boolean; static;
  100. end;
  101. TSingleTypeHelper = type helper for Single
  102. function ToString(const aRound: Integer = -3): String;
  103. class function TryFromString(s: String; out v: Single): Boolean; static;
  104. end;
  105. TDoubleTypeHelper = type helper for Double
  106. function ToString(const aRound: Integer = -3): String;
  107. class function TryFromString(s: String; out v: Double): Boolean; static;
  108. end;
  109. function IntToStrRounded(i: Int64; const aRound: Integer): String;
  110. var p: Cardinal;
  111. begin
  112. if (aRound > 0) then begin
  113. p := Round(power(10, aRound));
  114. i := i div p;
  115. i := i * p;
  116. end;
  117. result := IntToStr(i);
  118. end;
  119. function FloatToStrRounded(f: Extended; const aRound: Integer): String;
  120. var p: Cardinal; fmt: TFormatSettings;
  121. begin
  122. if (aRound > 0) then begin
  123. p := Round(power(10, aRound));
  124. f := Round(f / p) * p;
  125. end;
  126. fmt.DecimalSeparator := '.';
  127. result := Format('%.*f', [Max(0, -aRound), f], fmt);
  128. end;
  129. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  130. //TPointerTypeHelper////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  131. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  132. function TPointerTypeHelper.ToString(const aRound: Integer): String;
  133. begin
  134. result := '0x' + IntToHex({%H-}PtrUInt(self), 2 * SizeOf(Pointer));
  135. end;
  136. class function TPointerTypeHelper.TryFromString(s: String; out v: Pointer): Boolean;
  137. var
  138. i: Int64;
  139. begin
  140. s := StringReplace(s, '0x', '$', [rfReplaceAll, rfIgnoreCase]);
  141. result := TryStrToInt64(s, i);
  142. if result
  143. then v := {%H-}Pointer(PtrUInt(i))
  144. else v := nil;
  145. end;
  146. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  147. //TCardinalTypeHelper///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  148. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  149. function TCardinalTypeHelper.ToString(const aRound: Integer): String;
  150. begin
  151. result := IntToStrRounded(self, aRound);
  152. end;
  153. class function TCardinalTypeHelper.TryFromString(s: String; out v: Cardinal): Boolean;
  154. var i: LongInt;
  155. begin
  156. result := TryStrToInt(s, i);
  157. if result
  158. then v := i
  159. else v := 0;
  160. end;
  161. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  162. //TIntegerTypeHelper////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  163. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  164. function TIntegerTypeHelper.ToString(const aRound: Integer): String;
  165. begin
  166. result := IntToStrRounded(self, aRound);
  167. end;
  168. class function TIntegerTypeHelper.TryFromString(s: String; out v: Integer): Boolean;
  169. begin
  170. result := TryStrToInt(s, v);
  171. end;
  172. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  173. //TWordTypeHelper///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  174. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  175. function TWordTypeHelper.ToString(const aRound: Integer): String;
  176. begin
  177. result := IntToStrRounded(self, aRound);
  178. end;
  179. class function TWordTypeHelper.TryFromString(s: String; out v: Word): Boolean;
  180. var i: LongInt;
  181. begin
  182. result := TryStrToInt(s, i);
  183. if result
  184. then v := i
  185. else v := 0;
  186. end;
  187. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  188. //TByteTypeHelper///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  189. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  190. function TByteTypeHelper.ToString(const aRound: Integer): String;
  191. begin
  192. result := IntToStrRounded(self, aRound);
  193. end;
  194. class function TByteTypeHelper.TryFromString(s: String; out v: Byte): Boolean;
  195. var i: LongInt;
  196. begin
  197. result := TryStrToInt(s, i);
  198. if result
  199. then v := i
  200. else v := 0;
  201. end;
  202. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  203. //TSingleTypeHelper/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  204. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  205. function TSingleTypeHelper.ToString(const aRound: Integer): String;
  206. begin
  207. result := FloatToStrRounded(self, aRound);
  208. end;
  209. class function TSingleTypeHelper.TryFromString(s: String; out v: Single): Boolean;
  210. var f: TFormatSettings;
  211. begin
  212. f.DecimalSeparator := '.';
  213. result := TryStrToFloat(s, v, f);
  214. end;
  215. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  216. //TDoubleTypeHelper/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  217. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  218. function TDoubleTypeHelper.ToString(const aRound: Integer): String;
  219. begin
  220. result := FloatToStrRounded(self, aRound);
  221. end;
  222. class function TDoubleTypeHelper.TryFromString(s: String; out v: Double): Boolean;
  223. var f: TFormatSettings;
  224. begin
  225. f.DecimalSeparator := '.';
  226. result := TryStrToFloat(s, v, f);
  227. end;
  228. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  229. //TgluVectorHelper//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  230. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  231. class function TgluVectorHelper.Vector2(const x, y: T): TVector2;
  232. begin
  233. result[0] := x;
  234. result[1] := y;
  235. end;
  236. class function TgluVectorHelper.Vector3(const x, y, z: T): TVector3;
  237. begin
  238. result[0] := x;
  239. result[1] := y;
  240. result[2] := z;
  241. end;
  242. class function TgluVectorHelper.Vector4(const x, y, z, w: T): TVector4;
  243. begin
  244. result[0] := x;
  245. result[1] := y;
  246. result[2] := z;
  247. result[3] := w;
  248. end;
  249. class function TgluVectorHelper.Equals(const v1: TVector2; const v2: TVector2): Boolean;
  250. begin
  251. result := (v1[0] = v2[0]) and (v1[1] = v2[1]);
  252. end;
  253. class function TgluVectorHelper.Equals(const v1: TVector3; const v2: TVector3): Boolean;
  254. begin
  255. result := Equals(PVector2(@v1[0])^, PVector2(@v2[0])^) and (v1[2] = v2[2]);
  256. end;
  257. class function TgluVectorHelper.Equals(const v1: TVector4; const v2: TVector4): Boolean;
  258. begin
  259. result := Equals(PVector3(@v1[0])^, PVector3(@v2[0])^) and (v1[3] = v2[3]);
  260. end;
  261. class function TgluVectorHelper.ToString(const v: TVector2; const aRound: Integer): String;
  262. begin
  263. result := v[0].ToString(aRound) + '; ' + v[1].ToString(aRound);
  264. end;
  265. class function TgluVectorHelper.ToString(const v: TVector3; const aRound: Integer): String;
  266. begin
  267. result := v[0].ToString(aRound) + '; ' + v[1].ToString(aRound) + '; ' + v[2].ToString(aRound);
  268. end;
  269. class function TgluVectorHelper.ToString(const v: TVector4; const aRound: Integer): String;
  270. begin
  271. result := v[0].ToString(aRound) + '; ' + v[1].ToString(aRound) + '; ' + v[2].ToString(aRound) + '; ' + v[3].ToString(aRound);
  272. end;
  273. class function TgluVectorHelper.TryFromString(const s: String; out v: TVector2): Boolean;
  274. begin
  275. result := TryFromString(s, @v[0], 2);
  276. end;
  277. class function TgluVectorHelper.TryFromString(const s: String; out v: TVector3): Boolean;
  278. begin
  279. result := TryFromString(s, @v[0], 3);
  280. end;
  281. class function TgluVectorHelper.TryFromString(const s: String; out v: TVector4): Boolean;
  282. begin
  283. result := TryFromString(s, @v[0], 4);
  284. end;
  285. class function TgluVectorHelper.TryFromString(const s: String; p: PBaseType; aCount: Integer): Boolean;
  286. var
  287. i, j, l: Integer;
  288. begin
  289. result := true;
  290. i := 1;
  291. j := 1;
  292. l := Length(s);
  293. while ({%H-}i <= {%H-}l) and (aCount > 0) and result {%H-}do begin
  294. if (s[i] = ';') then begin
  295. result := TBaseType.TryFromString(Trim(copy(s, j, i-{%H-}j)), p^);
  296. j := i+1;
  297. inc(p);
  298. dec(aCount);
  299. end;
  300. inc(i);
  301. end;
  302. while (aCount > 0) do begin
  303. p^ := TBaseType(0);
  304. inc(p);
  305. dec(aCount);
  306. end;
  307. end;
  308. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  309. //TgluVectorHelperI/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  310. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  311. class function TgluVectorHelperI.Length(const v: TVector2): Double;
  312. begin
  313. result := SQRT(v[0]*v[0] + v[1]*v[1]);
  314. end;
  315. class function TgluVectorHelperI.Length(const v: TVector3): Double;
  316. begin
  317. result := SQRT(v[0]*v[0] + v[1]*v[1] + v[2]*v[2]);
  318. end;
  319. class function TgluVectorHelperI.Length(const v: TVector4): Double;
  320. begin
  321. result := SQRT(v[0]*v[0] + v[1]*v[1] + v[2]*v[2]) * v[3];
  322. end;
  323. class function TgluVectorHelperI.Multiply(const v: TVector2; const a: T): TVector2;
  324. begin
  325. result[0] := v[0] * a;
  326. result[1] := v[1] * a;
  327. end;
  328. class function TgluVectorHelperI.Multiply(const v: TVector3; const a: T): TVector3;
  329. begin
  330. result[0] := v[0] * a;
  331. result[1] := v[1] * a;
  332. result[2] := v[2] * a;
  333. end;
  334. class function TgluVectorHelperI.Multiply(const v: TVector4; const a: T): TVector4;
  335. begin
  336. result[0] := v[0] * a;
  337. result[1] := v[1] * a;
  338. result[2] := v[2] * a;
  339. result[3] := v[3] * a;
  340. end;
  341. class function TgluVectorHelperI.Add(const v1, v2: TVector2): TVector2;
  342. begin
  343. result[0] := v1[0] + v2[0];
  344. result[1] := v1[1] + v2[1];
  345. end;
  346. class function TgluVectorHelperI.Add(const v1, v2: TVector3): TVector3;
  347. begin
  348. result[0] := v1[0] + v2[0];
  349. result[1] := v1[1] + v2[1];
  350. result[2] := v1[2] + v2[2];
  351. end;
  352. class function TgluVectorHelperI.Sub(const v1, v2: TVector2): TVector2;
  353. begin
  354. result[0] := v1[0] - v2[0];
  355. result[1] := v1[1] - v2[1];
  356. end;
  357. class function TgluVectorHelperI.Sub(const v1, v2: TVector3): TVector3;
  358. begin
  359. result[0] := v1[0] - v2[0];
  360. result[1] := v1[1] - v2[1];
  361. result[2] := v1[2] - v2[2];
  362. end;
  363. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  364. //TgluVectorHelperF/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  365. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  366. class function TgluVectorHelperF.Normalize(const v: TVector2): TVector2;
  367. var l: Double;
  368. begin
  369. l := Length(v);
  370. result[0] := v[0] / l;
  371. result[1] := v[1] / l;
  372. end;
  373. class function TgluVectorHelperF.Normalize(const v: TVector3): TVector3;
  374. var l: Double;
  375. begin
  376. l := Length(v);
  377. result[0] := v[0] / l;
  378. result[1] := v[1] / l;
  379. result[2] := v[2] / l;
  380. end;
  381. class function TgluVectorHelperF.Normalize(const v: TVector4): TVector4;
  382. begin
  383. result := v;
  384. if (result[3] <> 0) then
  385. result := Divide(v, v[3]);
  386. PVector3(@result[0])^ := Normalize(PVector3(@result[0])^);
  387. end;
  388. class function TgluVectorHelperF.Divide(const v: TVector2; const a: T): TVector2;
  389. begin
  390. result[0] := v[0] / a;
  391. result[1] := v[1] / a;
  392. end;
  393. class function TgluVectorHelperF.Divide(const v: TVector3; const a: T): TVector3;
  394. begin
  395. result[0] := v[0] / a;
  396. result[1] := v[1] / a;
  397. result[2] := v[2] / a;
  398. end;
  399. class function TgluVectorHelperF.Divide(const v: TVector4; const a: T): TVector4;
  400. begin
  401. result[0] := v[0] / a;
  402. result[1] := v[1] / a;
  403. result[2] := v[2] / a;
  404. result[3] := v[3] / a;
  405. end;
  406. class function TgluVectorHelperF.Dot(const v1: TVector2; const v2: TVector2): T;
  407. begin
  408. result := v1[0] * v2[0] + v1[1] * v2[1];
  409. end;
  410. class function TgluVectorHelperF.Dot(const v1: TVector3; const v2: TVector3): T;
  411. begin
  412. result := v1[0] * v2[0] + v1[1] * v2[1] + v1[2] * v2[2];
  413. end;
  414. class function TgluVectorHelperF.Dot(const v1: TVector4; const v2: TVector4): T;
  415. begin
  416. result := v1[0] * v2[0] + v1[1] * v2[1] + v1[2] * v2[2] + v1[3] * v2[3];
  417. end;
  418. class function TgluVectorHelperF.Cross(const v1: TVector3; const v2: TVector3): TVector3;
  419. begin
  420. result[0] := v1[1] * v2[2] - v1[2] * v2[1];
  421. result[1] := v1[2] * v2[0] - v1[0] * v2[2];
  422. result[2] := v1[0] * v2[1] - v1[1] * v2[0];
  423. end;
  424. class function TgluVectorHelperF.Angle(const v1: TVector2; const v2: TVector2): Double;
  425. begin
  426. result := ArcCos(Dot(v1, v2) / (Length(v1) * Length(v2)));
  427. end;
  428. class function TgluVectorHelperF.Angle(const v1: TVector3; const v2: TVector3): Double;
  429. begin
  430. result := ArcCos(Dot(v1, v2) / (Length(v1) * Length(v2)));
  431. end;
  432. class function TgluVectorHelperF.Angle2(const v1: TVector2; const v2: TVector2): Double;
  433. begin
  434. result := arctan2(
  435. v2[0] * v1[1] - v2[1] * v1[0],
  436. v2[0] * v1[0] + v2[1] * v1[1]);
  437. end;
  438. class function TgluVectorHelperF.ClampVal(const v, aMin, aMax: T): T;
  439. begin
  440. if (v < aMin) then
  441. result := aMin
  442. else if (v > aMax) then
  443. result := aMax
  444. else
  445. result := v;
  446. end;
  447. class function TgluVectorHelperF.Clamp(const v, aMin, aMax: TVector2): TVector2;
  448. begin
  449. result[0] := ClampVal(v[0], aMin[0], aMax[0]);
  450. result[1] := ClampVal(v[1], aMin[1], aMax[1]);
  451. end;
  452. class function TgluVectorHelperF.Clamp(const v, aMin, aMax: TVector3): TVector3;
  453. begin
  454. result[0] := ClampVal(v[0], aMin[0], aMax[0]);
  455. result[1] := ClampVal(v[1], aMin[1], aMax[1]);
  456. result[2] := ClampVal(v[2], aMin[2], aMax[2]);
  457. end;
  458. class function TgluVectorHelperF.Clamp(const v, aMin, aMax: TVector4): TVector4;
  459. begin
  460. result[0] := ClampVal(v[0], aMin[0], aMax[0]);
  461. result[1] := ClampVal(v[1], aMin[1], aMax[1]);
  462. result[2] := ClampVal(v[2], aMin[2], aMax[2]);
  463. result[3] := ClampVal(v[3], aMin[3], aMax[3]);
  464. end;
  465. class function TgluVectorHelperF.Clamp(const v: TVector2; const aMin, aMax: T): TVector2;
  466. begin
  467. result[0] := ClampVal(v[0], aMin, aMax);
  468. result[1] := ClampVal(v[1], aMin, aMax);
  469. end;
  470. class function TgluVectorHelperF.Clamp(const v: TVector3; const aMin, aMax: T): TVector3;
  471. begin
  472. result[0] := ClampVal(v[0], aMin, aMax);
  473. result[1] := ClampVal(v[1], aMin, aMax);
  474. result[2] := ClampVal(v[2], aMin, aMax);
  475. end;
  476. class function TgluVectorHelperF.Clamp(const v: TVector4; const aMin, aMax: T): TVector4;
  477. begin
  478. result[0] := ClampVal(v[0], aMin, aMax);
  479. result[1] := ClampVal(v[1], aMin, aMax);
  480. result[2] := ClampVal(v[2], aMin, aMax);
  481. end;
  482. end.