glmth.h (9340B)
1 #pragma once 2 3 #ifndef M_PI 4 #define M_PI 3.14159265359f 5 #endif 6 7 typedef unsigned char u8; 8 typedef unsigned short u16; 9 typedef unsigned int u32; 10 typedef unsigned long long u64; 11 typedef signed char i8; 12 typedef signed short i16; 13 typedef signed int i32; 14 typedef signed long long i64; 15 typedef float f32; 16 typedef double f64; 17 18 #define GLMTH_PI 3.14159265358979323846f 19 #define GLMTH_M_2_PI 6.28318530717958647693f 20 #define GLMTH_D_4_PI 1.27323954473516268615f 21 #define GLMTH_D_PI_2 1.57079632679489661923f 22 #define GLMTH_D_4_SQ_PI 0.40528473456935108578f 23 24 static f32 glmth_floorf(f32 x) 25 { 26 f32 result = (f32)((i32)x - (x < 0.0f)); 27 return result; 28 } 29 30 // These Sine and Cosine approximations use a parabola adjusted to minimize 31 // error. This lovely approximation was derived by "Nick" on the devmaster.net 32 // forums: 33 // 34 // https://web.archive.org/web/20080228213915/http://www.devmaster.net/forums/showthread.php?t=5784 35 static f32 glmth_sinf(f32 x) 36 { 37 38 // wrap to range [0, 2PI] 39 f32 full_circles = glmth_floorf(x / GLMTH_M_2_PI); 40 f32 full_circle_radians = full_circles * GLMTH_M_2_PI; 41 x = x - full_circle_radians; 42 43 // TODO: remove branches 44 // wrap to range [-PI, PI] 45 if(x < -GLMTH_PI) 46 { 47 x += GLMTH_M_2_PI; 48 } 49 else if(x > GLMTH_PI) 50 { 51 x -= GLMTH_M_2_PI; 52 } 53 54 // fit parabola to sine 55 f32 f = 0.0f; 56 f32 g = 0.0f; 57 if(x < 0.0f) 58 { 59 f = (GLMTH_D_4_PI * x) + (GLMTH_D_4_SQ_PI * x * x); 60 g = f * -f; 61 62 } 63 else 64 { 65 f = (GLMTH_D_4_PI * x) - (GLMTH_D_4_SQ_PI * x * x); 66 g = f * f; 67 } 68 69 f32 h = g - f; 70 f32 i = h * 0.225f; 71 f = i + f; 72 73 return f; 74 } 75 76 static f32 glmth_cosf(f32 x) 77 { 78 // wrap to range [0, 2PI] 79 f32 full_circles = glmth_floorf(x / GLMTH_M_2_PI); 80 f32 full_circle_radians = full_circles * GLMTH_M_2_PI; 81 x = x - full_circle_radians; 82 83 // TODO: remove branches 84 // wrap to range [-PI, PI] 85 if(x < -GLMTH_PI) 86 { 87 x += GLMTH_M_2_PI; 88 } 89 else if(x > GLMTH_PI) 90 { 91 x -= GLMTH_M_2_PI; 92 } 93 94 x += GLMTH_D_PI_2; 95 if(x > GLMTH_PI) 96 { 97 x -= GLMTH_M_2_PI; 98 } 99 100 // fit parabola to cosine 101 f32 f = 0.0f; 102 f32 g = 0.0f; 103 if(x < 0.0f) 104 { 105 f = (GLMTH_D_4_PI * x) + (GLMTH_D_4_SQ_PI * x * x); 106 g = f * -f; 107 108 } 109 else 110 { 111 f = (GLMTH_D_4_PI * x) - (GLMTH_D_4_SQ_PI * x * x); 112 g = f * f; 113 } 114 115 f32 h = g - f; 116 f32 i = h * 0.225f; 117 f = i + f; 118 return f; 119 } 120 121 static f32 glmth_tanf(f32 x) 122 { 123 // TODO: make a proper approximation 124 return glmth_sinf(x)/glmth_cosf(x); 125 } 126 127 typedef union 128 { 129 struct 130 { 131 f32 x, y; 132 }; 133 f32 E[2]; 134 } v2; 135 136 typedef union 137 { 138 struct 139 { 140 f32 x, y, z; 141 }; 142 struct 143 { 144 v2 xy; 145 f32 ignored_z; 146 }; 147 struct 148 { 149 f32 ignored_x; 150 v2 yz; 151 }; 152 f32 E[3]; 153 } v3; 154 155 typedef union 156 { 157 struct 158 { 159 union 160 { 161 v3 xyz; 162 struct 163 { 164 f32 x, y, z; 165 }; 166 }; 167 f32 w; 168 }; 169 struct 170 { 171 v2 xy; 172 f32 ignored_z_xy; 173 f32 ignored_w_xy; 174 }; 175 struct 176 { 177 f32 ignored_x_yz; 178 v2 yz; 179 f32 ignored_w_yz; 180 }; 181 struct 182 { 183 f32 ignored_x_zw; 184 f32 ignored_y_zw; 185 v2 zw; 186 }; 187 f32 E[4]; 188 } v4; 189 190 typedef struct 191 { 192 // row-major, so you probably want to transpose before passing to opengl, 193 // which uses column-major matrices 194 f32 E[4][4]; // E[row][column] 195 } m4; 196 197 static m4 glmth_m4_init_id(void) 198 { 199 m4 m = { 0 }; 200 m.E[0][0] = 1.0f; 201 m.E[1][1] = 1.0f; 202 m.E[2][2] = 1.0f; 203 m.E[3][3] = 1.0f; 204 return m; 205 } 206 207 static void glmth_m4_valueptr(m4 m, f32* out_valueptr) 208 { 209 for (u8 v = 0; v < 16; ++v) 210 { 211 u8 row = v / 4; 212 u8 col = v % 4; 213 out_valueptr[v] = m.E[row][col]; 214 } 215 } 216 217 static m4 glmth_m4m4_m(m4 mat1, m4 mat2) 218 { 219 m4 r = { 220 .E[0][0] = (mat1.E[0][0] * mat2.E[0][0]) + (mat1.E[0][1] * mat2.E[1][0]) + (mat1.E[0][2] * mat2.E[2][0]) + (mat1.E[0][3] * mat2.E[3][0]), 221 .E[0][1] = (mat1.E[0][0] * mat2.E[0][1]) + (mat1.E[0][1] * mat2.E[1][1]) + (mat1.E[0][2] * mat2.E[2][1]) + (mat1.E[0][3] * mat2.E[3][1]), 222 .E[0][2] = (mat1.E[0][0] * mat2.E[0][2]) + (mat1.E[0][1] * mat2.E[1][2]) + (mat1.E[0][2] * mat2.E[2][2]) + (mat1.E[0][3] * mat2.E[3][2]), 223 .E[0][3] = (mat1.E[0][0] * mat2.E[0][3]) + (mat1.E[0][1] * mat2.E[1][3]) + (mat1.E[0][2] * mat2.E[2][3]) + (mat1.E[0][3] * mat2.E[3][3]), 224 225 .E[1][0] = (mat1.E[1][0] * mat2.E[0][0]) + (mat1.E[1][1] * mat2.E[1][0]) + (mat1.E[1][2] * mat2.E[2][0]) + (mat1.E[1][3] * mat2.E[3][0]), 226 .E[1][1] = (mat1.E[1][0] * mat2.E[0][1]) + (mat1.E[1][1] * mat2.E[1][1]) + (mat1.E[1][2] * mat2.E[2][1]) + (mat1.E[1][3] * mat2.E[3][1]), 227 .E[1][2] = (mat1.E[1][0] * mat2.E[0][2]) + (mat1.E[1][1] * mat2.E[1][2]) + (mat1.E[1][2] * mat2.E[2][2]) + (mat1.E[1][3] * mat2.E[3][2]), 228 .E[1][3] = (mat1.E[1][0] * mat2.E[0][3]) + (mat1.E[1][1] * mat2.E[1][3]) + (mat1.E[1][2] * mat2.E[2][3]) + (mat1.E[1][3] * mat2.E[3][3]), 229 230 .E[2][0] = (mat1.E[2][0] * mat2.E[0][0]) + (mat1.E[2][1] * mat2.E[1][0]) + (mat1.E[2][2] * mat2.E[2][0]) + (mat1.E[2][3] * mat2.E[3][0]), 231 .E[2][1] = (mat1.E[2][0] * mat2.E[0][1]) + (mat1.E[2][1] * mat2.E[1][1]) + (mat1.E[2][2] * mat2.E[2][1]) + (mat1.E[2][3] * mat2.E[3][1]), 232 .E[2][2] = (mat1.E[2][0] * mat2.E[0][2]) + (mat1.E[2][1] * mat2.E[1][2]) + (mat1.E[2][2] * mat2.E[2][2]) + (mat1.E[2][3] * mat2.E[3][2]), 233 .E[2][3] = (mat1.E[2][0] * mat2.E[0][3]) + (mat1.E[2][1] * mat2.E[1][3]) + (mat1.E[2][2] * mat2.E[2][3]) + (mat1.E[2][3] * mat2.E[3][3]), 234 235 .E[3][0] = (mat1.E[3][0] * mat2.E[0][0]) + (mat1.E[3][1] * mat2.E[1][0]) + (mat1.E[3][2] * mat2.E[2][0]) + (mat1.E[3][3] * mat2.E[3][0]), 236 .E[3][1] = (mat1.E[3][0] * mat2.E[0][1]) + (mat1.E[3][1] * mat2.E[1][1]) + (mat1.E[3][2] * mat2.E[2][1]) + (mat1.E[3][3] * mat2.E[3][1]), 237 .E[3][2] = (mat1.E[3][0] * mat2.E[0][2]) + (mat1.E[3][1] * mat2.E[1][2]) + (mat1.E[3][2] * mat2.E[2][2]) + (mat1.E[3][3] * mat2.E[3][2]), 238 .E[3][3] = (mat1.E[3][0] * mat2.E[0][3]) + (mat1.E[3][1] * mat2.E[1][3]) + (mat1.E[3][2] * mat2.E[2][3]) + (mat1.E[3][3] * mat2.E[3][3]), 239 }; 240 return r; 241 } 242 243 static v3 glmth_v3_init(f32 x, f32 y, f32 z) 244 { 245 v3 v = { .x = x, .y = y, .z = z }; 246 return v; 247 } 248 249 static f32 glmth_rad(f32 deg) 250 { 251 return deg * (M_PI / 180.0f); 252 } 253 254 static m4 glmth_rotate(m4 m, f32 rad, v3 axis) 255 { 256 f32 c = glmth_cosf(rad); 257 f32 s = glmth_sinf(rad); 258 259 m4 r = glmth_m4_init_id(); 260 261 r.E[0][0] = c + ((axis.x * axis.x) * (1 - c)); 262 r.E[0][1] = (axis.x * axis.y * (1 - c)) - (axis.z * s); 263 r.E[0][2] = (axis.x * axis.z * (1 - c)) + (axis.y * s); 264 265 r.E[1][0] = (axis.y * axis.x * (1 - c)) + (axis.z * s); 266 r.E[1][1] = c + ((axis.y * axis.y) * (1 - c)); 267 r.E[1][2] = (axis.y * axis.z * (1 - c)) - (axis.x * s); 268 269 r.E[2][0] = (axis.z * axis.x * (1 - c)) - (axis.y * s); 270 r.E[2][1] = (axis.z * axis.y * (1 - c)) + (axis.x * s); 271 r.E[2][2] = c + ((axis.z * axis.z) * (1 - c)); 272 273 return glmth_m4m4_m(m, r); 274 } 275 276 static m4 glmth_translate(m4 m, v3 v) 277 { 278 m4 r = glmth_m4_init_id(); 279 r.E[0][3] = v.x; 280 r.E[1][3] = v.y; 281 r.E[2][3] = v.z; 282 return glmth_m4m4_m(m, r); 283 } 284 285 static m4 glmth_projection_ortho(f32 left, f32 right, f32 bottom, f32 top, f32 near, f32 far) 286 { 287 // TODO: This assert fails when you minimise the window in Windows. 288 assert(left != right); 289 assert(bottom != top); 290 assert(near != far); 291 292 m4 r = glmth_m4_init_id(); 293 294 r.E[0][0] = 2.0f / (right - left); 295 r.E[0][1] = 0.0f; 296 r.E[0][2] = 0.0f; 297 r.E[0][3] = -(right + left) / (right - left); 298 299 r.E[1][0] = 0.0f; 300 r.E[1][1] = 2.0f / (top - bottom); 301 r.E[1][2] = 0.0f; 302 r.E[1][3] = -(top + bottom) / (top - bottom); 303 304 r.E[2][0] = 0.0f; 305 r.E[2][1] = 0.0f; 306 r.E[2][2] = -2.0f / (far - near); 307 r.E[2][3] = -(far + near) / (far - near); 308 309 r.E[3][0] = 0.0f; 310 r.E[3][1] = 0.0f; 311 r.E[3][2] = 0.0f; 312 r.E[3][3] = 1.0f; 313 314 return r; 315 } 316 317 static m4 glmth_projection_perspective(f32 left, f32 right, f32 bottom, f32 top, f32 near, f32 far) 318 { 319 assert(left != right); 320 assert(bottom != top); 321 assert(near != far); 322 323 m4 r = glmth_m4_init_id(); 324 325 r.E[0][0] = (2.0f * near) / (right - left); 326 r.E[0][1] = 0.0f; 327 r.E[0][2] = (right + left) / (right - left); 328 r.E[0][3] = 0.0f; 329 330 r.E[1][0] = 0.0f; 331 r.E[1][1] = (2.0f * near) / (top - bottom); 332 r.E[1][2] = (top + bottom) / (top - bottom); 333 r.E[1][3] = 0.0f; 334 335 r.E[2][0] = 0.0f; 336 r.E[2][1] = 0.0f; 337 r.E[2][2] = -(far + near) / (far - near); 338 r.E[2][3] = (-2.0f * far * near) / (far - near); 339 340 r.E[3][0] = 0.0f; 341 r.E[3][1] = 0.0f; 342 r.E[3][2] = -1.0f; 343 r.E[3][3] = 0.0f; 344 345 return r; 346 } 347 348 static m4 glmth_projection_perspective_fov(f32 fovy, f32 aspect, f32 near, f32 far) 349 { 350 f32 half_height = glmth_tanf(fovy / 2.0f) * near; 351 f32 half_width = half_height * aspect; 352 f32 left = -half_width; 353 f32 right = half_width; 354 f32 bottom = -half_height; 355 f32 top = half_height; 356 357 return glmth_projection_perspective(left, right, bottom, top, near, far); 358 }