#if !defined(DQN_NO_MATH) // NOTE: [$MATH] Math ============================================================================== DQN_API Dqn_V2I Dqn_V2ToV2I(Dqn_V2 a) { Dqn_V2I result = Dqn_V2I(DQN_CAST(int32_t)a.x, DQN_CAST(int32_t)a.y); return result; } DQN_API Dqn_V2 Dqn_V2Min(Dqn_V2 a, Dqn_V2 b) { Dqn_V2 result = Dqn_V2(DQN_MIN(a.x, b.x), DQN_MIN(a.y, b.y)); return result; } DQN_API Dqn_V2 Dqn_V2Max(Dqn_V2 a, Dqn_V2 b) { Dqn_V2 result = Dqn_V2(DQN_MAX(a.x, b.x), DQN_MAX(a.y, b.y)); return result; } DQN_API Dqn_V2 Dqn_V2Abs(Dqn_V2 a) { Dqn_V2 result = Dqn_V2(DQN_ABS(a.x), DQN_ABS(a.y)); return result; } DQN_API Dqn_f32 Dqn_V2Dot(Dqn_V2 a, Dqn_V2 b) { Dqn_f32 result = (a.x * b.x) + (a.y * b.y); return result; } DQN_API Dqn_f32 Dqn_V2LengthSq(Dqn_V2 a, Dqn_V2 b) { Dqn_f32 x_side = b.x - a.x; Dqn_f32 y_side = b.y - a.y; Dqn_f32 result = DQN_SQUARED(x_side) + DQN_SQUARED(y_side); return result; } DQN_API Dqn_V2 Dqn_V2Normalise(Dqn_V2 a) { Dqn_f32 length_sq = DQN_SQUARED(a.x) + DQN_SQUARED(a.y); Dqn_f32 length = DQN_SQRTF(length_sq); Dqn_V2 result = a / length; return result; } DQN_API Dqn_V2 Dqn_V2Perpendicular(Dqn_V2 a) { Dqn_V2 result = Dqn_V2(-a.y, a.x); return result; } // NOTE: Dqn_V3 Implementation // ------------------------------------------------------------------------------------------------- DQN_API Dqn_f32 Dqn_V3LengthSq(Dqn_V3 a) { Dqn_f32 result = DQN_SQUARED(a.x) + DQN_SQUARED(a.y) + DQN_SQUARED(a.z); return result; } DQN_API Dqn_f32 Dqn_V3Length(Dqn_V3 a) { Dqn_f32 length_sq = DQN_SQUARED(a.x) + DQN_SQUARED(a.y) + DQN_SQUARED(a.z); Dqn_f32 result = DQN_SQRTF(length_sq); return result; } DQN_API Dqn_V3 Dqn_V3Normalise(Dqn_V3 a) { Dqn_f32 length = Dqn_V3Length(a); Dqn_V3 result = a / length; return result; } // NOTE: Dqn_V4 Implementation // ------------------------------------------------------------------------------------------------- DQN_API Dqn_f32 Dqn_V4Dot(Dqn_V4 a, Dqn_V4 b) { Dqn_f32 result = (a.x * b.x) + (a.y * b.y) + (a.z * b.z) + (a.w * b.w); return result; } // NOTE: Dqn_M4 Implementation // ------------------------------------------------------------------------------------------------- DQN_API Dqn_M4 Dqn_M4_Identity() { Dqn_M4 result = {{ {1, 0, 0, 0}, {0, 1, 0, 0}, {0, 0, 1, 0}, {0, 0, 0, 1}, }}; return result; } DQN_API Dqn_M4 Dqn_M4_ScaleF(Dqn_f32 x, Dqn_f32 y, Dqn_f32 z) { Dqn_M4 result = {{ {x, 0, 0, 0}, {0, y, 0, 0}, {0, 0, z, 0}, {0, 0, 0, 1}, }}; return result; } DQN_API Dqn_M4 Dqn_M4_Scale(Dqn_V3 xyz) { Dqn_M4 result = {{ {xyz.x, 0, 0, 0}, {0, xyz.y, 0, 0}, {0, 0, xyz.z, 0}, {0, 0, 0, 1}, }}; return result; } DQN_API Dqn_M4 Dqn_M4_TranslateF(Dqn_f32 x, Dqn_f32 y, Dqn_f32 z) { Dqn_M4 result = {{ {1, 0, 0, 0}, {0, 1, 0, 0}, {0, 0, 1, 0}, {x, y, z, 1}, }}; return result; } DQN_API Dqn_M4 Dqn_M4_Translate(Dqn_V3 xyz) { Dqn_M4 result = {{ {1, 0, 0, 0}, {0, 1, 0, 0}, {0, 0, 1, 0}, {xyz.x, xyz.y, xyz.z, 1}, }}; return result; } DQN_API Dqn_M4 Dqn_M4_Transpose(Dqn_M4 mat) { Dqn_M4 result; for (int col = 0; col < 4; col++) for (int row = 0; row < 4; row++) result.columns[col][row] = mat.columns[row][col]; return result; } DQN_API Dqn_M4 Dqn_M4_Rotate(Dqn_V3 axis01, Dqn_f32 radians) { DQN_ASSERTF(DQN_ABS(Dqn_V3Length(axis01) - 1.f) <= 0.01f, "Rotation axis must be normalised, length = %f", Dqn_V3Length(axis01)); Dqn_f32 sin = DQN_SINF(radians); Dqn_f32 cos = DQN_COSF(radians); Dqn_f32 one_minus_cos = 1.f - cos; Dqn_f32 x = axis01.x; Dqn_f32 y = axis01.y; Dqn_f32 z = axis01.z; Dqn_f32 x2 = DQN_SQUARED(x); Dqn_f32 y2 = DQN_SQUARED(y); Dqn_f32 z2 = DQN_SQUARED(z); Dqn_M4 result = {{ {cos + x2*one_minus_cos, y*x*one_minus_cos + z*sin, z*x*one_minus_cos - y*sin, 0}, // Col 1 {x*y*one_minus_cos - z*sin, cos + y2*one_minus_cos, z*y*one_minus_cos + x*sin, 0}, // Col 2 {x*z*one_minus_cos + y*sin, y*z*one_minus_cos - x*sin, cos + z2*one_minus_cos, 0}, // Col 3 {0, 0, 0, 1}, // Col 4 }}; return result; } DQN_API Dqn_M4 Dqn_M4_Orthographic(Dqn_f32 left, Dqn_f32 right, Dqn_f32 bottom, Dqn_f32 top, Dqn_f32 z_near, Dqn_f32 z_far) { // NOTE: Here is the matrix in column major for readability. Below it's // transposed due to how you have to declare column major matrices in C/C++. // // m = [2/r-l, 0, 0, -1*(r+l)/(r-l)] // [0, 2/t-b, 0, 1*(t+b)/(t-b)] // [0, 0, -2/f-n, -1*(f+n)/(f-n)] // [0, 0, 0, 1 ] Dqn_M4 result = {{ {2.f / (right - left), 0.f, 0.f, 0.f}, {0.f, 2.f / (top - bottom), 0.f, 0.f}, {0.f, 0.f, -2.f / (z_far - z_near), 0.f}, {(-1.f * (right + left)) / (right - left), (-1.f * (top + bottom)) / (top - bottom), (-1.f * (z_far + z_near)) / (z_far - z_near), 1.f}, }}; return result; } DQN_API Dqn_M4 Dqn_M4_Perspective(Dqn_f32 fov /*radians*/, Dqn_f32 aspect, Dqn_f32 z_near, Dqn_f32 z_far) { Dqn_f32 tan_fov = DQN_TANF(fov / 2.f); Dqn_M4 result = {{ {1.f / (aspect * tan_fov), 0.f, 0.f, 0.f}, {0, 1.f / tan_fov, 0.f, 0.f}, {0.f, 0.f, (z_near + z_far) / (z_near - z_far), -1.f}, {0.f, 0.f, (2.f * z_near * z_far)/(z_near - z_far), 0.f}, }}; return result; } DQN_API Dqn_M4 Dqn_M4_Add(Dqn_M4 lhs, Dqn_M4 rhs) { Dqn_M4 result; for (int col = 0; col < 4; col++) { for (int it = 0; it < 4; it++) result.columns[col][it] = lhs.columns[col][it] + rhs.columns[col][it]; } return result; } DQN_API Dqn_M4 Dqn_M4_Sub(Dqn_M4 lhs, Dqn_M4 rhs) { Dqn_M4 result; for (int col = 0; col < 4; col++) { for (int it = 0; it < 4; it++) result.columns[col][it] = lhs.columns[col][it] - rhs.columns[col][it]; } return result; } DQN_API Dqn_M4 Dqn_M4_Mul(Dqn_M4 lhs, Dqn_M4 rhs) { Dqn_M4 result; for (int col = 0; col < 4; col++) { for (int row = 0; row < 4; row++) { Dqn_f32 sum = 0; for (int f32_it = 0; f32_it < 4; f32_it++) sum += lhs.columns[f32_it][row] * rhs.columns[col][f32_it]; result.columns[col][row] = sum; } } return result; } DQN_API Dqn_M4 Dqn_M4_Div(Dqn_M4 lhs, Dqn_M4 rhs) { Dqn_M4 result; for (int col = 0; col < 4; col++) { for (int it = 0; it < 4; it++) result.columns[col][it] = lhs.columns[col][it] / rhs.columns[col][it]; } return result; } DQN_API Dqn_M4 Dqn_M4_AddF(Dqn_M4 lhs, Dqn_f32 rhs) { Dqn_M4 result; for (int col = 0; col < 4; col++) { for (int it = 0; it < 4; it++) result.columns[col][it] = lhs.columns[col][it] + rhs; } return result; } DQN_API Dqn_M4 Dqn_M4_SubF(Dqn_M4 lhs, Dqn_f32 rhs) { Dqn_M4 result; for (int col = 0; col < 4; col++) { for (int it = 0; it < 4; it++) result.columns[col][it] = lhs.columns[col][it] - rhs; } return result; } DQN_API Dqn_M4 Dqn_M4_MulF(Dqn_M4 lhs, Dqn_f32 rhs) { Dqn_M4 result; for (int col = 0; col < 4; col++) { for (int it = 0; it < 4; it++) result.columns[col][it] = lhs.columns[col][it] * rhs; } return result; } DQN_API Dqn_M4 Dqn_M4_DivF(Dqn_M4 lhs, Dqn_f32 rhs) { Dqn_M4 result; for (int col = 0; col < 4; col++) { for (int it = 0; it < 4; it++) result.columns[col][it] = lhs.columns[col][it] / rhs; } return result; } #if !defined(DQN_NO_FSTRING8) DQN_API Dqn_FString8<256> Dqn_M4_ColumnMajorString(Dqn_M4 mat) { Dqn_FString8<256> result = {}; for (int row = 0; row < 4; row++) { for (int it = 0; it < 4; it++) { if (it == 0) Dqn_FString8_Append(&result, DQN_STRING8("|")); Dqn_FString8_AppendF(&result, "%.5f", mat.columns[it][row]); if (it != 3) Dqn_FString8_Append(&result, DQN_STRING8(", ")); else Dqn_FString8_Append(&result, DQN_STRING8("|\n")); } } return result; } #endif // NOTE: Dqn_Rect // ------------------------------------------------------------------------------------------------- DQN_API Dqn_Rect Dqn_Rect_InitFromPosAndSize(Dqn_V2 pos, Dqn_V2 size) { Dqn_Rect result = {}; result.min = pos; if (size.x < 0) result.min.x -= size.x; if (size.y < 0) result.min.y -= size.y; result.max = result.min + Dqn_V2Abs(size); return result; } DQN_API Dqn_V2 Dqn_Rect_Center(Dqn_Rect rect) { Dqn_V2 size = rect.max - rect.min; Dqn_V2 result = rect.min + (size * 0.5f); return result; } DQN_API bool Dqn_Rect_ContainsPoint(Dqn_Rect rect, Dqn_V2 p) { bool result = (p.x >= rect.min.x && p.x <= rect.max.x && p.y >= rect.min.y && p.y <= rect.max.y); return result; } DQN_API bool Dqn_Rect_ContainsRect(Dqn_Rect a, Dqn_Rect b) { bool result = (b.min >= a.min && b.max <= a.max); return result; } DQN_API Dqn_V2 Dqn_Rect_Size(Dqn_Rect rect) { Dqn_V2 result = rect.max - rect.min; return result; } DQN_API Dqn_Rect Dqn_Rect_Move(Dqn_Rect src, Dqn_V2 move_amount) { Dqn_Rect result = src; result.min += move_amount; result.max += move_amount; return result; } DQN_API Dqn_Rect Dqn_Rect_MoveTo(Dqn_Rect src, Dqn_V2 dest) { Dqn_V2 move_amount = dest - src.min; Dqn_Rect result = src; result.min += move_amount; result.max += move_amount; return result; } DQN_API bool Dqn_Rect_Intersects(Dqn_Rect a, Dqn_Rect b) { bool result = (a.min.x <= b.max.x && a.max.x >= b.min.x) && (a.min.y <= b.max.y && a.max.y >= b.min.y); return result; } DQN_API Dqn_Rect Dqn_Rect_Intersection(Dqn_Rect a, Dqn_Rect b) { Dqn_Rect result = {}; if (Dqn_Rect_Intersects(a, b)) { result.min.x = DQN_MAX(a.min.x, b.min.x); result.min.y = DQN_MAX(a.min.y, b.min.y); result.max.x = DQN_MIN(a.max.x, b.max.x); result.max.y = DQN_MIN(a.max.y, b.max.y); } return result; } DQN_API Dqn_Rect Dqn_Rect_Union(Dqn_Rect a, Dqn_Rect b) { Dqn_Rect result = {}; result.min.x = DQN_MIN(a.min.x, b.min.x); result.min.y = DQN_MIN(a.min.y, b.min.y); result.max.x = DQN_MAX(a.max.x, b.max.x); result.max.y = DQN_MAX(a.max.y, b.max.y); return result; } DQN_API Dqn_Rect Dqn_Rect_FromRectI32(Dqn_RectI32 a) { Dqn_Rect result = Dqn_Rect(a.min, a.max); return result; } DQN_API Dqn_V2I Dqn_RectI32_Size(Dqn_RectI32 rect) { Dqn_V2I result = rect.max - rect.min; return result; } // NOTE: Math Utils // ------------------------------------------------------------------------------------------------- DQN_API Dqn_V2 Dqn_Lerp_V2(Dqn_V2 a, Dqn_f32 t, Dqn_V2 b) { Dqn_V2 result = {}; result.x = a.x + ((b.x - a.x) * t); result.y = a.y + ((b.y - a.y) * t); return result; } DQN_API Dqn_f32 Dqn_Lerp_F32(Dqn_f32 a, Dqn_f32 t, Dqn_f32 b) { Dqn_f32 result = a + ((b - a) * t); return result; } #endif // !defined(DQN_NO_MATH)