added mats, updated gradient, updated bmp.
This commit is contained in:
2
.gitignore
vendored
Normal file
2
.gitignore
vendored
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
/output/
|
||||||
|
/bin/
|
||||||
73
.vscode/settings.json
vendored
Normal file
73
.vscode/settings.json
vendored
Normal 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"
|
||||||
|
}
|
||||||
|
}
|
||||||
BIN
gradient.bmp
BIN
gradient.bmp
Binary file not shown.
|
Before Width: | Height: | Size: 768 KiB |
100
main.cpp
100
main.cpp
@@ -41,76 +41,41 @@ int main(int argc, char* argv[]) {
|
|||||||
Grid2 grid;
|
Grid2 grid;
|
||||||
|
|
||||||
// Define our target colors at specific positions
|
// Define our target colors at specific positions
|
||||||
Vec4 red = hexToVec4("ff0000"); // Top-left corner
|
Vec4 white = hexToVec4("ffffff"); // Top-left corner (1,1)
|
||||||
Vec4 green = hexToVec4("00ff00"); // Center
|
Vec4 red = hexToVec4("ff0000"); // Top-right corner (1,-1)
|
||||||
Vec4 blue = hexToVec4("0000ff"); // Bottom-right corner
|
Vec4 green = hexToVec4("00ff00"); // Center (0,0)
|
||||||
Vec4 white = hexToVec4("ffffff"); // Top-right corner
|
Vec4 blue = hexToVec4("0000ff"); // Bottom-left corner (-1,-1)
|
||||||
Vec4 black = hexToVec4("000000"); // Bottom-left corner
|
Vec4 black = hexToVec4("000000"); // Bottom-right corner (-1,1)
|
||||||
|
|
||||||
// Create gradient points
|
// Create gradient points
|
||||||
for (int y = 0; y < POINTS_PER_DIM; ++y) {
|
for (int y = 0; y < POINTS_PER_DIM; ++y) {
|
||||||
for (int x = 0; x < POINTS_PER_DIM; ++x) {
|
for (int x = 0; x < POINTS_PER_DIM; ++x) {
|
||||||
// Normalize coordinates to [0, 1]
|
// Normalize coordinates to [-1, 1]
|
||||||
float nx = static_cast<float>(x) / (POINTS_PER_DIM - 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);
|
float ny = (static_cast<float>(y) / (POINTS_PER_DIM - 1)) * 2.0f - 1.0f;
|
||||||
|
|
||||||
// Create position in [-1, 1] range
|
// Create position
|
||||||
Vec2 pos(nx * 2.0f - 1.0f, ny * 2.0f - 1.0f);
|
Vec2 pos(nx, ny);
|
||||||
|
|
||||||
// Calculate interpolated color based on position
|
// Calculate weights for each corner based on distance
|
||||||
Vec4 color;
|
// We'll use bilinear interpolation
|
||||||
|
|
||||||
if (nx + ny <= 1.0f) {
|
// Convert to [0,1] range for interpolation
|
||||||
// Lower triangle: interpolate between red, green, and black
|
float u = (nx + 1.0f) / 2.0f; // maps -1..1 to 0..1
|
||||||
if (nx <= 0.5f && ny <= 0.5f) {
|
float v = (ny + 1.0f) / 2.0f; // maps -1..1 to 0..1
|
||||||
// Bottom-left quadrant: red to black to green
|
|
||||||
float t1 = nx * 2.0f; // Horizontal interpolation
|
// For a more natural gradient, we'll interpolate between the four corners
|
||||||
float t2 = ny * 2.0f; // Vertical interpolation
|
// and blend with the center color based on distance from center
|
||||||
|
|
||||||
if (t1 + t2 <= 1.0f) {
|
// Bilinear interpolation between corners
|
||||||
// Interpolate between red and black
|
Vec4 top = white * (1.0f - u) + red * u;
|
||||||
color = red * (1.0f - t1 - t2) + black * (t1 + t2);
|
Vec4 bottom = blue * (1.0f - u) + black * u;
|
||||||
} else {
|
Vec4 cornerColor = top * (1.0f - v) + bottom * v;
|
||||||
// Interpolate between black and green
|
|
||||||
color = black * (2.0f - t1 - t2) + green * (t1 + t2 - 1.0f);
|
// Calculate distance from center (0,0)
|
||||||
}
|
float distFromCenter = std::sqrt(nx * nx + ny * ny) / std::sqrt(2.0f); // normalize to [0,1]
|
||||||
} else {
|
|
||||||
// Use bilinear interpolation for other areas
|
Vec4 color = green * (1.0f - distFromCenter) + cornerColor * distFromCenter;
|
||||||
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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
grid.addPoint(pos, color);
|
grid.addPoint(pos, color);
|
||||||
}
|
}
|
||||||
@@ -122,11 +87,12 @@ int main(int argc, char* argv[]) {
|
|||||||
// Save as BMP
|
// Save as BMP
|
||||||
if (BMPWriter::saveBMP("output/gradient.bmp", imageData, WIDTH, HEIGHT)) {
|
if (BMPWriter::saveBMP("output/gradient.bmp", imageData, WIDTH, HEIGHT)) {
|
||||||
std::cout << "Gradient image saved as 'gradient.bmp'" << std::endl;
|
std::cout << "Gradient image saved as 'gradient.bmp'" << std::endl;
|
||||||
std::cout << "Colors: " << std::endl;
|
std::cout << "Color positions: " << std::endl;
|
||||||
std::cout << " Top-left: ff0000 (red)" << 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 << " Center: 00ff00 (green)" << std::endl;
|
||||||
std::cout << " Bottom-right: 0000ff (blue)" << std::endl;
|
std::cout << " Bottom-left: 0000ff (blue)" << std::endl;
|
||||||
std::cout << " Gradient between ffffff and 000000 throughout" << std::endl;
|
std::cout << " Bottom-right: 000000 (black)" << std::endl;
|
||||||
} else {
|
} else {
|
||||||
std::cerr << "Failed to save gradient image" << std::endl;
|
std::cerr << "Failed to save gradient image" << std::endl;
|
||||||
return 1;
|
return 1;
|
||||||
|
|||||||
Binary file not shown.
@@ -6,6 +6,7 @@
|
|||||||
#include <cstring>
|
#include <cstring>
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
|
#include <filesystem>
|
||||||
#include "vec3.hpp"
|
#include "vec3.hpp"
|
||||||
|
|
||||||
class BMPWriter {
|
class BMPWriter {
|
||||||
@@ -34,6 +35,18 @@ private:
|
|||||||
};
|
};
|
||||||
#pragma pack(pop)
|
#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:
|
public:
|
||||||
// Save a 2D vector of Vec3 (RGB) colors as BMP
|
// Save a 2D vector of Vec3 (RGB) colors as BMP
|
||||||
// Vec3 components: x = red, y = green, z = blue (values in range [0,1])
|
// Vec3 components: x = red, y = green, z = blue (values in range [0,1])
|
||||||
@@ -78,6 +91,11 @@ public:
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Create directory if needed
|
||||||
|
if (!createDirectoryIfNeeded(filename)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
BMPHeader header;
|
BMPHeader header;
|
||||||
BMPInfoHeader infoHeader;
|
BMPInfoHeader infoHeader;
|
||||||
|
|
||||||
@@ -121,6 +139,11 @@ public:
|
|||||||
|
|
||||||
private:
|
private:
|
||||||
static bool saveBMP(const std::string& filename, const std::vector<std::vector<Vec3>>& pixels, int width, int height) {
|
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;
|
BMPHeader header;
|
||||||
BMPInfoHeader infoHeader;
|
BMPInfoHeader infoHeader;
|
||||||
|
|
||||||
|
|||||||
166
util/mat2.hpp
Normal file
166
util/mat2.hpp
Normal 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
232
util/mat3.hpp
Normal 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
310
util/mat4.hpp
Normal 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
|
||||||
Reference in New Issue
Block a user