-
Notifications
You must be signed in to change notification settings - Fork 13
/
Copy pathmath.inc
176 lines (156 loc) · 5.07 KB
/
math.inc
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
/**
* Some math-related functions.
*/
#if defined __stocksoup_math_included
#endinput
#endif
#define __stocksoup_math_included
/**
* Linearly interpolates float across (a, b).
*/
stock float LerpFloat(float flPercent, float a, float b) {
return a + ((b - a) * flPercent);
}
/**
* Returns a value such that the distance between it to `c` and `d` is respectively proportional
* to the distance of `i` to `a` and `b`. If `clamp` is true, then the returned value will be
* between `c` and `d`.
*
* Special case: If `a == b`, `c` will be returned if `i <= a`, `d` will be returned if
* `i > a`. The value will always be clamped.
*
* @param i Input value.
* @param a Input bound value.
* @param b Input bound value.
* @param c Output bound value corresponding to `a`.
* @param d Output bound value corresponding to `b`.
* @param clamp If set, the returned value is clamped to be between `c` and `d`.
*/
float RemapValueFloatEx(float i, float a, float b, float c, float d, bool clamp = false) {
if (a == b) {
return i > b ? d : c;
}
float result = c + (d - c) * (i - a) / (b - a);
if (clamp) {
return ClampFloat(result, c, d);
}
return result;
}
/**
* Scales the difference between `initial` to `current` by a factor of `scale`.
* Completely missed the fact that LerpFloat does the same thing; this is now just present for
* backwards compatibility.
*/
#pragma deprecated This is literally just LerpFloat with a different name and argument order
stock float ScaleDifference(float current, float initial, float scale) {
return LerpFloat(scale, initial, current);
}
/**
* Clamps the given value to between min / max.
*/
stock float ClampFloat(float value, float min, float max) {
if (value > max) {
return max;
} else if (value < min) {
return min;
}
return value;
}
/**
* Returns a normalized angle between [-180.0, 180).
*/
stock float NormalizeAngle(float value) {
// https://stackoverflow.com/a/43780476
return value - 360.0 * RoundToFloor((value + 180.0) / 360.0);
}
/**
* Converts a signed 8-bit value into a signed 32-bit value.
* Any higher bits set will be ignored and replaced accordingly.
*/
stock int SignExtendInt8(int byte) {
return (byte >> 7 & 1)? 0xFFFFFF00 | byte : 0x000000FF & byte;
}
/**
* Converts a signed 16-bit value into a signed 32-bit value.
* Any higher bits set will be ignored and replaced accordingly.
*/
stock int SignExtendInt16(int word) {
return (word >> 15 & 1)? 0xFFFF0000 | word : 0x0000FFFF & word;
}
/**
* The double values below can be represented by the following enum struct:
*
* enum struct Double {
* int low;
* int high;
* }
*/
/**
* Performs a double conversion to a float value.
* Lower 32 bits of the double should be in index zero.
*/
stock float DoubleToFloat(const int dblVal[2], bool clamp = false) {
int sign = (dblVal[1] >> 31) & 1;
// extract truncated mantissa from both cells
int mantissa = ((dblVal[1] << 3) & 0x007FFFFF) | (dblVal[0] >> 29);
int expdbl_2 = (dblVal[1] >> 20) & 0x7FF;
int expflt_2 = (expdbl_2 - 1023) + 127;
if (expdbl_2 == 0x7FF) {
// special case: infinity or subnormal
expflt_2 = 0xFF;
mantissa = (mantissa || dblVal[0]);
} else if (expdbl_2 == 0) {
// special case: no exponent
expflt_2 = 0;
} else if (expflt_2 > 0xFE) {
// case: exponent is larger than can be represented
// TODO test case for smaller exponent values
if (!clamp) {
ThrowError("Double value %08x%08x is outside of float value range", dblVal[1], dblVal[0]);
}
expflt_2 = 0xFE;
mantissa = 0x007FFFFFF;
}
return view_as<float>((sign << 31) | (expflt_2 << 23) | (mantissa & 0x007FFFFF));
}
/**
* Performs a float conversion to a double value.
* Lower bits of the double in index zero.
*/
stock void FloatToDouble(float flValue, int dblVal[2]) {
int bytesFloat = view_as<int>(flValue);
int sign = (bytesFloat >> 31) & 1;
int exp_2 = (bytesFloat >> 23) & 0xFF;
int mantissa = bytesFloat & 0x007FFFFF;
int expdbl_2 = (1023 + (exp_2 - 127)) & 0x7FF;
if (exp_2 == 0xFF) {
// special case: infinity or subnormal
expdbl_2 = 0x7FF;
} else if (exp_2 == 0) {
// special case: no exponent
expdbl_2 = 0;
}
// no bits in lower three bytes of double
dblVal[0] = (mantissa << 29);
dblVal[1] = (sign << 31) | (expdbl_2 << 20) | (mantissa >> 3);
}
/**
* Returns a vector containing the midpoint between two points.
*/
stock void GetCenterFromPoints(const float pt1[3], const float pt2[3], float center[3]) {
center[0] = pt1[0] + pt2[0] / 2.0;
center[1] = pt1[1] + pt2[1] / 2.0;
center[2] = pt1[2] + pt2[2] / 2.0;
}
/**
* Calculates the width of the forward view cone as a dot product result from the given angle.
* This manually calculates the value of CBaseCombatCharacter's `m_flFieldOfView` data property.
*
* For reference: https://github.com/ValveSoftware/source-sdk-2013/blob/master/sp/src/game/server/hl2/npc_bullseye.cpp#L151
*
* @param angle The FOV value in degree
* @return Width of the forward view cone as a dot product result
*/
stock float GetFOVDotProduct(float angle) {
return Cosine(DegToRad(angle) / 2.0);
}