src/common/math.odin
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 |
package common
import "core:fmt"
import "core:math"
FRAC_BITS : u64 : 31
FRAC_BIT_MASK : iFP : 0x7FFFFFFF
INT_BITS : u64 : 32
FP_ONE :: f32(1 << FRAC_BITS)
DB_ONE :: f64(1 << FRAC_BITS)
TOLERENCE : iFP : 21474
METER : iFP : 2147483648
TWO_METER : iFP : 4294967296
FOUR_METER : iFP : 8589934592
INF : iFP : 0x7FFFFFFFFFFFFFFF
SQRT2 : iFP : 3037000448
BOX_NORMALS := [6][3]iFP {
[3]iFP{METER,0,0},
[3]iFP{-METER,0,0},
[3]iFP{0,METER,0},
[3]iFP{0,-METER,0},
[3]iFP{0,0,METER},
[3]iFP{0,0,-METER},
}
iFP :: distinct i64
Plane :: struct {
normal: [3]iFP,
center: [3]iFP,
}
PlaneSide :: enum {
OUTSIDE,
INSIDE
}
FloatToInt :: proc(f: f32) -> iFP {
intComponent := iFP(f)
fracComponent := f-f32(intComponent)
result := intComponent << FRAC_BITS
result += iFP(fracComponent * FP_ONE)
return result
}
DoubleToInt :: proc(f: f64) -> iFP {
intComponent := iFP(f)
fracComponent := f-f64(intComponent)
result := intComponent << FRAC_BITS
result += iFP(fracComponent * DB_ONE)
return result
}
IntToFloat :: proc(i: iFP) -> f32 {
intPart := f32(i >> FRAC_BITS)
fracPart := f32(i & FRAC_BIT_MASK)/FP_ONE
return intPart+fracPart
}
ToFloatVector :: proc(vec: [3]iFP) -> [3]f32 {
vecFloat :[3]f32
for x,i in vec do vecFloat[i] = IntToFloat(x)
return vecFloat
}
ToIntVector :: proc(vec: [3]f32) -> [3]iFP {
vecInt : [3]iFP
for x,i in vec do vecInt[i] = FloatToInt(x)
return vecInt
}
Mul :: proc(i1: iFP, i2: iFP) -> iFP {
intPart1 := i1 >> FRAC_BITS
intPart2 := i2 >> FRAC_BITS
fracPart1 := i1 & FRAC_BIT_MASK
fracPart2 := i2 & FRAC_BIT_MASK
result: iFP = 0
result += (intPart1*intPart2) << FRAC_BITS
result += (intPart1*fracPart2)
result += (fracPart1*intPart2)
result += ((fracPart1*fracPart2) >> FRAC_BITS) & FRAC_BIT_MASK
return result
}
Div :: proc(n: iFP, d: iFP) -> iFP {
one := iFP(1 << (FRAC_BITS+INT_BITS-1))
reciprocal: iFP = (one/d)
return Mul(n,reciprocal)
}
VecMul :: proc(vec: [3]iFP, sc: iFP) -> [3]iFP {
vecNew : [3]iFP
for x,i in vec do vecNew[i] = Mul(x,sc)
return vecNew
}
VecDiv :: proc(vec: [3]iFP, sc: iFP) -> [3]iFP {
vecNew : [3]iFP
for x,i in vec do vecNew[i] = Div(x,sc)
return vecNew
}
InvSqrt :: proc(x: iFP) -> iFP {
xf :f32 = IntToFloat(x)
if xf <= 0.0 do return 0
yf :f32 = 1.0 / math.sqrt(xf)
y0 := FloatToInt(yf)
y1 := Div((Mul(x,Mul(y0,Mul(y0,y0))) + y0),FloatToInt(2.0))
for math.abs(y1-y0) > TOLERENCE {
y0 = y1
y1 = Div((Mul(x,Mul(y0,Mul(y0,y0))) - y0),FloatToInt(2.0))
}
return y1
}
CrossProduct :: proc(v1: [3]iFP, v2: [3]iFP) -> [3]iFP {
return [3]iFP{
Mul(v1[1],v2[2]) - Mul(v1[2],v2[1]),
Mul(v1[2],v2[0]) - Mul(v1[0],v2[2]),
Mul(v1[0],v2[1]) - Mul(v1[1],v2[0]),
}
}
DotProduct :: proc(v1: [3]iFP, v2: [3]iFP) -> iFP {
return Mul(v1[0],v2[0])+Mul(v1[1],v2[1])+Mul(v1[2],v2[2])
}
Normalize :: proc(vec: [3]iFP) -> [3]iFP {
return VecMul(vec,InvSqrt(DotProduct(vec,vec)))
}
PointInsidePlane :: proc(point: [3]iFP, plane: Plane) -> PlaneSide {
if DotProduct(point-plane.center,plane.normal) > 0 do return PlaneSide.OUTSIDE
else do return PlaneSide.INSIDE
}
LinePlaneIntersection :: proc(origin: [3]iFP, target: [3]iFP, plane: Plane) -> ([3]iFP, bool) {
denom: iFP = DotProduct(Normalize(target-origin),plane.normal)
if denom == 0 {
return origin, false
}
return VecMul(Normalize(target-origin),Div(DotProduct(plane.center-origin,plane.normal),denom)) + origin, true
}
|