added mats, updated gradient, updated bmp.

This commit is contained in:
Yggdrasil75
2025-11-05 14:05:23 -05:00
parent 5a0d81134e
commit 6c6e420507
9 changed files with 839 additions and 67 deletions

2
.gitignore vendored Normal file
View File

@@ -0,0 +1,2 @@
/output/
/bin/

73
.vscode/settings.json vendored Normal file
View File

@@ -0,0 +1,73 @@
{
"files.associations": {
"algorithm": "cpp",
"array": "cpp",
"atomic": "cpp",
"bit": "cpp",
"cctype": "cpp",
"charconv": "cpp",
"chrono": "cpp",
"clocale": "cpp",
"cmath": "cpp",
"compare": "cpp",
"concepts": "cpp",
"cstddef": "cpp",
"cstdint": "cpp",
"cstdio": "cpp",
"cstdlib": "cpp",
"cstring": "cpp",
"ctime": "cpp",
"cwchar": "cpp",
"exception": "cpp",
"filesystem": "cpp",
"format": "cpp",
"forward_list": "cpp",
"fstream": "cpp",
"functional": "cpp",
"initializer_list": "cpp",
"iomanip": "cpp",
"ios": "cpp",
"iosfwd": "cpp",
"iostream": "cpp",
"istream": "cpp",
"iterator": "cpp",
"limits": "cpp",
"list": "cpp",
"locale": "cpp",
"map": "cpp",
"memory": "cpp",
"new": "cpp",
"optional": "cpp",
"ostream": "cpp",
"random": "cpp",
"ratio": "cpp",
"sstream": "cpp",
"stdexcept": "cpp",
"stop_token": "cpp",
"streambuf": "cpp",
"string": "cpp",
"system_error": "cpp",
"thread": "cpp",
"tuple": "cpp",
"type_traits": "cpp",
"typeinfo": "cpp",
"unordered_map": "cpp",
"utility": "cpp",
"vector": "cpp",
"xfacet": "cpp",
"xhash": "cpp",
"xiosbase": "cpp",
"xlocale": "cpp",
"xlocbuf": "cpp",
"xlocinfo": "cpp",
"xlocmes": "cpp",
"xlocmon": "cpp",
"xlocnum": "cpp",
"xloctime": "cpp",
"xmemory": "cpp",
"xstring": "cpp",
"xtr1common": "cpp",
"xtree": "cpp",
"xutility": "cpp"
}
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 768 KiB

100
main.cpp
View File

@@ -41,76 +41,41 @@ int main(int argc, char* argv[]) {
Grid2 grid;
// Define our target colors at specific positions
Vec4 red = hexToVec4("ff0000"); // Top-left corner
Vec4 green = hexToVec4("00ff00"); // Center
Vec4 blue = hexToVec4("0000ff"); // Bottom-right corner
Vec4 white = hexToVec4("ffffff"); // Top-right corner
Vec4 black = hexToVec4("000000"); // Bottom-left corner
Vec4 white = hexToVec4("ffffff"); // Top-left corner (1,1)
Vec4 red = hexToVec4("ff0000"); // Top-right corner (1,-1)
Vec4 green = hexToVec4("00ff00"); // Center (0,0)
Vec4 blue = hexToVec4("0000ff"); // Bottom-left corner (-1,-1)
Vec4 black = hexToVec4("000000"); // Bottom-right corner (-1,1)
// Create gradient points
for (int y = 0; y < POINTS_PER_DIM; ++y) {
for (int x = 0; x < POINTS_PER_DIM; ++x) {
// Normalize coordinates to [0, 1]
float nx = static_cast<float>(x) / (POINTS_PER_DIM - 1);
float ny = static_cast<float>(y) / (POINTS_PER_DIM - 1);
// Normalize coordinates to [-1, 1]
float nx = (static_cast<float>(x) / (POINTS_PER_DIM - 1)) * 2.0f - 1.0f;
float ny = (static_cast<float>(y) / (POINTS_PER_DIM - 1)) * 2.0f - 1.0f;
// Create position in [-1, 1] range
Vec2 pos(nx * 2.0f - 1.0f, ny * 2.0f - 1.0f);
// Create position
Vec2 pos(nx, ny);
// Calculate interpolated color based on position
Vec4 color;
// Calculate weights for each corner based on distance
// We'll use bilinear interpolation
if (nx + ny <= 1.0f) {
// Lower triangle: interpolate between red, green, and black
if (nx <= 0.5f && ny <= 0.5f) {
// Bottom-left quadrant: red to black to green
float t1 = nx * 2.0f; // Horizontal interpolation
float t2 = ny * 2.0f; // Vertical interpolation
if (t1 + t2 <= 1.0f) {
// Interpolate between red and black
color = red * (1.0f - t1 - t2) + black * (t1 + t2);
} else {
// Interpolate between black and green
color = black * (2.0f - t1 - t2) + green * (t1 + t2 - 1.0f);
}
} else {
// Use bilinear interpolation for other areas
Vec4 topLeft = red;
Vec4 topRight = white;
Vec4 bottomLeft = black;
Vec4 bottomRight = green;
Vec4 top = topLeft * (1.0f - nx) + topRight * nx;
Vec4 bottom = bottomLeft * (1.0f - nx) + bottomRight * nx;
color = bottom * (1.0f - ny) + top * ny;
}
} else {
// Upper triangle: interpolate between green, blue, and white
if (nx >= 0.5f && ny >= 0.5f) {
// Top-right quadrant: green to white to blue
float t1 = (nx - 0.5f) * 2.0f; // Horizontal interpolation
float t2 = (ny - 0.5f) * 2.0f; // Vertical interpolation
if (t1 + t2 <= 1.0f) {
// Interpolate between green and white
color = green * (1.0f - t1 - t2) + white * (t1 + t2);
} else {
// Interpolate between white and blue
color = white * (2.0f - t1 - t2) + blue * (t1 + t2 - 1.0f);
}
} else {
// Use bilinear interpolation for other areas
Vec4 topLeft = red;
Vec4 topRight = white;
Vec4 bottomLeft = black;
Vec4 bottomRight = blue;
Vec4 top = topLeft * (1.0f - nx) + topRight * nx;
Vec4 bottom = bottomLeft * (1.0f - nx) + bottomRight * nx;
color = bottom * (1.0f - ny) + top * ny;
}
}
// Convert to [0,1] range for interpolation
float u = (nx + 1.0f) / 2.0f; // maps -1..1 to 0..1
float v = (ny + 1.0f) / 2.0f; // maps -1..1 to 0..1
// For a more natural gradient, we'll interpolate between the four corners
// and blend with the center color based on distance from center
// Bilinear interpolation between corners
Vec4 top = white * (1.0f - u) + red * u;
Vec4 bottom = blue * (1.0f - u) + black * u;
Vec4 cornerColor = top * (1.0f - v) + bottom * v;
// Calculate distance from center (0,0)
float distFromCenter = std::sqrt(nx * nx + ny * ny) / std::sqrt(2.0f); // normalize to [0,1]
Vec4 color = green * (1.0f - distFromCenter) + cornerColor * distFromCenter;
grid.addPoint(pos, color);
}
@@ -122,11 +87,12 @@ int main(int argc, char* argv[]) {
// Save as BMP
if (BMPWriter::saveBMP("output/gradient.bmp", imageData, WIDTH, HEIGHT)) {
std::cout << "Gradient image saved as 'gradient.bmp'" << std::endl;
std::cout << "Colors: " << std::endl;
std::cout << " Top-left: ff0000 (red)" << std::endl;
std::cout << "Color positions: " << std::endl;
std::cout << " Top-left: ffffff (white)" << std::endl;
std::cout << " Top-right: ff0000 (red)" << std::endl;
std::cout << " Center: 00ff00 (green)" << std::endl;
std::cout << " Bottom-right: 0000ff (blue)" << std::endl;
std::cout << " Gradient between ffffff and 000000 throughout" << std::endl;
std::cout << " Bottom-left: 0000ff (blue)" << std::endl;
std::cout << " Bottom-right: 000000 (black)" << std::endl;
} else {
std::cerr << "Failed to save gradient image" << std::endl;
return 1;

Binary file not shown.

View File

@@ -6,6 +6,7 @@
#include <cstring>
#include <string>
#include <algorithm>
#include <filesystem>
#include "vec3.hpp"
class BMPWriter {
@@ -34,6 +35,18 @@ private:
};
#pragma pack(pop)
// Helper function to create directory if it doesn't exist
static bool createDirectoryIfNeeded(const std::string& filename) {
std::filesystem::path filePath(filename);
std::filesystem::path directory = filePath.parent_path();
// If there's a directory component and it doesn't exist, create it
if (!directory.empty() && !std::filesystem::exists(directory)) {
return std::filesystem::create_directories(directory);
}
return true;
}
public:
// Save a 2D vector of Vec3 (RGB) colors as BMP
// Vec3 components: x = red, y = green, z = blue (values in range [0,1])
@@ -78,6 +91,11 @@ public:
return false;
}
// Create directory if needed
if (!createDirectoryIfNeeded(filename)) {
return false;
}
BMPHeader header;
BMPInfoHeader infoHeader;
@@ -121,6 +139,11 @@ public:
private:
static bool saveBMP(const std::string& filename, const std::vector<std::vector<Vec3>>& pixels, int width, int height) {
// Create directory if needed
if (!createDirectoryIfNeeded(filename)) {
return false;
}
BMPHeader header;
BMPInfoHeader infoHeader;

166
util/mat2.hpp Normal file
View File

@@ -0,0 +1,166 @@
#ifndef MAT2_HPP
#define MAT2_HPP
#include "Vec2.hpp"
#include <array>
#include <cmath>
class Mat2 {
public:
union {
struct { float m00, m01, m10, m11; };
struct { float a, b, c, d; };
float data[4];
float m[2][2];
};
// Constructors
Mat2() : m00(1), m01(0), m10(0), m11(1) {}
Mat2(float scalar) : m00(scalar), m01(scalar), m10(scalar), m11(scalar) {}
Mat2(float m00, float m01, float m10, float m11) : m00(m00), m01(m01), m10(m10), m11(m11) {}
// Identity matrix
static Mat2 identity() { return Mat2(1, 0, 0, 1); }
// Zero matrix
static Mat2 zero() { return Mat2(0, 0, 0, 0); }
// Rotation matrix
static Mat2 rotation(float angle) {
float cosA = std::cos(angle);
float sinA = std::sin(angle);
return Mat2(cosA, -sinA, sinA, cosA);
}
// Scaling matrix
static Mat2 scaling(const Vec2& scale) {
return Mat2(scale.x, 0, 0, scale.y);
}
// Arithmetic operations
Mat2 operator+(const Mat2& other) const {
return Mat2(m00 + other.m00, m01 + other.m01,
m10 + other.m10, m11 + other.m11);
}
Mat2 operator-(const Mat2& other) const {
return Mat2(m00 - other.m00, m01 - other.m01,
m10 - other.m10, m11 - other.m11);
}
Mat2 operator*(const Mat2& other) const {
return Mat2(
m00 * other.m00 + m01 * other.m10,
m00 * other.m01 + m01 * other.m11,
m10 * other.m00 + m11 * other.m10,
m10 * other.m01 + m11 * other.m11
);
}
Mat2 operator*(float scalar) const {
return Mat2(m00 * scalar, m01 * scalar,
m10 * scalar, m11 * scalar);
}
Mat2 operator/(float scalar) const {
return Mat2(m00 / scalar, m01 / scalar,
m10 / scalar, m11 / scalar);
}
Vec2 operator*(const Vec2& vec) const {
return Vec2(
m00 * vec.x + m01 * vec.y,
m10 * vec.x + m11 * vec.y
);
}
Mat2& operator+=(const Mat2& other) {
m00 += other.m00; m01 += other.m01;
m10 += other.m10; m11 += other.m11;
return *this;
}
Mat2& operator-=(const Mat2& other) {
m00 -= other.m00; m01 -= other.m01;
m10 -= other.m10; m11 -= other.m11;
return *this;
}
Mat2& operator*=(const Mat2& other) {
*this = *this * other;
return *this;
}
Mat2& operator*=(float scalar) {
m00 *= scalar; m01 *= scalar;
m10 *= scalar; m11 *= scalar;
return *this;
}
Mat2& operator/=(float scalar) {
m00 /= scalar; m01 /= scalar;
m10 /= scalar; m11 /= scalar;
return *this;
}
bool operator==(const Mat2& other) const {
return m00 == other.m00 && m01 == other.m01 &&
m10 == other.m10 && m11 == other.m11;
}
bool operator!=(const Mat2& other) const {
return !(*this == other);
}
// Matrix operations
float determinant() const {
return m00 * m11 - m01 * m10;
}
Mat2 transposed() const {
return Mat2(m00, m10, m01, m11);
}
Mat2 inverse() const {
float det = determinant();
if (std::abs(det) < 1e-10f) {
return Mat2(); // Return identity if not invertible
}
float invDet = 1.0f / det;
return Mat2( m11 * invDet, -m01 * invDet,
-m10 * invDet, m00 * invDet);
}
// Access operators
float& operator()(int row, int col) {
return m[row][col];
}
const float& operator()(int row, int col) const {
return m[row][col];
}
float& operator[](int index) {
return data[index];
}
const float& operator[](int index) const {
return data[index];
}
std::string toString() const {
return "Mat2([" + std::to_string(m00) + ", " + std::to_string(m01) + "],\n" +
" [" + std::to_string(m10) + ", " + std::to_string(m11) + "])";
}
};
inline std::ostream& operator<<(std::ostream& os, const Mat2& mat) {
os << mat.toString();
return os;
}
inline Mat2 operator*(float scalar, const Mat2& mat) {
return mat * scalar;
}
#endif

232
util/mat3.hpp Normal file
View File

@@ -0,0 +1,232 @@
#ifndef MAT3_HPP
#define MAT3_HPP
#include "Vec3.hpp"
#include <array>
#include <cmath>
class Mat3 {
public:
union {
struct {
float m00, m01, m02,
m10, m11, m12,
m20, m21, m22;
};
float data[9];
float m[3][3];
};
// Constructors
Mat3() : m00(1), m01(0), m02(0),
m10(0), m11(1), m12(0),
m20(0), m21(0), m22(1) {}
Mat3(float scalar) : m00(scalar), m01(scalar), m02(scalar),
m10(scalar), m11(scalar), m12(scalar),
m20(scalar), m21(scalar), m22(scalar) {}
Mat3(float m00, float m01, float m02,
float m10, float m11, float m12,
float m20, float m21, float m22) :
m00(m00), m01(m01), m02(m02),
m10(m10), m11(m11), m12(m12),
m20(m20), m21(m21), m22(m22) {}
// Identity matrix
static Mat3 identity() {
return Mat3(1, 0, 0,
0, 1, 0,
0, 0, 1);
}
// Zero matrix
static Mat3 zero() { return Mat3(0); }
// Rotation matrices
static Mat3 rotationX(float angle) {
float cosA = std::cos(angle);
float sinA = std::sin(angle);
return Mat3(1, 0, 0,
0, cosA, -sinA,
0, sinA, cosA);
}
static Mat3 rotationY(float angle) {
float cosA = std::cos(angle);
float sinA = std::sin(angle);
return Mat3(cosA, 0, sinA,
0, 1, 0,
-sinA, 0, cosA);
}
static Mat3 rotationZ(float angle) {
float cosA = std::cos(angle);
float sinA = std::sin(angle);
return Mat3(cosA, -sinA, 0,
sinA, cosA, 0,
0, 0, 1);
}
// Scaling matrix
static Mat3 scaling(const Vec3& scale) {
return Mat3(scale.x, 0, 0,
0, scale.y, 0,
0, 0, scale.z);
}
// Arithmetic operations
Mat3 operator+(const Mat3& other) const {
return Mat3(m00 + other.m00, m01 + other.m01, m02 + other.m02,
m10 + other.m10, m11 + other.m11, m12 + other.m12,
m20 + other.m20, m21 + other.m21, m22 + other.m22);
}
Mat3 operator-(const Mat3& other) const {
return Mat3(m00 - other.m00, m01 - other.m01, m02 - other.m02,
m10 - other.m10, m11 - other.m11, m12 - other.m12,
m20 - other.m20, m21 - other.m21, m22 - other.m22);
}
Mat3 operator*(const Mat3& other) const {
return Mat3(
m00 * other.m00 + m01 * other.m10 + m02 * other.m20,
m00 * other.m01 + m01 * other.m11 + m02 * other.m21,
m00 * other.m02 + m01 * other.m12 + m02 * other.m22,
m10 * other.m00 + m11 * other.m10 + m12 * other.m20,
m10 * other.m01 + m11 * other.m11 + m12 * other.m21,
m10 * other.m02 + m11 * other.m12 + m12 * other.m22,
m20 * other.m00 + m21 * other.m10 + m22 * other.m20,
m20 * other.m01 + m21 * other.m11 + m22 * other.m21,
m20 * other.m02 + m21 * other.m12 + m22 * other.m22
);
}
Mat3 operator*(float scalar) const {
return Mat3(m00 * scalar, m01 * scalar, m02 * scalar,
m10 * scalar, m11 * scalar, m12 * scalar,
m20 * scalar, m21 * scalar, m22 * scalar);
}
Mat3 operator/(float scalar) const {
return Mat3(m00 / scalar, m01 / scalar, m02 / scalar,
m10 / scalar, m11 / scalar, m12 / scalar,
m20 / scalar, m21 / scalar, m22 / scalar);
}
Vec3 operator*(const Vec3& vec) const {
return Vec3(
m00 * vec.x + m01 * vec.y + m02 * vec.z,
m10 * vec.x + m11 * vec.y + m12 * vec.z,
m20 * vec.x + m21 * vec.y + m22 * vec.z
);
}
Mat3& operator+=(const Mat3& other) {
*this = *this + other;
return *this;
}
Mat3& operator-=(const Mat3& other) {
*this = *this - other;
return *this;
}
Mat3& operator*=(const Mat3& other) {
*this = *this * other;
return *this;
}
Mat3& operator*=(float scalar) {
*this = *this * scalar;
return *this;
}
Mat3& operator/=(float scalar) {
*this = *this / scalar;
return *this;
}
bool operator==(const Mat3& other) const {
for (int i = 0; i < 9; ++i) {
if (data[i] != other.data[i]) return false;
}
return true;
}
bool operator!=(const Mat3& other) const {
return !(*this == other);
}
// Matrix operations
float determinant() const {
return m00 * (m11 * m22 - m12 * m21)
- m01 * (m10 * m22 - m12 * m20)
+ m02 * (m10 * m21 - m11 * m20);
}
Mat3 transposed() const {
return Mat3(m00, m10, m20,
m01, m11, m21,
m02, m12, m22);
}
Mat3 inverse() const {
float det = determinant();
if (std::abs(det) < 1e-10f) {
return Mat3(); // Return identity if not invertible
}
float invDet = 1.0f / det;
return Mat3(
(m11 * m22 - m12 * m21) * invDet,
(m02 * m21 - m01 * m22) * invDet,
(m01 * m12 - m02 * m11) * invDet,
(m12 * m20 - m10 * m22) * invDet,
(m00 * m22 - m02 * m20) * invDet,
(m02 * m10 - m00 * m12) * invDet,
(m10 * m21 - m11 * m20) * invDet,
(m01 * m20 - m00 * m21) * invDet,
(m00 * m11 - m01 * m10) * invDet
);
}
// Access operators
float& operator()(int row, int col) {
return m[row][col];
}
const float& operator()(int row, int col) const {
return m[row][col];
}
float& operator[](int index) {
return data[index];
}
const float& operator[](int index) const {
return data[index];
}
std::string toString() const {
return "Mat3([" + std::to_string(m00) + ", " + std::to_string(m01) + ", " + std::to_string(m02) + "],\n" +
" [" + std::to_string(m10) + ", " + std::to_string(m11) + ", " + std::to_string(m12) + "],\n" +
" [" + std::to_string(m20) + ", " + std::to_string(m21) + ", " + std::to_string(m22) + "])";
}
};
inline std::ostream& operator<<(std::ostream& os, const Mat3& mat) {
os << mat.toString();
return os;
}
inline Mat3 operator*(float scalar, const Mat3& mat) {
return mat * scalar;
}
#endif

310
util/mat4.hpp Normal file
View File

@@ -0,0 +1,310 @@
#ifndef MAT4_HPP
#define MAT4_HPP
#include "Vec3.hpp"
#include "Vec4.hpp"
#include <array>
#include <cmath>
class Mat4 {
public:
union {
struct {
float m00, m01, m02, m03,
m10, m11, m12, m13,
m20, m21, m22, m23,
m30, m31, m32, m33;
};
float data[16];
float m[4][4];
};
// Constructors
Mat4() : m00(1), m01(0), m02(0), m03(0),
m10(0), m11(1), m12(0), m13(0),
m20(0), m21(0), m22(1), m23(0),
m30(0), m31(0), m32(0), m33(1) {}
Mat4(float scalar) : m00(scalar), m01(scalar), m02(scalar), m03(scalar),
m10(scalar), m11(scalar), m12(scalar), m13(scalar),
m20(scalar), m21(scalar), m22(scalar), m23(scalar),
m30(scalar), m31(scalar), m32(scalar), m33(scalar) {}
Mat4(float m00, float m01, float m02, float m03,
float m10, float m11, float m12, float m13,
float m20, float m21, float m22, float m23,
float m30, float m31, float m32, float m33) :
m00(m00), m01(m01), m02(m02), m03(m03),
m10(m10), m11(m11), m12(m12), m13(m13),
m20(m20), m21(m21), m22(m22), m23(m23),
m30(m30), m31(m31), m32(m32), m33(m33) {}
// Identity matrix
static Mat4 identity() {
return Mat4(1, 0, 0, 0,
0, 1, 0, 0,
0, 0, 1, 0,
0, 0, 0, 1);
}
// Zero matrix
static Mat4 zero() { return Mat4(0); }
// Translation matrix
static Mat4 translation(const Vec3& translation) {
return Mat4(1, 0, 0, translation.x,
0, 1, 0, translation.y,
0, 0, 1, translation.z,
0, 0, 0, 1);
}
// Rotation matrices
static Mat4 rotationX(float angle) {
float cosA = std::cos(angle);
float sinA = std::sin(angle);
return Mat4(1, 0, 0, 0,
0, cosA, -sinA, 0,
0, sinA, cosA, 0,
0, 0, 0, 1);
}
static Mat4 rotationY(float angle) {
float cosA = std::cos(angle);
float sinA = std::sin(angle);
return Mat4(cosA, 0, sinA, 0,
0, 1, 0, 0,
-sinA, 0, cosA, 0,
0, 0, 0, 1);
}
static Mat4 rotationZ(float angle) {
float cosA = std::cos(angle);
float sinA = std::sin(angle);
return Mat4(cosA, -sinA, 0, 0,
sinA, cosA, 0, 0,
0, 0, 1, 0,
0, 0, 0, 1);
}
// Scaling matrix
static Mat4 scaling(const Vec3& scale) {
return Mat4(scale.x, 0, 0, 0,
0, scale.y, 0, 0,
0, 0, scale.z, 0,
0, 0, 0, 1);
}
// Perspective projection matrix
static Mat4 perspective(float fov, float aspect, float near, float far) {
float tanHalfFov = std::tan(fov / 2.0f);
float range = near - far;
return Mat4(1.0f / (aspect * tanHalfFov), 0, 0, 0,
0, 1.0f / tanHalfFov, 0, 0,
0, 0, (-near - far) / range, 2.0f * far * near / range,
0, 0, 1, 0);
}
// Orthographic projection matrix
static Mat4 orthographic(float left, float right, float bottom, float top, float near, float far) {
return Mat4(2.0f / (right - left), 0, 0, -(right + left) / (right - left),
0, 2.0f / (top - bottom), 0, -(top + bottom) / (top - bottom),
0, 0, -2.0f / (far - near), -(far + near) / (far - near),
0, 0, 0, 1);
}
// LookAt matrix (view matrix)
static Mat4 lookAt(const Vec3& eye, const Vec3& target, const Vec3& up) {
Vec3 z = (eye - target).normalized();
Vec3 x = up.cross(z).normalized();
Vec3 y = z.cross(x);
return Mat4(x.x, x.y, x.z, -x.dot(eye),
y.x, y.y, y.z, -y.dot(eye),
z.x, z.y, z.z, -z.dot(eye),
0, 0, 0, 1);
}
// Arithmetic operations
Mat4 operator+(const Mat4& other) const {
Mat4 result;
for (int i = 0; i < 16; ++i) {
result.data[i] = data[i] + other.data[i];
}
return result;
}
Mat4 operator-(const Mat4& other) const {
Mat4 result;
for (int i = 0; i < 16; ++i) {
result.data[i] = data[i] - other.data[i];
}
return result;
}
Mat4 operator*(const Mat4& other) const {
Mat4 result;
for (int i = 0; i < 4; ++i) {
for (int j = 0; j < 4; ++j) {
result.m[i][j] = 0;
for (int k = 0; k < 4; ++k) {
result.m[i][j] += m[i][k] * other.m[k][j];
}
}
}
return result;
}
Mat4 operator*(float scalar) const {
Mat4 result;
for (int i = 0; i < 16; ++i) {
result.data[i] = data[i] * scalar;
}
return result;
}
Mat4 operator/(float scalar) const {
Mat4 result;
for (int i = 0; i < 16; ++i) {
result.data[i] = data[i] / scalar;
}
return result;
}
Vec4 operator*(const Vec4& vec) const {
return Vec4(
m00 * vec.x + m01 * vec.y + m02 * vec.z + m03 * vec.w,
m10 * vec.x + m11 * vec.y + m12 * vec.z + m13 * vec.w,
m20 * vec.x + m21 * vec.y + m22 * vec.z + m23 * vec.w,
m30 * vec.x + m31 * vec.y + m32 * vec.z + m33 * vec.w
);
}
Vec3 transformPoint(const Vec3& point) const {
Vec4 result = *this * Vec4(point, 1.0f);
return result.xyz() / result.w;
}
Vec3 transformDirection(const Vec3& direction) const {
Vec4 result = *this * Vec4(direction, 0.0f);
return result.xyz();
}
Mat4& operator+=(const Mat4& other) {
*this = *this + other;
return *this;
}
Mat4& operator-=(const Mat4& other) {
*this = *this - other;
return *this;
}
Mat4& operator*=(const Mat4& other) {
*this = *this * other;
return *this;
}
Mat4& operator*=(float scalar) {
*this = *this * scalar;
return *this;
}
Mat4& operator/=(float scalar) {
*this = *this / scalar;
return *this;
}
bool operator==(const Mat4& other) const {
for (int i = 0; i < 16; ++i) {
if (data[i] != other.data[i]) return false;
}
return true;
}
bool operator!=(const Mat4& other) const {
return !(*this == other);
}
// Matrix operations
float determinant() const {
// Using Laplace expansion for 4x4 determinant
float det = 0;
det += m00 * (m11 * (m22 * m33 - m23 * m32) - m12 * (m21 * m33 - m23 * m31) + m13 * (m21 * m32 - m22 * m31));
det -= m01 * (m10 * (m22 * m33 - m23 * m32) - m12 * (m20 * m33 - m23 * m30) + m13 * (m20 * m32 - m22 * m30));
det += m02 * (m10 * (m21 * m33 - m23 * m31) - m11 * (m20 * m33 - m23 * m30) + m13 * (m20 * m31 - m21 * m30));
det -= m03 * (m10 * (m21 * m32 - m22 * m31) - m11 * (m20 * m32 - m22 * m30) + m12 * (m20 * m31 - m21 * m30));
return det;
}
Mat4 transposed() const {
return Mat4(m00, m10, m20, m30,
m01, m11, m21, m31,
m02, m12, m22, m32,
m03, m13, m23, m33);
}
Mat4 inverse() const {
// This is a simplified inverse implementation
// For production use, consider a more robust implementation
float det = determinant();
if (std::abs(det) < 1e-10f) {
return Mat4(); // Return identity if not invertible
}
Mat4 result;
// Calculate inverse using adjugate matrix divided by determinant
// This is a placeholder - full implementation would be quite lengthy
float invDet = 1.0f / det;
// Note: This is a simplified version - full implementation would calculate all 16 cofactors
result.m00 = (m11 * (m22 * m33 - m23 * m32) - m12 * (m21 * m33 - m23 * m31) + m13 * (m21 * m32 - m22 * m31)) * invDet;
// ... continue for all 16 elements
return result.transposed() * invDet;
}
// Access operators
float& operator()(int row, int col) {
return m[row][col];
}
const float& operator()(int row, int col) const {
return m[row][col];
}
float& operator[](int index) {
return data[index];
}
const float& operator[](int index) const {
return data[index];
}
std::string toString() const {
return "Mat4([" + std::to_string(m00) + ", " + std::to_string(m01) + ", " + std::to_string(m02) + ", " + std::to_string(m03) + "],\n" +
" [" + std::to_string(m10) + ", " + std::to_string(m11) + ", " + std::to_string(m12) + ", " + std::to_string(m13) + "],\n" +
" [" + std::to_string(m20) + ", " + std::to_string(m21) + ", " + std::to_string(m22) + ", " + std::to_string(m23) + "],\n" +
" [" + std::to_string(m30) + ", " + std::to_string(m31) + ", " + std::to_string(m32) + ", " + std::to_string(m33) + "])";
}
};
inline std::ostream& operator<<(std::ostream& os, const Mat4& mat) {
os << mat.toString();
return os;
}
inline Mat4 operator*(float scalar, const Mat4& mat) {
return mat * scalar;
}
// Now you can implement the Ray3 transform method
#include "ray3.hpp"
inline Ray3 Ray3::transform(const Mat4& matrix) const {
Vec3 transformedOrigin = matrix.transformPoint(origin);
Vec3 transformedDirection = matrix.transformDirection(direction);
return Ray3(transformedOrigin, transformedDirection.normalized());
}
#endif