rasterizer

c++ software renderer

math.hpp

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