/* HandmadeMath.h v0.2 This is a single header file with a bunch of useful functions for basic game math operations. ========================================================================== You MUST #define HANDMADE_MATH_IMPLEMENTATION in EXACTLY one C or C++ file that includes this header, BEFORE the include, like this: #define HANDMADE_MATH_IMPLEMENTATION #include "HandmadeMath.h" All other files should just #include "HandmadeMath.h" without the #define. ========================================================================== For overloaded, and operator overloaded versions of the base C functions. You MUST #define HANDMADE_MATH_CPP_MODE in EXACTLY one C or C++ file that includes this header, BEFORE the include, like this: #define HANDMADE_MATH_IMPLEMENTATION #define HANDMADE_MATH_CPP_MODE #include "HandmadeMath.h" All other files should just #include "HandmadeMath.h" without the #define. ========================================================================== Version History: 0.2 (*) Updated documentation () Better C compliance () Prefix all handmade math functions () Remove use of math.h () Better operator overloading LICENSE This software is in the public domain. Where that dedication is not recognized, you are granted a perpetual, irrevocable license to copy, distribute, and modify this file as you see fit. CREDITS Written by Zakary Strange (zak@handmade.network && @strangezak) Functionality: Matt Mascarenhas (@miblo_) Aleph FieryDrake (@fierydrake) Fixes: Jeroen van Rijn (@J_vanRijn) Kiljacken (@Kiljacken) Insofaras (@insofaras) */ #ifndef HANDMADE_MATH_H #define HANDMADE_MATH_H #include // TODO(zak): Remove this later on #ifdef __cplusplus extern "C" { #endif #ifdef HANDMADEMATH_STATIC #define HMMDEF static #else #define HMMDEF extern #endif #if _MSC_VER && !__INTEL_COMPILER #define HINLINE __inline #else #define HINLINE inline #endif #define Pi32 3.14159265359f #define HMM_PI 3.14159265358979323846 #define MIN(a, b) (a) > (b) ? (b) : (a) #define MAX(a, b) (a) < (b) ? (b) : (a) #define ABS(a) (a) < 0 ? -(a) : (a) #define MOD(a, m) ((a) % (m)) >= 0 ? ((a) % (m)) : (((a) % (m)) + (m)) #define Square(x) ((x) * (x)) typedef union vec2 { struct { float X, Y; }; struct { float U, V; }; struct { float Left, Right; }; float Elements[2]; } vec2; typedef union vec3 { struct { float X, Y, Z; }; struct { float U, V, W; }; struct { float R, G, B; }; struct { vec2 XY; float Ignored0_; }; struct { float Ignored1_; vec2 YZ; }; struct { vec2 UV; float Ignored2_; }; struct { float Ignored3_; vec2 VW; }; float Elements[3]; } vec3; typedef union vec4 { struct { union { vec3 XYZ; struct { float X, Y, Z; }; }; float W; }; struct { union { vec3 RGB; struct { float R, G, B; }; }; float A; }; struct { vec2 XY; float Ignored0_; float Ignored1_; }; struct { float Ignored2_; vec2 YZ; float Ignored3_; }; struct { float Ignored4_; float Ignored5_; vec2 ZW; }; float Elements[4]; } vec4; typedef union mat4 { float Elements[4][4]; } mat4; typedef vec2 v2; typedef vec3 v3; typedef vec4 v4; typedef mat4 m4; HMMDEF float ToRadians(float Degrees); HMMDEF float Inner(vec3 A, vec3 B); HMMDEF float SquareRoot(float Float); HMMDEF float LengthSquareRoot(vec3 A); HMMDEF float Length(vec3 A); HMMDEF float Power(float Base, int Exponent); HMMDEF float Clamp(float Min, float Value, float Max); HMMDEF vec3 Normalize(vec3 A); HMMDEF vec3 Cross(vec3 VecOne, vec3 VecTwo); HMMDEF float Dot(vec3 VecOne, vec3 VecTwo); HMMDEF vec2 Vec2i(int X, int Y); HMMDEF vec2 Vec2(float X, float Y); HMMDEF vec3 Vec3(float X, float Y, float Z); HMMDEF vec3 Vec3i(int X, int Y, int Z); HMMDEF vec4 Vec4(float X, float Y, float Z, float W); HMMDEF vec4 Vec4i(int X, int Y, int Z, int W); HMMDEF vec2 AddVec2(vec2 Left, vec2 Right); HMMDEF vec3 AddVec3(vec3 Left, vec3 Right); HMMDEF vec4 AddVec4(vec4 Left, vec4 Right); HMMDEF vec2 SubtractVec2(vec2 Left, vec2 Right); HMMDEF vec3 SubtractVec3(vec3 Left, vec3 Right); HMMDEF vec4 SubtractVec4(vec4 Left, vec4 Right); HMMDEF vec2 MultiplyVec2(vec2 Left, vec2 Right); HMMDEF vec3 MultiplyVec3(vec3 Left, vec3 Right); HMMDEF vec4 MultiplyVec4(vec4 Left, vec4 Right); HMMDEF vec2 DivideVec2(vec2 Left, vec2 Right); HMMDEF vec3 DivideVec3(vec3 Left, vec3 Right); HMMDEF vec4 DivideVec4(vec4 Left, vec4 Right); HMMDEF mat4 Mat4(void); HMMDEF mat4 Mat4d(float Diagonal); HMMDEF mat4 MultiplyMat4(mat4 Left, mat4 Right); HMMDEF mat4 Orthographic(float Left, float Right, float Bottom, float Top, float Near, float Far); HMMDEF mat4 Perspective(float FOV, float AspectRatio, float Near, float Far); HMMDEF mat4 Translate(vec3 Translation); HMMDEF mat4 Rotate(float Angle, vec3 Axis); HMMDEF mat4 Scale(vec3 Scale); HMMDEF mat4 LookAt(vec3 Eye, vec3 Center, vec3 Up); #ifdef __cplusplus } #endif #ifdef HANDMADE_MATH_CPP_MODE HMMDEF vec2 Add(int X, int Y); HMMDEF vec3 Add(int X, int Y, int Z); HMMDEF vec4 Add(int X, int Y, int Z, int W); HMMDEF vec2 Subtract(int X, int Y); HMMDEF vec3 Subtract(int X, int Y, int Z); HMMDEF vec4 Subtract(int X, int Y, int Z, int W); HMMDEF vec2 Multiply(int X, int Y); HMMDEF vec3 Multiply(int X, int Y, int Z); HMMDEF vec4 Multiply(int X, int Y, int Z, int W); HMMDEF mat4 Multiply(mat4 Left, mat4 Right); HMMDEF vec2 Divide(int X, int Y); HMMDEF vec3 Divide(int X, int Y, int Z); HMMDEF vec4 Divide(int X, int Y, int Z, int W); HMMDEF vec2 operator+(vec2 Left, vec2 Right); HMMDEF vec3 operator+(vec3 Left, vec3 Right); HMMDEF vec4 operator+(vec4 Left, vec4 Right); HMMDEF vec2 operator-(vec2 Left, vec2 Right); HMMDEF vec3 operator-(vec3 Left, vec3 Right); HMMDEF vec4 operator-(vec4 Left, vec4 Right); HMMDEF vec2 operator*(vec2 Left, vec2 Right); HMMDEF vec3 operator*(vec3 Left, vec3 Right); HMMDEF vec4 operator*(vec4 Left, vec4 Right); HMMDEF mat4 operator*(mat4 Left, mat4 Right); HMMDEF vec3 operator*(vec3 Left, float Right); HMMDEF vec2 operator*(vec2 Left, float Right); HMMDEF vec2 operator/(vec2 Left, vec2 Right); HMMDEF vec3 operator/(vec3 Left, vec3 Right); HMMDEF vec4 operator/(vec4 Left, vec4 Right); #endif /* HANDMADE_MATH_CPP */ #endif /* HANDMADE_MATH_H */ #ifdef HANDMADE_MATH_IMPLEMENTATION HINLINE float ToRadians(float Degrees) { float Result = Degrees * (Pi32 / 180.0f); return (Result); } HINLINE float Inner(vec3 A, vec3 B) { float Result = A.X * B.X + A.Y * B.Y + A.Z * B.Z; return (Result); } HINLINE float SquareRoot(float Float) { float Result = sqrtf(Float); return (Result); } HINLINE float LengthSquareRoot(vec3 A) { float Result = Inner(A, A); return (Result); } HINLINE float Length(vec3 A) { float Result = SquareRoot(LengthSquareRoot(A)); return (Result); } HINLINE float Power(float Base, int Exponent) { float Result = 1; if(Exponent > 0) { int i; for(i = 0; i < Exponent; ++i) { Result *= Base; } } else { int i; for(i = 0; i > Exponent; --i) { Result /= Base; } } return (Result); } HINLINE float Lerp(float A, float Time, float B) { float Result = (1.0f - Time) * A + Time * B; return (Result); } HINLINE float Clamp(float Min, float Value, float Max) { float Result = Value; if(Result < Min) { Result = Min; } else if(Result > Max) { Result = Max; } return (Result); } HINLINE vec3 Normalize(vec3 A) { vec3 Result = {0}; Result.X = A.X * (1.0f / Length(A)); Result.Y = A.Y * (1.0f / Length(A)); Result.Z = A.Z * (1.0f / Length(A)); return (Result); } HINLINE vec3 Cross(vec3 VecOne, vec3 VecTwo) { vec3 Result; Result.X = (VecOne.Y * VecTwo.Z) - (VecOne.Z * VecTwo.Y); Result.Y = (VecOne.Z * VecTwo.X) - (VecOne.X * VecTwo.Z); Result.Z = (VecOne.X * VecTwo.Y) - (VecOne.Y * VecTwo.X); return (Result); } HINLINE float Dot(vec3 VecOne, vec3 VecTwo) { float Result = 0; Result = (VecOne.X * VecTwo.X) + (VecOne.Y * VecTwo.Y) + (VecOne.Z * VecTwo.Z); return (Result); } HINLINE vec2 Vec2(float X, float Y) { vec2 Result; Result.X = X; Result.Y = Y; return (Result); } HINLINE vec2 Vec2i(int X, int Y) { vec2 Result; Result.X = (float)X; Result.Y = (float)Y; return (Result); } HINLINE vec3 Vec3(float X, float Y, float Z) { vec3 Result; Result.X = X; Result.Y = Y; Result.Z = Z; return (Result); } HINLINE vec3 Vec3i(int X, int Y, int Z) { vec3 Result; Result.X = (float)X; Result.Y = (float)Y; Result.Z = (float)Z; return (Result); } HINLINE vec4 Vec4(float X, float Y, float Z, float W) { vec4 Result; Result.X = X; Result.Y = Y; Result.Z = Z; Result.W = W; return (Result); } HINLINE vec4 Vec4i(int X, int Y, int Z, int W) { vec4 Result; Result.X = (float)X; Result.Y = (float)Y; Result.Z = (float)Z; Result.W = (float)W; return (Result); } HINLINE vec2 AddVec2(vec2 Left, vec2 Right) { vec2 Result; Result.X = Left.X + Right.X; Result.Y = Left.Y + Right.Y; return (Result); } HINLINE vec3 AddVec3(vec3 Left, vec3 Right) { vec3 Result; Result.X = Left.X + Right.X; Result.Y = Left.Y + Right.Y; Result.Z = Left.Z + Right.Z; return (Result); } HINLINE vec4 AddVec4(vec4 Left, vec4 Right) { vec4 Result; Result.X = Left.X + Right.X; Result.Y = Left.Y + Right.Y; Result.Z = Left.Z + Right.Z; Result.W = Left.W + Right.W; return (Result); } HINLINE vec2 SubtractVec2(vec2 Left, vec2 Right) { vec2 Result; Result.X = Left.X - Right.X; Result.Y = Left.Y - Right.Y; return (Result); } HINLINE vec3 SubtractVec3(vec3 Left, vec3 Right) { vec3 Result; Result.X = Left.X - Right.X; Result.Y = Left.Y - Right.Y; Result.Z = Left.Z - Right.Z; return (Result); } HINLINE vec4 SubtractVec4(vec4 Left, vec4 Right) { vec4 Result; Result.X = Left.X - Right.X; Result.Y = Left.Y - Right.Y; Result.Z = Left.Z - Right.Z; Result.W = Left.W - Right.W; return (Result); } HINLINE vec2 MultiplyVec2(vec2 Left, vec2 Right) { vec2 Result; Result.X = Left.X * Right.X; Result.Y = Left.Y * Right.Y; return (Result); } HINLINE vec3 MultiplyVec3(vec3 Left, vec3 Right) { vec3 Result; Result.X = Left.Z * Right.X; Result.Y = Left.Y * Right.Y; Result.Z = Left.Z * Right.Z; return (Result); } HINLINE vec4 MultiplyVec4(vec4 Left, vec4 Right) { vec4 Result; Result.X = Left.X * Right.X; Result.Y = Left.Y * Right.Y; Result.Z = Left.Z * Right.Z; Result.W = Left.W * Right.W; return (Result); } HINLINE vec2 DivideVec2(vec2 Left, vec2 Right) { vec2 Result; Result.X = Left.X / Right.X; Result.Y = Left.Y / Right.Y; return (Result); } HINLINE vec3 DivideVec3(vec3 Left, vec3 Right) { vec3 Result; Result.X = Left.X / Right.X; Result.Y = Left.Y / Right.Y; Result.Z = Left.Z / Right.Z; return (Result); } HINLINE vec4 DivideVec4(vec4 Left, vec4 Right) { vec4 Result; Result.X = Left.X / Right.X; Result.Y = Left.Y / Right.Y; Result.Z = Left.Z / Right.Z; Result.W = Left.W / Right.W; return (Result); } HINLINE mat4 Mat4() { mat4 Result = {0}; return (Result); } mat4 Mat4d(float Diagonal) { mat4 Result; int Rows; for(Rows = 0; Rows < 4; ++Rows) { int Columns; for(Columns = 0; Columns < 4; ++Columns) { Result.Elements[Rows][Columns] = 0.0f; } } Result.Elements[0][0] = Diagonal; Result.Elements[1][1] = Diagonal; Result.Elements[2][2] = Diagonal; Result.Elements[3][3] = Diagonal; return (Result); } mat4 MultiplyMat4(mat4 Left, mat4 Right) { mat4 Result = Mat4(); int Rows; for(Rows = 0; Rows < 4; ++Rows) { int Columns; for(Columns = 0; Columns < 4; ++Columns) { float Sum = 0; int CurrentMatrice; for(CurrentMatrice = 0; CurrentMatrice < 4; ++CurrentMatrice) { Sum += Right.Elements[Rows][CurrentMatrice] * Left.Elements[CurrentMatrice][Columns]; } Result.Elements[Rows][Columns] = Sum; } } return (Result); } mat4 Orthographic(float Left, float Right, float Bottom, float Top, float Near, float Far) { mat4 Result = Mat4d(1.0f); Result.Elements[0][0] = 2.0f / (Right - Left); Result.Elements[1][1] = 2.0f / (Top - Bottom); Result.Elements[2][2] = 2.0f / (Near - Far); Result.Elements[3][0] = (Left + Right) / (Left - Right); Result.Elements[3][1] = (Bottom + Top) / (Bottom - Top); Result.Elements[3][2] = (Far + Near) / (Near - Far); return (Result); } mat4 Perspective(float FOV, float AspectRatio, float Near, float Far) { mat4 Result = Mat4d(1.0f); Result.Elements[0][0] = 1.0f / (AspectRatio * tanf(FOV / 2.0f)); Result.Elements[1][1] = 1.0f / tanf(FOV / 2.0f); Result.Elements[2][3] = -1.0f; Result.Elements[2][2] = -(Far + Near) / (Far - Near); Result.Elements[3][2] = -(2.0f * Far * Near) / (Far - Near); Result.Elements[3][3] = 0.0f; return (Result); } mat4 Translate(vec3 Translation) { mat4 Result = Mat4d(1.0f); Result.Elements[3][0] = Translation.X; Result.Elements[3][1] = Translation.Y; Result.Elements[3][2] = Translation.Z; return (Result); } mat4 Rotate(float Angle, vec3 Axis) { mat4 Result = Mat4d(1.0f); Result.Elements[0][0] = Axis.X * Axis.X * (1.0f - cosf(ToRadians(Angle))) + cosf(ToRadians(Angle)); Result.Elements[0][1] = Axis.Y * Axis.X * (1.0f - cosf(ToRadians(Angle))) + Axis.Z * (sinf(ToRadians(Angle))); Result.Elements[0][2] = Axis.X * Axis.Z * (1.0f - cosf(ToRadians(Angle))) - Axis.Y * (sinf(ToRadians(Angle))); Result.Elements[1][0] = Axis.X * Axis.Y * (1.0f - cosf(ToRadians(Angle))) - Axis.Z * (sinf(ToRadians(Angle))); Result.Elements[1][1] = Axis.Y * Axis.Y * (1.0f - cosf(ToRadians(Angle))) + (cosf(ToRadians(Angle))); Result.Elements[1][2] = Axis.Y * Axis.Z * (1.0f - cosf(ToRadians(Angle))) + Axis.X * (sinf(ToRadians(Angle))); Result.Elements[2][0] = Axis.X * Axis.Z * (1.0f - cosf(ToRadians(Angle))) + Axis.Y * (sinf(ToRadians(Angle))); Result.Elements[2][1] = Axis.Y * Axis.Z * (1.0f - cosf(ToRadians(Angle))) - Axis.X * (sinf(ToRadians(Angle))); Result.Elements[2][2] = Axis.Z * Axis.Z * (1.0f - cosf(ToRadians(Angle))) * (cosf(ToRadians(Angle))); return (Result); } mat4 LookAt(vec3 Eye, vec3 Center, vec3 Up) { mat4 Result = {0}; vec3 F = Normalize(SubtractVec3(Center, Eye)); vec3 S = Normalize(Cross(F, Up)); vec3 U = Cross(S, F); Result.Elements[0][0] = S.X; Result.Elements[0][1] = U.X; Result.Elements[0][2] = -F.X; Result.Elements[1][0] = S.Y; Result.Elements[1][1] = U.Y; Result.Elements[1][2] = -F.Y; Result.Elements[2][0] = S.Z; Result.Elements[2][1] = U.Z; Result.Elements[2][2] = -F.Z; Result.Elements[3][0] = -Dot(S, Eye); Result.Elements[3][1] = -Dot(U, Eye); Result.Elements[3][2] = Dot(F, Eye); Result.Elements[3][3] = 1.0f; return (Result); } mat4 Scale(vec3 Scale) { mat4 Result = Mat4d(1.0f); Result.Elements[0][0] = Scale.X; Result.Elements[1][1] = Scale.Y; Result.Elements[2][2] = Scale.Z; return (Result); } #ifdef HANDMADE_MATH_CPP_MODE HMMDEF HINLINE vec2 Add(vec2 Left, vec2 Right) { vec2 Result = AddVec2(Left, Right); return (Result); } HMMDEF HINLINE vec3 Add(vec3 Left, vec3 Right) { vec3 Result = AddVec3(Left, Right); return (Result); } HMMDEF HINLINE vec4 Add(vec4 Left, vec4 Right) { vec4 Result = AddVec4(Left, Right); return (Result); } HMMDEF HINLINE vec2 Subtract(vec2 Left, vec2 Right) { vec2 Result = SubtractVec2(Left, Right); return (Result); } HMMDEF HINLINE vec3 Subtract(vec3 Left, vec3 Right) { vec3 Result = SubtractVec3(Left, Right); return (Result); } HMMDEF HINLINE vec4 Subtract(vec4 Left, vec4 Right) { vec4 Result = SubtractVec4(Left, Right); return (Result); } HMMDEF HINLINE vec2 Multiply(vec2 Left, vec2 Right) { vec2 Result = MultiplyVec2(Left, Right); return (Result); } HMMDEF HINLINE vec3 Multiply(vec3 Left, vec3 Right) { vec3 Result = MultiplyVec3(Left, Right); return (Result); } HMMDEF HINLINE vec4 Multiply(vec4 Left, vec4 Right) { vec4 Result = MultiplyVec4(Left, Right); return (Result); } HMMDEF HINLINE mat4 Multiply(mat4 Left, mat4 Right) { mat4 Result = MultiplyMat4(Left, Right); return (Result); } HMMDEF HINLINE vec2 Divide(vec2 Left, vec2 Right) { vec2 Result = DivideVec2(Left, Right); return (Result); } HMMDEF HINLINE vec3 Divide(vec3 Left, vec3 Right) { vec3 Result = DivideVec3(Left, Right); return (Result); } HMMDEF HINLINE vec4 Divide(vec4 Left, vec4 Right) { vec4 Result = DivideVec4(Left, Right); return (Result); } HMMDEF HINLINE vec2 operator+(vec2 Left, vec2 Right) { vec2 Result = Add(Left, Right); return (Result); } HMMDEF HINLINE vec3 operator+(vec3 Left, vec3 Right) { vec3 Result = Add(Left, Right); return (Result); } HMMDEF HINLINE vec4 operator+(vec4 Left, vec4 Right) { vec4 Result = Add(Left, Right); return (Result); } HMMDEF HINLINE vec2 operator-(vec2 Left, vec2 Right) { vec2 Result = Subtract(Left, Right); return (Result); } HMMDEF HINLINE vec3 operator-(vec3 Left, vec3 Right) { vec3 Result = Subtract(Left, Right); return (Result); } HMMDEF HINLINE vec4 operator-(vec4 Left, vec4 Right) { vec4 Result = Subtract(Left, Right); return (Result); } HMMDEF HINLINE vec2 operator*(vec2 Left, vec2 Right) { vec2 Result = Multiply(Left, Right); return (Result); } HMMDEF HINLINE vec3 operator*(vec3 Left, vec3 Right) { vec3 Result = Multiply(Left, Right); return (Result); } HMMDEF HINLINE vec3 operator*(vec3 Left, float Right) { vec3 Result; Result.X = Right * Left.X; Result.Y = Right * Left.Y; Result.Z = Right * Left.Z; return (Result); } HMMDEF vec2 operator*(vec2 Left, float Right) { vec2 Result; Result.X = Right * Left.X; Result.Y = Right * Left.Y; return (Result); } HMMDEF HINLINE vec4 operator*(vec4 Left, vec4 Right) { vec4 Result = Multiply(Left, Right); return (Result); } HMMDEF HINLINE mat4 operator*(mat4 Left, mat4 Right) { mat4 Result = Multiply(Left, Right); return (Result); } HMMDEF HINLINE vec2 operator/(vec2 Left, vec2 Right) { vec2 Result = Divide(Left, Right); return (Result); } HMMDEF HINLINE vec3 operator/(vec3 Left, vec3 Right) { vec3 Result = Divide(Left, Right); return (Result); } HMMDEF HINLINE vec4 operator/(vec4 Left, vec4 Right) { vec4 Result = Divide(Left, Right); return (Result); } #endif /* HANDMADE_MATH_CPP_MODE */ #endif /* HANDMADE_MATH_IMPLEMENTATION */