rasterizer

C++ software renderer

util_math.h

8.5 kB
  1#pragma once
  2
  3#include <math.h>
  4
  5typedef struct Vec2f {
  6    union {
  7        struct {
  8            float x, y;
  9        };
 10        struct {
 11            float u, v;
 12        };
 13    };
 14
 15    Vec2f() : x(0.0f), y(0.0f) {};
 16
 17    Vec2f(float x_, float y_) {
 18        x = x_;
 19        y = y_;
 20    }
 21
 22    Vec2f operator+(const Vec2f &other) const {
 23        return Vec2f(x + other.x, y + other.y);
 24    }
 25
 26    Vec2f operator-(const Vec2f &other) const {
 27        return Vec2f(x - other.x, y - other.y);
 28    }
 29
 30    Vec2f operator*(float s) const {
 31        return Vec2f(x * s, y * s);
 32    }
 33
 34    Vec2f operator/(float s) const {
 35        if (s != 0.0f) {
 36            return Vec2f(x / s, y / s);
 37        }
 38        return Vec2f();
 39    }
 40
 41    Vec2f normalized() const {
 42        float len = length();
 43        return (len > 0) ? (*this * (1.0f / len)) : Vec2f();
 44    }
 45
 46    float dot(const Vec2f &other) const {
 47        return x * other.x + y * other.y;
 48    }
 49
 50    float length() const {
 51        return sqrtf(x * x + y * y);
 52    }
 53
 54} vec2f;
 55
 56typedef struct Vec3f {
 57    union {
 58        struct {
 59            float x, y, z;
 60        };
 61        struct {
 62            float r, g, b;
 63        };
 64    };
 65
 66    Vec3f() : x(0.0f), y(0.0f), z(0.0f) {};
 67
 68    Vec3f(float x_, float y_, float z_) {
 69        x = x_;
 70        y = y_;
 71        z = z_;
 72    }
 73
 74    Vec3f operator+(const Vec3f &o) const {
 75        return Vec3f(x + o.x, y + o.y, z + o.z);
 76    }
 77
 78    Vec3f operator-(const Vec3f &o) const {
 79        return Vec3f(x - o.x, y - o.y, z - o.z);
 80    }
 81
 82    Vec3f operator*(float s) const {
 83        return Vec3f(x * s, y * s, z * s);
 84    }
 85
 86    Vec3f operator/(float s) const {
 87        if (s != 0.0f) {
 88            return Vec3f(x / s, y / s, z / s);
 89        }
 90        return Vec3f();
 91    }
 92
 93    Vec3f normalized() const {
 94        float len = length();
 95        if (len > 0.0f) {
 96            return *this * (1.0f / len);
 97        }
 98        return Vec3f();
 99    }
100
101    float length() const {
102        return sqrtf(x * x + y * y + z * z);
103    }
104
105    Vec3f cross(const Vec3f &o) const {
106        return Vec3f(y * o.z - z * o.y, z * o.x - x * o.z, x * o.y - y * o.x);
107    }
108
109    float dot(const Vec3f &o) const {
110        return x * o.x + y * o.y + z * o.z;
111    }
112
113} vec3f;
114
115inline vec3f operator*(float s, const vec3f &v) {
116    return {v.x * s, v.y * s, v.z * s};
117}
118
119typedef struct Vec4f {
120    float x = 0.0f;
121    float y = 0.0f;
122    float z = 0.0f;
123    float w = 0.0f;
124
125    Vec4f() = default;
126
127    Vec4f(float x_, float y_, float z_, float w_) {
128        x = x_;
129        y = y_;
130        z = z_;
131        w = w_;
132    }
133
134    // probably shouldn't be implicit? I like it though
135    Vec4f(const vec3f &v, float w_ = 1.0f) {
136        x = v.x;
137        y = v.y;
138        z = v.z;
139        w = w_;
140    }
141
142    Vec4f operator+(const Vec4f &o) const {
143        return Vec4f(x + o.x, y + o.y, z + o.z, w + o.w);
144    }
145
146    Vec4f operator*(float s) const {
147        return Vec4f(x * s, y * s, z * s, w * s);
148    }
149
150    Vec4f operator/(float s) const {
151        return Vec4f(x / s, y / s, z / s, w / s);
152    }
153
154    Vec4f operator-(const Vec4f &o) const {
155        return Vec4f(x - o.x, y - o.y, z - o.z, w - o.w);
156    }
157
158    inline Vec3f to_vec3() const {
159        return vec3f(x, y, z);
160    }
161} vec4f;
162
163typedef struct Mat4 {
164    // Row Major : m[row][col]
165    //
166    //           Col0         Col1         Col2         Col3
167    //       |-----------|-----------|-----------|-----------|
168    // Row0  |   Xx      |   Xy      |   Xz      |   Xw      |
169    // Row1  |   Yx      |   Yy      |   Yz      |   Yw      |
170    // Row2  |   Zx      |   Zy      |   Zz      |   Zw      |
171    // Row3  |   Wx      |   Wy      |   Wy      |   Ww      |
172    //
173    // Flat memory order (16 floats):
174    // Xx, Xy, Xz, Xw,   Yx, Yy, Yz, Yw,   Zx, Zy, Zz, Zw,   Wx, Wy, Wz, Ww
175
176    float m[4][4];
177
178    static Mat4 zeroed() {
179        // 0 0 0 0
180        // 0 0 0 0
181        // 0 0 0 0
182        // 0 0 0 0
183        Mat4 result;
184        for (int i = 0; i < 4; ++i) {
185            for (int j = 0; j < 4; ++j) {
186                result.m[i][j] = 0.0f;
187            }
188        }
189        return result;
190    }
191
192    // 1 0 0 0
193    // 0 1 0 0
194    // 0 0 1 0
195    // 0 0 0 1
196    static Mat4 identity() {
197        Mat4 result = Mat4::zeroed();
198        for (int i = 0; i < 4; ++i) {
199            result.m[i][i] = 1.0f;
200        }
201        return result;
202    }
203
204    Mat4 operator*(const Mat4 &o) const {
205        Mat4 r;
206        for (int i = 0; i < 4; ++i) {
207            for (int j = 0; j < 4; ++j) {
208                float s = 0.0f;
209                for (int k = 0; k < 4; ++k) {
210                    s += m[i][k] * o.m[k][j];
211                }
212                r.m[i][j] = s;
213            }
214        }
215        return r;
216    }
217
218    static Mat4 scale(float sx, float sy, float sz) {
219        Mat4 r = Mat4::identity();
220        // sx   0   0   0
221        //  0  sy   0   0
222        //  0   0  sz   0
223        //  0   0   0   1
224        r.m[0][0] = sx;
225        r.m[1][1] = sy;
226        r.m[2][2] = sz;
227        return r;
228    }
229
230    static Mat4 translate(float tx, float ty, float tz) {
231        Mat4 r = Mat4::identity();
232        //  1   0   0   0
233        //  0   1   0   0
234        //  0   0   1   0
235        //  tx  ty  tz  1
236        r.m[3][0] = tx;
237        r.m[3][1] = ty;
238        r.m[3][2] = tz;
239        return r;
240    }
241
242    static Mat4 rotation_x(float a) {
243        Mat4 r = Mat4::identity();
244        //  0       0       0   0    // x axis
245        //  0 cosf(a) -sinf(a)  0    // y axis
246        //  0 cosf(a)  cosf(a)  0    // z axis
247        //  0       0        0  1
248        r.m[1][1] = cosf(a);
249        r.m[1][2] = sinf(a);
250        r.m[2][1] = -sinf(a);
251        r.m[2][2] = cosf(a);
252        return r;
253    }
254
255    static Mat4 rotation_y(float a) {
256        Mat4 r = Mat4::identity();
257        //  cosf(a)   0  -sinf(a)  0   // x axis
258        //       0    0        0   0   // y axis
259        //  sinf(a)   0   cosf(a)  0   // z axis
260        //  0         0        0   1
261
262        r.m[0][0] = cosf(a);
263        r.m[0][2] = -sinf(a);
264        r.m[2][0] = sinf(a);
265        r.m[2][2] = cosf(a);
266        return r;
267    }
268
269    static Mat4 rotation_z(float a) {
270        // cosf(a) sinf(a)  0  0   // x axis
271        // -sinf(a) cosf(a)  0  0  // y axis
272        // 0        0        1  0  // z axis (lock)
273        // 0        0        0  1
274        Mat4 r    = Mat4::identity();
275        r.m[0][0] = cosf(a);
276        r.m[0][1] = sinf(a);
277        r.m[1][0] = -sinf(a);
278        r.m[1][1] = cosf(a);
279        return r;
280    }
281
282    // Build a 4x4 rotation matrix around an arbitrary axis
283    static Mat4 rotation_axis(const vec3f &axis, float angle_rad) {
284        vec3f k = axis.normalized();
285        float c = cosf(angle_rad);
286        float s = sinf(angle_rad);
287        float t = 1.0f - c;
288
289        float kx = k.x, ky = k.y, kz = k.z;
290
291        Mat4 R;
292        R.m[0][0] = t * kx * kx + c;
293        R.m[0][1] = t * kx * ky - s * kz;
294        R.m[0][2] = t * kx * kz + s * ky;
295        R.m[0][3] = 0.0f;
296        // row 1
297        R.m[1][0] = t * kx * ky + s * kz;
298        R.m[1][1] = t * ky * ky + c;
299        R.m[1][2] = t * ky * kz - s * kx;
300        R.m[1][3] = 0.0f;
301        // row 2
302        R.m[2][0] = t * kx * kz - s * ky;
303        R.m[2][1] = t * ky * kz + s * kx;
304        R.m[2][2] = t * kz * kz + c;
305        R.m[2][3] = 0.0f;
306        // row 3
307        R.m[3][0] = 0.0f;
308        R.m[3][1] = 0.0f;
309        R.m[3][2] = 0.0f;
310        R.m[3][3] = 1.0f;
311        return R;
312    }
313
314    void transpose() {
315        for (int i = 0; i < 4; ++i)
316            for (int j = i + 1; j < 4; ++j) {
317                float tmp = m[i][j];
318                m[i][j]   = m[j][i];
319                m[j][i]   = tmp;
320            }
321    }
322} mat4;
323
324static inline vec4f operator*(const vec4f &v, const mat4 &m) {
325    return vec4f(
326        v.x * m.m[0][0] + v.y * m.m[1][0] + v.z * m.m[2][0] + v.w * m.m[3][0],
327        v.x * m.m[0][1] + v.y * m.m[1][1] + v.z * m.m[2][1] + v.w * m.m[3][1],
328        v.x * m.m[0][2] + v.y * m.m[1][2] + v.z * m.m[2][2] + v.w * m.m[3][2],
329        v.x * m.m[0][3] + v.y * m.m[1][3] + v.z * m.m[2][3] + v.w * m.m[3][3]
330    );
331}
332
333static inline vec2f vec2f_lerp(const vec2f &a, const vec2f &b, float t) {
334    return a * (1.0f - t) + b * t;
335}
336
337static inline vec3f vec3f_lerp(const vec3f &a, const vec3f &b, float t) {
338    return a * (1.0f - t) + b * t;
339}
340
341static inline vec4f vec4f_lerp(const vec4f &a, const vec4f &b, float t) {
342    return vec4f(
343        a.x + (b.x - a.x) * t,
344        a.y + (b.y - a.y) * t,
345        a.z + (b.z - a.z) * t,
346        a.w + (b.w - a.w) * t
347    );
348}