.
This commit is contained in:
1 parent
a0b7e4c0d8
commit
6883d103ff
36 files changed
+2736
-1428
No files matched your search
@@ -1,3 +1,637 @@
|
||||
//
|
||||
// Created by Vicente Ferrari Smith on 27.02.26.
|
||||
//
|
||||
/*
|
||||
See LICENSE folder for this sample’s licensing information.
|
||||
|
||||
Abstract:
|
||||
Implementation of vector, matrix, and quaternion math utility functions useful for 3D graphics
|
||||
rendering with Metal
|
||||
|
||||
Metal uses column-major matrices and column-vector inputs.
|
||||
|
||||
linearIndex cr example with reference elements
|
||||
0 4 8 12 00 10 20 30 sx 10 20 tx
|
||||
1 5 9 13 --> 01 11 21 31 --> 01 sy 21 ty
|
||||
2 6 10 14 02 12 22 32 02 12 sz tz
|
||||
3 7 11 15 03 13 23 33 03 13 1/d 33
|
||||
|
||||
The "cr" names are for <column><row>
|
||||
*/
|
||||
|
||||
#include "AAPLMathUtilities.h"
|
||||
#include <assert.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
uint32_t seed_lo, seed_hi;
|
||||
|
||||
static float inline F16ToF32(const __fp16 *address) {
|
||||
return *address;
|
||||
}
|
||||
|
||||
float AAPL_SIMD_OVERLOAD float32_from_float16(uint16_t i) {
|
||||
return F16ToF32((__fp16 *)&i);
|
||||
}
|
||||
|
||||
static inline void F32ToF16(float F32, __fp16 *F16Ptr) {
|
||||
*F16Ptr = F32;
|
||||
}
|
||||
|
||||
uint16_t AAPL_SIMD_OVERLOAD float16_from_float32(float f) {
|
||||
uint16_t f16;
|
||||
F32ToF16(f, (__fp16 *)&f16);
|
||||
return f16;
|
||||
}
|
||||
|
||||
vector_float3 AAPL_SIMD_OVERLOAD generate_random_vector(float min, float max)
|
||||
{
|
||||
vector_float3 rand;
|
||||
|
||||
float range = max - min;
|
||||
rand.x = ((double)random() / (double) (0x7FFFFFFF)) * range + min;
|
||||
rand.y = ((double)random() / (double) (0x7FFFFFFF)) * range + min;
|
||||
rand.z = ((double)random() / (double) (0x7FFFFFFF)) * range + min;
|
||||
|
||||
return rand;
|
||||
}
|
||||
|
||||
void AAPL_SIMD_OVERLOAD seedRand(uint32_t seed) {
|
||||
seed_lo = seed; seed_hi = ~seed;
|
||||
}
|
||||
|
||||
int32_t AAPL_SIMD_OVERLOAD randi(void) {
|
||||
seed_hi = (seed_hi<<16) + (seed_hi>>16);
|
||||
seed_hi += seed_lo; seed_lo += seed_hi;
|
||||
return seed_hi;
|
||||
}
|
||||
|
||||
float AAPL_SIMD_OVERLOAD randf(float x) {
|
||||
return (x * randi() / (float)0x7FFFFFFF);
|
||||
}
|
||||
|
||||
float AAPL_SIMD_OVERLOAD degrees_from_radians(float radians) {
|
||||
return (radians / M_PI) * 180;
|
||||
}
|
||||
|
||||
float AAPL_SIMD_OVERLOAD radians_from_degrees(float degrees) {
|
||||
return (degrees / 180) * M_PI;
|
||||
}
|
||||
|
||||
static vector_float3 AAPL_SIMD_OVERLOAD vector_make(float x, float y, float z) {
|
||||
return (vector_float3){ x, y, z };
|
||||
}
|
||||
|
||||
vector_float3 AAPL_SIMD_OVERLOAD vector_lerp(vector_float3 v0, vector_float3 v1, float t) {
|
||||
return ((1 - t) * v0) + (t * v1);
|
||||
}
|
||||
|
||||
vector_float4 AAPL_SIMD_OVERLOAD vector_lerp(vector_float4 v0, vector_float4 v1, float t) {
|
||||
return ((1 - t) * v0) + (t * v1);
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// matrix_make_rows takes input data with rows of elements.
|
||||
// This way, the calling code matrix data can look like the rows
|
||||
// of a matrix made for transforming column vectors.
|
||||
|
||||
// Indices are m<column><row>
|
||||
matrix_float3x3 AAPL_SIMD_OVERLOAD matrix_make_rows(
|
||||
float m00, float m10, float m20,
|
||||
float m01, float m11, float m21,
|
||||
float m02, float m12, float m22) {
|
||||
return (matrix_float3x3){ {
|
||||
{ m00, m01, m02 }, // each line here provides column data
|
||||
{ m10, m11, m12 },
|
||||
{ m20, m21, m22 } } };
|
||||
}
|
||||
|
||||
matrix_float4x4 AAPL_SIMD_OVERLOAD matrix_make_rows(
|
||||
float m00, float m10, float m20, float m30,
|
||||
float m01, float m11, float m21, float m31,
|
||||
float m02, float m12, float m22, float m32,
|
||||
float m03, float m13, float m23, float m33) {
|
||||
return (matrix_float4x4){ {
|
||||
{ m00, m01, m02, m03 }, // each line here provides column data
|
||||
{ m10, m11, m12, m13 },
|
||||
{ m20, m21, m22, m23 },
|
||||
{ m30, m31, m32, m33 } } };
|
||||
}
|
||||
|
||||
// each arg is a column vector
|
||||
matrix_float3x3 AAPL_SIMD_OVERLOAD matrix_make_columns(
|
||||
vector_float3 col0,
|
||||
vector_float3 col1,
|
||||
vector_float3 col2) {
|
||||
return (matrix_float3x3){ col0, col1, col2 };
|
||||
}
|
||||
|
||||
// each arg is a column vector
|
||||
matrix_float4x4 AAPL_SIMD_OVERLOAD matrix_make_columns(
|
||||
vector_float4 col0,
|
||||
vector_float4 col1,
|
||||
vector_float4 col2,
|
||||
vector_float4 col3) {
|
||||
return (matrix_float4x4){ col0, col1, col2, col3 };
|
||||
}
|
||||
|
||||
matrix_float3x3 AAPL_SIMD_OVERLOAD matrix3x3_from_quaternion(quaternion_float q) {
|
||||
float xx = q.x * q.x;
|
||||
float xy = q.x * q.y;
|
||||
float xz = q.x * q.z;
|
||||
float xw = q.x * q.w;
|
||||
float yy = q.y * q.y;
|
||||
float yz = q.y * q.z;
|
||||
float yw = q.y * q.w;
|
||||
float zz = q.z * q.z;
|
||||
float zw = q.z * q.w;
|
||||
|
||||
// indices are m<column><row>
|
||||
float m00 = 1 - 2 * (yy + zz);
|
||||
float m10 = 2 * (xy - zw);
|
||||
float m20 = 2 * (xz + yw);
|
||||
|
||||
float m01 = 2 * (xy + zw);
|
||||
float m11 = 1 - 2 * (xx + zz);
|
||||
float m21 = 2 * (yz - xw);
|
||||
|
||||
float m02 = 2 * (xz - yw);
|
||||
float m12 = 2 * (yz + xw);
|
||||
float m22 = 1 - 2 * (xx + yy);
|
||||
|
||||
return matrix_make_rows(m00, m10, m20,
|
||||
m01, m11, m21,
|
||||
m02, m12, m22);
|
||||
}
|
||||
|
||||
matrix_float3x3 AAPL_SIMD_OVERLOAD matrix3x3_rotation(float radians, vector_float3 axis) {
|
||||
axis = vector_normalize(axis);
|
||||
float ct = cosf(radians);
|
||||
float st = sinf(radians);
|
||||
float ci = 1 - ct;
|
||||
float x = axis.x, y = axis.y, z = axis.z;
|
||||
return matrix_make_rows( ct + x * x * ci, x * y * ci - z * st, x * z * ci + y * st,
|
||||
y * x * ci + z * st, ct + y * y * ci, y * z * ci - x * st,
|
||||
z * x * ci - y * st, z * y * ci + x * st, ct + z * z * ci );
|
||||
}
|
||||
|
||||
matrix_float3x3 AAPL_SIMD_OVERLOAD matrix3x3_rotation(float radians, float x, float y, float z) {
|
||||
return matrix3x3_rotation(radians, vector_make(x, y, z));
|
||||
}
|
||||
|
||||
matrix_float3x3 AAPL_SIMD_OVERLOAD matrix3x3_scale(float sx, float sy, float sz) {
|
||||
return matrix_make_rows(sx, 0, 0,
|
||||
0, sy, 0,
|
||||
0, 0, sz);
|
||||
}
|
||||
|
||||
matrix_float3x3 AAPL_SIMD_OVERLOAD matrix3x3_scale(vector_float3 s) {
|
||||
return matrix_make_rows(s.x, 0, 0,
|
||||
0, s.y, 0,
|
||||
0, 0, s.z);
|
||||
}
|
||||
|
||||
matrix_float3x3 AAPL_SIMD_OVERLOAD matrix3x3_upper_left(matrix_float4x4 m) {
|
||||
vector_float3 x = m.columns[0].xyz;
|
||||
vector_float3 y = m.columns[1].xyz;
|
||||
vector_float3 z = m.columns[2].xyz;
|
||||
return matrix_make_columns(x, y, z);
|
||||
}
|
||||
|
||||
matrix_float3x3 AAPL_SIMD_OVERLOAD matrix_inverse_transpose(matrix_float3x3 m) {
|
||||
return matrix_invert(matrix_transpose(m));
|
||||
}
|
||||
|
||||
matrix_float4x4 AAPL_SIMD_OVERLOAD matrix4x4_from_quaternion(quaternion_float q) {
|
||||
|
||||
float xx = q.x * q.x;
|
||||
float xy = q.x * q.y;
|
||||
float xz = q.x * q.z;
|
||||
float xw = q.x * q.w;
|
||||
float yy = q.y * q.y;
|
||||
float yz = q.y * q.z;
|
||||
float yw = q.y * q.w;
|
||||
float zz = q.z * q.z;
|
||||
float zw = q.z * q.w;
|
||||
|
||||
// indices are m<column><row>
|
||||
float m00 = 1 - 2 * (yy + zz);
|
||||
float m10 = 2 * (xy - zw);
|
||||
float m20 = 2 * (xz + yw);
|
||||
|
||||
float m01 = 2 * (xy + zw);
|
||||
float m11 = 1 - 2 * (xx + zz);
|
||||
float m21 = 2 * (yz - xw);
|
||||
|
||||
float m02 = 2 * (xz - yw);
|
||||
float m12 = 2 * (yz + xw);
|
||||
float m22 = 1 - 2 * (xx + yy);
|
||||
|
||||
matrix_float4x4 matrix = matrix_make_rows(m00, m10, m20, 0,
|
||||
m01, m11, m21, 0,
|
||||
m02, m12, m22, 0,
|
||||
0, 0, 0, 1);
|
||||
return matrix;
|
||||
}
|
||||
|
||||
matrix_float4x4 AAPL_SIMD_OVERLOAD matrix4x4_rotation(float radians, vector_float3 axis) {
|
||||
axis = vector_normalize(axis);
|
||||
float ct = cosf(radians);
|
||||
float st = sinf(radians);
|
||||
float ci = 1 - ct;
|
||||
float x = axis.x, y = axis.y, z = axis.z;
|
||||
return matrix_make_rows(
|
||||
ct + x * x * ci, x * y * ci - z * st, x * z * ci + y * st, 0,
|
||||
y * x * ci + z * st, ct + y * y * ci, y * z * ci - x * st, 0,
|
||||
z * x * ci - y * st, z * y * ci + x * st, ct + z * z * ci, 0,
|
||||
0, 0, 0, 1);
|
||||
}
|
||||
|
||||
matrix_float4x4 AAPL_SIMD_OVERLOAD matrix4x4_rotation(float radians, float x, float y, float z) {
|
||||
return matrix4x4_rotation(radians, vector_make(x, y, z));
|
||||
}
|
||||
|
||||
matrix_float4x4 AAPL_SIMD_OVERLOAD matrix4x4_identity(void) {
|
||||
return matrix_make_rows(1, 0, 0, 0,
|
||||
0, 1, 0, 0,
|
||||
0, 0, 1, 0,
|
||||
0, 0, 0, 1 );
|
||||
}
|
||||
|
||||
matrix_float4x4 AAPL_SIMD_OVERLOAD matrix4x4_scale(float sx, float sy, float sz) {
|
||||
return matrix_make_rows(sx, 0, 0, 0,
|
||||
0, sy, 0, 0,
|
||||
0, 0, sz, 0,
|
||||
0, 0, 0, 1 );
|
||||
}
|
||||
|
||||
matrix_float4x4 AAPL_SIMD_OVERLOAD matrix4x4_scale(vector_float3 s) {
|
||||
return matrix_make_rows(s.x, 0, 0, 0,
|
||||
0, s.y, 0, 0,
|
||||
0, 0, s.z, 0,
|
||||
0, 0, 0, 1 );
|
||||
}
|
||||
|
||||
matrix_float4x4 AAPL_SIMD_OVERLOAD matrix4x4_translation(float tx, float ty, float tz) {
|
||||
return matrix_make_rows(1, 0, 0, tx,
|
||||
0, 1, 0, ty,
|
||||
0, 0, 1, tz,
|
||||
0, 0, 0, 1 );
|
||||
}
|
||||
|
||||
matrix_float4x4 AAPL_SIMD_OVERLOAD matrix4x4_translation(vector_float3 t) {
|
||||
return matrix_make_rows(1, 0, 0, t.x,
|
||||
0, 1, 0, t.y,
|
||||
0, 0, 1, t.z,
|
||||
0, 0, 0, 1 );
|
||||
}
|
||||
|
||||
matrix_float4x4 AAPL_SIMD_OVERLOAD matrix4x4_scale_translation(vector_float3 s, vector_float3 t) {
|
||||
return matrix_make_rows(s.x, 0, 0, t.x,
|
||||
0, s.y, 0, t.y,
|
||||
0, 0, s.z, t.z,
|
||||
0, 0, 0, 1 );
|
||||
}
|
||||
|
||||
|
||||
matrix_float4x4 AAPL_SIMD_OVERLOAD matrix_look_at_left_hand(vector_float3 eye,
|
||||
vector_float3 target,
|
||||
vector_float3 up) {
|
||||
vector_float3 z = vector_normalize(target - eye);
|
||||
vector_float3 x = vector_normalize(vector_cross(up, z));
|
||||
vector_float3 y = vector_cross(z, x);
|
||||
vector_float3 t = vector_make(-vector_dot(x, eye), -vector_dot(y, eye), -vector_dot(z, eye));
|
||||
|
||||
return matrix_make_rows(x.x, x.y, x.z, t.x,
|
||||
y.x, y.y, y.z, t.y,
|
||||
z.x, z.y, z.z, t.z,
|
||||
0, 0, 0, 1 );
|
||||
}
|
||||
|
||||
matrix_float4x4 AAPL_SIMD_OVERLOAD matrix_look_at_left_hand(float eyeX, float eyeY, float eyeZ,
|
||||
float centerX, float centerY, float centerZ,
|
||||
float upX, float upY, float upZ) {
|
||||
vector_float3 eye = vector_make(eyeX, eyeY, eyeZ);
|
||||
vector_float3 center = vector_make(centerX, centerY, centerZ);
|
||||
vector_float3 up = vector_make(upX, upY, upZ);
|
||||
|
||||
return matrix_look_at_left_hand(eye, center, up);
|
||||
}
|
||||
|
||||
matrix_float4x4 AAPL_SIMD_OVERLOAD matrix_look_at_right_hand(vector_float3 eye,
|
||||
vector_float3 target,
|
||||
vector_float3 up) {
|
||||
vector_float3 z = vector_normalize(eye - target);
|
||||
vector_float3 x = vector_normalize(vector_cross(up, z));
|
||||
vector_float3 y = vector_cross(z, x);
|
||||
vector_float3 t = vector_make(-vector_dot(x, eye), -vector_dot(y, eye), -vector_dot(z, eye));
|
||||
|
||||
return matrix_make_rows(x.x, x.y, x.z, t.x,
|
||||
y.x, y.y, y.z, t.y,
|
||||
z.x, z.y, z.z, t.z,
|
||||
0, 0, 0, 1 );
|
||||
}
|
||||
|
||||
matrix_float4x4 AAPL_SIMD_OVERLOAD matrix_look_at_right_hand(float eyeX, float eyeY, float eyeZ,
|
||||
float centerX, float centerY, float centerZ,
|
||||
float upX, float upY, float upZ) {
|
||||
vector_float3 eye = vector_make(eyeX, eyeY, eyeZ);
|
||||
vector_float3 center = vector_make(centerX, centerY, centerZ);
|
||||
vector_float3 up = vector_make(upX, upY, upZ);
|
||||
|
||||
return matrix_look_at_right_hand(eye, center, up);
|
||||
}
|
||||
|
||||
matrix_float4x4 AAPL_SIMD_OVERLOAD matrix_ortho_left_hand(float left, float right, float bottom, float top, float nearZ, float farZ) {
|
||||
return matrix_make_rows(
|
||||
2 / (right - left), 0, 0, (left + right) / (left - right),
|
||||
0, 2 / (top - bottom), 0, (top + bottom) / (bottom - top),
|
||||
0, 0, 1 / (farZ - nearZ), nearZ / (nearZ - farZ),
|
||||
0, 0, 0, 1 );
|
||||
}
|
||||
|
||||
matrix_float4x4 AAPL_SIMD_OVERLOAD matrix_ortho_right_hand(float left, float right, float bottom, float top, float nearZ, float farZ) {
|
||||
return matrix_make_rows(
|
||||
2 / (right - left), 0, 0, (left + right) / (left - right),
|
||||
0, 2 / (top - bottom), 0, (top + bottom) / (bottom - top),
|
||||
0, 0, -1 / (farZ - nearZ), nearZ / (nearZ - farZ),
|
||||
0, 0, 0, 1 );
|
||||
}
|
||||
|
||||
matrix_float4x4 AAPL_SIMD_OVERLOAD matrix_perspective_left_hand(float fovyRadians, float aspect, float nearZ, float farZ) {
|
||||
float ys = 1 / tanf(fovyRadians * 0.5);
|
||||
float xs = ys / aspect;
|
||||
float zs = farZ / (farZ - nearZ);
|
||||
return matrix_make_rows(xs, 0, 0, 0,
|
||||
0, ys, 0, 0,
|
||||
0, 0, zs, -nearZ * zs,
|
||||
0, 0, 1, 0 );
|
||||
}
|
||||
|
||||
matrix_float4x4 AAPL_SIMD_OVERLOAD matrix_perspective_right_hand(float fovyRadians, float aspect, float nearZ, float farZ) {
|
||||
float ys = 1 / tanf(fovyRadians * 0.5);
|
||||
float xs = ys / aspect;
|
||||
float zs = farZ / (nearZ - farZ);
|
||||
return matrix_make_rows(xs, 0, 0, 0,
|
||||
0, ys, 0, 0,
|
||||
0, 0, zs, nearZ * zs,
|
||||
0, 0, -1, 0 );
|
||||
}
|
||||
|
||||
matrix_float4x4 AAPL_SIMD_OVERLOAD matrix_perspective_frustum_right_hand(float l, float r, float b, float t, float n, float f) {
|
||||
return matrix_make_rows(
|
||||
2 * n / (r - l), 0, (r + l) / (r - l), 0,
|
||||
0, 2 * n / (t - b), (t + b) / (t - b), 0,
|
||||
0, 0, -f / (f - n), -f * n / (f - n),
|
||||
0, 0, -1, 0 );
|
||||
}
|
||||
|
||||
matrix_float4x4 AAPL_SIMD_OVERLOAD matrix_inverse_transpose(matrix_float4x4 m) {
|
||||
return matrix_invert(matrix_transpose(m));
|
||||
}
|
||||
|
||||
quaternion_float AAPL_SIMD_OVERLOAD quaternion(float x, float y, float z, float w) {
|
||||
return (quaternion_float){ x, y, z, w };
|
||||
}
|
||||
|
||||
quaternion_float AAPL_SIMD_OVERLOAD quaternion(vector_float3 v, float w) {
|
||||
return (quaternion_float){ v.x, v.y, v.z, w };
|
||||
}
|
||||
|
||||
quaternion_float AAPL_SIMD_OVERLOAD quaternion_identity() {
|
||||
return quaternion(0, 0, 0, 1);
|
||||
}
|
||||
|
||||
quaternion_float AAPL_SIMD_OVERLOAD quaternion_from_axis_angle(vector_float3 axis, float radians) {
|
||||
float t = radians * 0.5;
|
||||
return quaternion(axis.x * sinf(t), axis.y * sinf(t), axis.z * sinf(t), cosf(t));
|
||||
}
|
||||
|
||||
quaternion_float AAPL_SIMD_OVERLOAD quaternion_from_euler(vector_float3 euler) {
|
||||
quaternion_float q;
|
||||
|
||||
float cx = cosf(euler.x / 2.f);
|
||||
float cy = cosf(euler.y / 2.f);
|
||||
float cz = cosf(euler.z / 2.f);
|
||||
float sx = sinf(euler.x / 2.f);
|
||||
float sy = sinf(euler.y / 2.f);
|
||||
float sz = sinf(euler.z / 2.f);
|
||||
|
||||
q.w = cx * cy * cz + sx * sy * sz;
|
||||
q.x = sx * cy * cz - cx * sy * sz;
|
||||
q.y = cx * sy * cz + sx * cy * sz;
|
||||
q.z = cx * cy * sz - sx * sy * cz;
|
||||
|
||||
return q;
|
||||
}
|
||||
|
||||
quaternion_float AAPL_SIMD_OVERLOAD quaternion(matrix_float3x3 m) {
|
||||
float m00 = m.columns[0].x;
|
||||
float m11 = m.columns[1].y;
|
||||
float m22 = m.columns[2].z;
|
||||
float x = sqrtf(1 + m00 - m11 - m22) * 0.5;
|
||||
float y = sqrtf(1 - m00 + m11 - m22) * 0.5;
|
||||
float z = sqrtf(1 - m00 - m11 + m22) * 0.5;
|
||||
float w = sqrtf(1 + m00 + m11 + m22) * 0.5;
|
||||
return quaternion(x, y, z, w);
|
||||
}
|
||||
|
||||
quaternion_float AAPL_SIMD_OVERLOAD quaternion(matrix_float4x4 m) {
|
||||
return quaternion(matrix3x3_upper_left(m));
|
||||
}
|
||||
|
||||
float AAPL_SIMD_OVERLOAD quaternion_length(quaternion_float q) {
|
||||
// return sqrt(q.x*q.x + q.y*q.y + q.z*q.z + q.w*q.w);
|
||||
return vector_length(q);
|
||||
}
|
||||
|
||||
float AAPL_SIMD_OVERLOAD quaternion_length_squared(quaternion_float q) {
|
||||
// return q.x*q.x + q.y*q.y + q.z*q.z + q.w*q.w;
|
||||
return vector_length_squared(q);
|
||||
}
|
||||
|
||||
vector_float3 AAPL_SIMD_OVERLOAD quaternion_axis(quaternion_float q) {
|
||||
// This query doesn't make sense if w > 1, but we do our best by
|
||||
// forcing q to be a unit quaternion if it obviously isn't
|
||||
if (q.w > 1.0)
|
||||
{
|
||||
q = quaternion_normalize(q);
|
||||
}
|
||||
|
||||
float axisLen = sqrtf(1 - q.w * q.w);
|
||||
|
||||
if (axisLen < 1e-5)
|
||||
{
|
||||
// At lengths this small, direction is arbitrary
|
||||
return vector_make(1, 0, 0);
|
||||
}
|
||||
else
|
||||
{
|
||||
return vector_make(q.x / axisLen, q.y / axisLen, q.z / axisLen);
|
||||
}
|
||||
}
|
||||
|
||||
float AAPL_SIMD_OVERLOAD quaternion_angle(quaternion_float q) {
|
||||
return 2 * acosf(q.w);
|
||||
}
|
||||
|
||||
quaternion_float AAPL_SIMD_OVERLOAD quaternion_normalize(quaternion_float q) {
|
||||
// return q / quaternion_length(q);
|
||||
return vector_normalize(q);
|
||||
}
|
||||
|
||||
quaternion_float AAPL_SIMD_OVERLOAD quaternion_inverse(quaternion_float q) {
|
||||
return quaternion_conjugate(q) / quaternion_length_squared(q);
|
||||
}
|
||||
|
||||
quaternion_float AAPL_SIMD_OVERLOAD quaternion_conjugate(quaternion_float q) {
|
||||
return quaternion(-q.x, -q.y, -q.z, q.w);
|
||||
}
|
||||
|
||||
quaternion_float AAPL_SIMD_OVERLOAD quaternion_multiply(quaternion_float q0, quaternion_float q1) {
|
||||
quaternion_float q;
|
||||
|
||||
q.x = q0.w*q1.x + q0.x*q1.w + q0.y*q1.z - q0.z*q1.y;
|
||||
q.y = q0.w*q1.y - q0.x*q1.z + q0.y*q1.w + q0.z*q1.x;
|
||||
q.z = q0.w*q1.z + q0.x*q1.y - q0.y*q1.x + q0.z*q1.w;
|
||||
q.w = q0.w*q1.w - q0.x*q1.x - q0.y*q1.y - q0.z*q1.z;
|
||||
return q;
|
||||
}
|
||||
|
||||
quaternion_float AAPL_SIMD_OVERLOAD quaternion_slerp(quaternion_float q0, quaternion_float q1, float t) {
|
||||
quaternion_float q;
|
||||
|
||||
float cosHalfTheta = vector_dot(q0, q1);
|
||||
if (fabs(cosHalfTheta) >= 1.f) ///q0=q1 or q0=q1
|
||||
{
|
||||
return q0;
|
||||
}
|
||||
|
||||
float halfTheta = acosf(cosHalfTheta);
|
||||
float sinHalfTheta = sqrtf(1.f - cosHalfTheta * cosHalfTheta);
|
||||
if (fabs(sinHalfTheta) < 0.001f)
|
||||
{ // q0 & q1 180 degrees not defined
|
||||
return q0*0.5f + q1*0.5f;
|
||||
}
|
||||
float srcWeight = sin((1 - t) * halfTheta) / sinHalfTheta;
|
||||
float dstWeight = sin(t * halfTheta) / sinHalfTheta;
|
||||
|
||||
q = srcWeight*q0 + dstWeight*q1;
|
||||
|
||||
return q;
|
||||
}
|
||||
|
||||
vector_float3 AAPL_SIMD_OVERLOAD quaternion_rotate_vector(quaternion_float q, vector_float3 v) {
|
||||
vector_float3 qp = vector_make(q.x, q.y, q.z);
|
||||
float w = q.w;
|
||||
return 2 * vector_dot(qp, v) * qp +
|
||||
((w * w) - vector_dot(qp, qp)) * v +
|
||||
2 * w * vector_cross(qp, v);
|
||||
}
|
||||
|
||||
quaternion_float AAPL_SIMD_OVERLOAD quaternion_from_matrix3x3(matrix_float3x3 m)
|
||||
{
|
||||
quaternion_float q;
|
||||
|
||||
float trace = 1 + m.columns[0][0] + m.columns[1][1] + m.columns[2][2];
|
||||
|
||||
if(trace > 0)
|
||||
{
|
||||
float diagonal = sqrt(trace) * 2.0;
|
||||
|
||||
q.x = (m.columns[2][1] - m.columns[1][2]) / diagonal;
|
||||
q.y = (m.columns[0][2] - m.columns[2][0]) / diagonal;
|
||||
q.z = (m.columns[1][0] - m.columns[0][1]) / diagonal;
|
||||
q.w = diagonal / 4.0;
|
||||
|
||||
} else if ((m.columns[0][0] > m.columns[1][1] ) &&
|
||||
(m.columns[0][0] > m.columns[2][2])) {
|
||||
|
||||
float diagonal = sqrt( 1.0 + m.columns[0][0] - m.columns[1][1] - m.columns[2][2] ) * 2.0;
|
||||
|
||||
q.x = diagonal / 4.0;
|
||||
q.y = (m.columns[0][1] + m.columns[1][0]) / diagonal;
|
||||
q.z = (m.columns[0][2] + m.columns[2][0]) / diagonal;
|
||||
q.w = (m.columns[2][1] - m.columns[1][2]) / diagonal;
|
||||
|
||||
} else if ( m.columns[1][1] > m.columns[2][2]) {
|
||||
|
||||
float diagonal = sqrt(1.0 + m.columns[1][1] - m.columns[0][0] - m.columns[2][2]) * 2.0;
|
||||
|
||||
q.x = (m.columns[0][1] + m.columns[1][0]) / diagonal;
|
||||
q.y = diagonal / 4.0;
|
||||
q.z = (m.columns[1][2] + m.columns[2][1]) / diagonal;
|
||||
q.w = (m.columns[0][2] - m.columns[2][0]) / diagonal;
|
||||
|
||||
} else {
|
||||
|
||||
float diagonal = sqrt(1.0 + m.columns[2][2] - m.columns[0][0] - m.columns[1][1]) * 2.0;
|
||||
|
||||
q.x = (m.columns[0][2] + m.columns[2][0]) / diagonal;
|
||||
q.y = (m.columns[1][2] + m.columns[2][1]) / diagonal;
|
||||
q.z = diagonal / 4.0;
|
||||
q.w = (m.columns[1][0] - m.columns[0][1]) / diagonal;
|
||||
}
|
||||
|
||||
q = quaternion_normalize(q);
|
||||
return q;
|
||||
}
|
||||
|
||||
static inline quaternion_float AAPL_SIMD_OVERLOAD quaternion_from_direction_vectors(vector_float3 forward, vector_float3 up, int right_handed) {
|
||||
|
||||
forward = vector_normalize(forward);
|
||||
up = vector_normalize(up);
|
||||
|
||||
vector_float3 side = vector_normalize(vector_cross(up, forward));
|
||||
|
||||
matrix_float3x3 m = { side, up, forward };
|
||||
|
||||
quaternion_float q = quaternion_from_matrix3x3(m);
|
||||
|
||||
if(right_handed) {
|
||||
q = q.yxwz;
|
||||
q.xw = -q.xw;
|
||||
}
|
||||
|
||||
q = vector_normalize(q);
|
||||
|
||||
return q;
|
||||
}
|
||||
|
||||
quaternion_float AAPL_SIMD_OVERLOAD quaternion_from_direction_vectors_right_hand(vector_float3 forward, vector_float3 up) {
|
||||
|
||||
return quaternion_from_direction_vectors(forward, up, 1);
|
||||
}
|
||||
|
||||
quaternion_float AAPL_SIMD_OVERLOAD quaternion_from_direction_vectors_left_hand(vector_float3 forward, vector_float3 up) {
|
||||
|
||||
return quaternion_from_direction_vectors(forward, up, 0);
|
||||
}
|
||||
|
||||
vector_float3 AAPL_SIMD_OVERLOAD forward_direction_vector_from_quaternion(quaternion_float q) {
|
||||
vector_float3 direction;
|
||||
direction.x = 2.0 * (q.x*q.z - q.w*q.y);
|
||||
direction.y = 2.0 * (q.y*q.z + q.w*q.x);
|
||||
direction.z = 1.0 - 2.0 * ((q.x * q.x) + (q.y * q.y));
|
||||
|
||||
direction = vector_normalize(direction);
|
||||
return direction;
|
||||
}
|
||||
|
||||
vector_float3 AAPL_SIMD_OVERLOAD up_direction_vector_from_quaternion(quaternion_float q) {
|
||||
vector_float3 direction;
|
||||
direction.x = 2.0 * (q.x*q.y + q.w*q.z);
|
||||
direction.y = 1.0 - 2.0 * (q.x*q.x + q.z*q.z);
|
||||
direction.z = 2.0 * (q.y*q.z - q.w*q.x);
|
||||
|
||||
direction = vector_normalize(direction);
|
||||
// Negate for a right-handed coordinate system
|
||||
return direction;
|
||||
}
|
||||
|
||||
vector_float3 AAPL_SIMD_OVERLOAD right_direction_vector_from_quaternion(quaternion_float q) {
|
||||
vector_float3 direction;
|
||||
direction.x = 1.0 - 2.0 * (q.y * q.y + q.z * q.z);
|
||||
direction.y = 2.0 * (q.x * q.y - q.w * q.z);
|
||||
direction.z = 2.0 * (q.x * q.z + q.w * q.y);
|
||||
|
||||
direction = vector_normalize(direction);
|
||||
// Negate for a right-handed coordinate system
|
||||
return direction;
|
||||
}
|
||||
@@ -1,8 +1,266 @@
|
||||
//
|
||||
// Created by Vicente Ferrari Smith on 27.02.26.
|
||||
//
|
||||
/*
|
||||
See LICENSE folder for this sample’s licensing information.
|
||||
|
||||
#ifndef V_AAPLMATHUTILITIES_H
|
||||
#define V_AAPLMATHUTILITIES_H
|
||||
Abstract:
|
||||
Header for vector, matrix, and quaternion math utility functions useful for 3D graphics rendering.
|
||||
*/
|
||||
|
||||
#endif //V_AAPLMATHUTILITIES_H
|
||||
#include <stdlib.h>
|
||||
#include <simd/simd.h>
|
||||
|
||||
// Because these are common methods, allow other libraries to overload their implementation.
|
||||
#define AAPL_SIMD_OVERLOAD __attribute__((__overloadable__))
|
||||
|
||||
/// A single-precision quaternion type.
|
||||
typedef vector_float4 quaternion_float;
|
||||
|
||||
/// Given a uint16_t encoded as a 16-bit float, returns a 32-bit float.
|
||||
float AAPL_SIMD_OVERLOAD float32_from_float16(uint16_t i);
|
||||
|
||||
// Given a 32-bit float, returns a uint16_t encoded as a 16-bit float.
|
||||
uint16_t AAPL_SIMD_OVERLOAD float16_from_float32(float f);
|
||||
|
||||
/// Returns the number of degrees in the specified number of radians.
|
||||
float AAPL_SIMD_OVERLOAD degrees_from_radians(float radians);
|
||||
|
||||
/// Returns the number of radians in the specified number of degrees.
|
||||
float AAPL_SIMD_OVERLOAD radians_from_degrees(float degrees);
|
||||
|
||||
// Generates a random float value inside the given range.
|
||||
inline static float AAPL_SIMD_OVERLOAD random_float(float min, float max)
|
||||
{
|
||||
return (((double)random()/RAND_MAX) * (max-min)) + min;
|
||||
}
|
||||
|
||||
/// Generate a random three-component vector with values between min and max.
|
||||
vector_float3 AAPL_SIMD_OVERLOAD generate_random_vector(float min, float max);
|
||||
|
||||
/// Fast random seed.
|
||||
void AAPL_SIMD_OVERLOAD seedRand(uint32_t seed);
|
||||
|
||||
/// Fast integer random.
|
||||
int32_t AAPL_SIMD_OVERLOAD randi(void);
|
||||
|
||||
/// Fast floating-point random.
|
||||
float AAPL_SIMD_OVERLOAD randf(float x);
|
||||
|
||||
/// Returns a vector that is linearly interpolated between the two given vectors.
|
||||
vector_float3 AAPL_SIMD_OVERLOAD vector_lerp(vector_float3 v0, vector_float3 v1, float t);
|
||||
|
||||
/// Returns a vector that is linearly interpolated between the two given vectors.
|
||||
vector_float4 AAPL_SIMD_OVERLOAD vector_lerp(vector_float4 v0, vector_float4 v1, float t);
|
||||
|
||||
/// Converts a unit-norm quaternion into its corresponding rotation matrix.
|
||||
matrix_float3x3 AAPL_SIMD_OVERLOAD matrix3x3_from_quaternion(quaternion_float q);
|
||||
|
||||
/// Constructs a matrix_float3x3 from three rows of three columns with float values.
|
||||
/// Indices are m<column><row>.
|
||||
matrix_float3x3 AAPL_SIMD_OVERLOAD matrix_make_rows(float m00, float m10, float m20,
|
||||
float m01, float m11, float m21,
|
||||
float m02, float m12, float m22);
|
||||
|
||||
/// Constructs a matrix_float4x4 from four rows of four columns with float values.
|
||||
/// Indices are m<column><row>.
|
||||
matrix_float4x4 AAPL_SIMD_OVERLOAD matrix_make_rows(float m00, float m10, float m20, float m30,
|
||||
float m01, float m11, float m21, float m31,
|
||||
float m02, float m12, float m22, float m32,
|
||||
float m03, float m13, float m23, float m33);
|
||||
|
||||
/// Constructs a matrix_float3x3 from 3 vector_float3 column vectors.
|
||||
matrix_float3x3 AAPL_SIMD_OVERLOAD matrix_make_columns(vector_float3 col0,
|
||||
vector_float3 col1,
|
||||
vector_float3 col2);
|
||||
|
||||
/// Constructs a matrix_float4x4 from 4 vector_float4 column vectors.
|
||||
matrix_float4x4 AAPL_SIMD_OVERLOAD matrix_make_columns(vector_float4 col0,
|
||||
vector_float4 col1,
|
||||
vector_float4 col2,
|
||||
vector_float4 col3);
|
||||
|
||||
/// Constructs a rotation matrix from the given angle and axis.
|
||||
matrix_float3x3 AAPL_SIMD_OVERLOAD matrix3x3_rotation(float radians, vector_float3 axis);
|
||||
|
||||
/// Constructs a rotation matrix from the given angle and axis.
|
||||
matrix_float3x3 AAPL_SIMD_OVERLOAD matrix3x3_rotation(float radians, float x, float y, float z);
|
||||
|
||||
/// Constructs a scaling matrix with the specified scaling factors.
|
||||
matrix_float3x3 AAPL_SIMD_OVERLOAD matrix3x3_scale(float x, float y, float z);
|
||||
|
||||
/// Constructs a scaling matrix, using the given vector as an array of scaling factors.
|
||||
matrix_float3x3 AAPL_SIMD_OVERLOAD matrix3x3_scale(vector_float3 s);
|
||||
|
||||
/// Extracts the upper-left 3x3 submatrix of the given 4x4 matrix.
|
||||
matrix_float3x3 AAPL_SIMD_OVERLOAD matrix3x3_upper_left(matrix_float4x4 m);
|
||||
|
||||
/// Returns the inverse of the transpose of the given matrix.
|
||||
matrix_float3x3 AAPL_SIMD_OVERLOAD matrix_inverse_transpose(matrix_float3x3 m);
|
||||
|
||||
/// Constructs a homogeneous rotation matrix from the given angle and axis.
|
||||
matrix_float4x4 AAPL_SIMD_OVERLOAD matrix4x4_from_quaternion(quaternion_float q);
|
||||
|
||||
/// Constructs a rotation matrix from the provided angle and axis
|
||||
matrix_float4x4 AAPL_SIMD_OVERLOAD matrix4x4_rotation(float radians, vector_float3 axis);
|
||||
|
||||
/// Constructs a rotation matrix from the given angle and axis.
|
||||
matrix_float4x4 AAPL_SIMD_OVERLOAD matrix4x4_rotation(float radians, float x, float y, float z);
|
||||
|
||||
/// Constructs an identity matrix.
|
||||
matrix_float4x4 AAPL_SIMD_OVERLOAD matrix4x4_identity(void);
|
||||
|
||||
/// Constructs a scaling matrix with the given scaling factors.
|
||||
matrix_float4x4 AAPL_SIMD_OVERLOAD matrix4x4_scale(float sx, float sy, float sz);
|
||||
|
||||
/// Constructs a scaling matrix, using the given vector as an array of scaling factors.
|
||||
matrix_float4x4 AAPL_SIMD_OVERLOAD matrix4x4_scale(vector_float3 s);
|
||||
|
||||
/// Constructs a translation matrix that translates by the vector (tx, ty, tz).
|
||||
matrix_float4x4 AAPL_SIMD_OVERLOAD matrix4x4_translation(float tx, float ty, float tz);
|
||||
|
||||
/// Constructs a translation matrix that translates by the vector (t.x, t.y, t.z).
|
||||
matrix_float4x4 AAPL_SIMD_OVERLOAD matrix4x4_translation(vector_float3 t);
|
||||
|
||||
/// Constructs a translation matrix that scales by the vector (s.x, s.y, s.z)
|
||||
/// and translates by the vector (t.x, t.y, t.z).
|
||||
matrix_float4x4 AAPL_SIMD_OVERLOAD matrix4x4_scale_translation(vector_float3 s, vector_float3 t);
|
||||
|
||||
/// Starting with left-hand world coordinates, constructs a view matrix that is
|
||||
/// positioned at (eyeX, eyeY, eyeZ) and looks toward (centerX, centerY, centerZ),
|
||||
/// with the vector (upX, upY, upZ) pointing up for a left-hand coordinate system.
|
||||
matrix_float4x4 AAPL_SIMD_OVERLOAD matrix_look_at_left_hand(float eyeX, float eyeY, float eyeZ,
|
||||
float centerX, float centerY, float centerZ,
|
||||
float upX, float upY, float upZ);
|
||||
|
||||
/// Starting with left-hand world coordinates, constructs a view matrix that is
|
||||
/// positioned at (eye) and looks toward (target), with the vector (up) pointing
|
||||
/// up for a left-hand coordinate system.
|
||||
matrix_float4x4 AAPL_SIMD_OVERLOAD matrix_look_at_left_hand(vector_float3 eye,
|
||||
vector_float3 target,
|
||||
vector_float3 up);
|
||||
|
||||
/// Starting with right-hand world coordinates, constructs a view matrix that is
|
||||
/// positioned at (eyeX, eyeY, eyeZ) and looks toward (centerX, centerY, centerZ),
|
||||
/// with the vector (upX, upY, upZ) pointing up for a right-hand coordinate system.
|
||||
matrix_float4x4 AAPL_SIMD_OVERLOAD matrix_look_at_right_hand(float eyeX, float eyeY, float eyeZ,
|
||||
float centerX, float centerY, float centerZ,
|
||||
float upX, float upY, float upZ);
|
||||
|
||||
/// Starting with right-hand world coordinates, constructs a view matrix that is
|
||||
/// positioned at (eye) and looks toward (target), with the vector (up) pointing
|
||||
/// up for a right-hand coordinate system.
|
||||
matrix_float4x4 AAPL_SIMD_OVERLOAD matrix_look_at_right_hand(vector_float3 eye,
|
||||
vector_float3 target,
|
||||
vector_float3 up);
|
||||
|
||||
/// Constructs a symmetric orthographic projection matrix, from left-hand eye
|
||||
/// coordinates to left-hand clip coordinates.
|
||||
/// That maps (left, top) to (-1, 1), (right, bottom) to (1, -1), and (nearZ, farZ) to (0, 1).
|
||||
/// The first four arguments are signed eye coordinates.
|
||||
/// nearZ and farZ are absolute distances from the eye to the near and far clip planes.
|
||||
matrix_float4x4 AAPL_SIMD_OVERLOAD matrix_ortho_left_hand(float left, float right, float bottom, float top, float nearZ, float farZ);
|
||||
|
||||
/// Constructs a symmetric orthographic projection matrix, from right-hand eye
|
||||
/// coordinates to right-hand clip coordinates.
|
||||
/// That maps (left, top) to (-1, 1), (right, bottom) to (1, -1), and (nearZ, farZ) to (0, 1).
|
||||
/// The first four arguments are signed eye coordinates.
|
||||
/// nearZ and farZ are absolute distances from the eye to the near and far clip planes.
|
||||
matrix_float4x4 AAPL_SIMD_OVERLOAD matrix_ortho_right_hand(float left, float right, float bottom, float top, float nearZ, float farZ);
|
||||
|
||||
/// Constructs a symmetric perspective projection matrix, from left-hand eye
|
||||
/// coordinates to left-hand clip coordinates, with a vertical viewing angle of
|
||||
/// fovyRadians, the given aspect ratio, and the given absolute near and far
|
||||
/// z distances from the eye.
|
||||
matrix_float4x4 AAPL_SIMD_OVERLOAD matrix_perspective_left_hand(float fovyRadians, float aspect, float nearZ, float farZ);
|
||||
|
||||
/// Constructs a symmetric perspective projection matrix, from right-hand eye
|
||||
/// coordinates to right-hand clip coordinates, with a vertical viewing angle of
|
||||
/// fovyRadians, the given aspect ratio, and the given absolute near and far
|
||||
/// z distances from the eye.
|
||||
matrix_float4x4 AAPL_SIMD_OVERLOAD matrix_perspective_right_hand(float fovyRadians, float aspect, float nearZ, float farZ);
|
||||
|
||||
/// Construct a general frustum projection matrix, from right-hand eye
|
||||
/// coordinates to left-hand clip coordinates.
|
||||
/// The bounds left, right, bottom, and top, define the visible frustum at the near clip plane.
|
||||
/// The first four arguments are signed eye coordinates.
|
||||
/// nearZ and farZ are absolute distances from the eye to the near and far clip planes.
|
||||
matrix_float4x4 AAPL_SIMD_OVERLOAD matrix_perspective_frustum_right_hand(float left, float right, float bottom, float top, float nearZ, float farZ);
|
||||
|
||||
/// Returns the inverse of the transpose of the given matrix.
|
||||
matrix_float4x4 AAPL_SIMD_OVERLOAD matrix_inverse_transpose(matrix_float4x4 m);
|
||||
|
||||
/// Constructs an identity quaternion.
|
||||
quaternion_float AAPL_SIMD_OVERLOAD quaternion_identity(void);
|
||||
|
||||
/// Constructs a quaternion of the form w + xi + yj + zk.
|
||||
quaternion_float AAPL_SIMD_OVERLOAD quaternion(float x, float y, float z, float w);
|
||||
|
||||
/// Constructs a quaternion of the form w + v.x*i + v.y*j + v.z*k.
|
||||
quaternion_float AAPL_SIMD_OVERLOAD quaternion(vector_float3 v, float w);
|
||||
|
||||
/// Constructs a unit-norm quaternion that represents rotation by the given angle about the axis (x, y, z).
|
||||
quaternion_float AAPL_SIMD_OVERLOAD quaternion(float radians, float x, float y, float z);
|
||||
|
||||
/// Constructs a unit-norm quaternion that represents rotation by the given angle about the specified axis.
|
||||
quaternion_float AAPL_SIMD_OVERLOAD quaternion(float radians, vector_float3 axis);
|
||||
|
||||
/// Constructs a unit-norm quaternion from the given matrix.
|
||||
/// The result is undefined if the matrix does not represent a pure rotation.
|
||||
quaternion_float AAPL_SIMD_OVERLOAD quaternion(matrix_float3x3 m);
|
||||
|
||||
/// Constructs a unit-norm quaternion from the given matrix.
|
||||
/// The result is undefined if the matrix does not represent a pure rotation.
|
||||
quaternion_float AAPL_SIMD_OVERLOAD quaternion(matrix_float4x4 m);
|
||||
|
||||
/// Returns the length of the given quaternion.
|
||||
float AAPL_SIMD_OVERLOAD quaternion_length(quaternion_float q);
|
||||
|
||||
float AAPL_SIMD_OVERLOAD quaternion_length_squared(quaternion_float q);
|
||||
|
||||
/// Returns the rotation axis of the given unit-norm quaternion.
|
||||
vector_float3 AAPL_SIMD_OVERLOAD quaternion_axis(quaternion_float q);
|
||||
|
||||
/// Returns the rotation angle of the given unit-norm quaternion.
|
||||
float AAPL_SIMD_OVERLOAD quaternion_angle(quaternion_float q);
|
||||
|
||||
/// Returns a quaternion from the given rotation axis and angle, in radians.
|
||||
quaternion_float AAPL_SIMD_OVERLOAD quaternion_from_axis_angle(vector_float3 axis, float radians);
|
||||
|
||||
/// Returns a quaternion from the given 3x3 rotation matrix.
|
||||
quaternion_float AAPL_SIMD_OVERLOAD quaternion_from_matrix3x3(matrix_float3x3 m);
|
||||
|
||||
/// Returns a quaternion from the given Euler angle, in radians.
|
||||
quaternion_float AAPL_SIMD_OVERLOAD quaternion_from_euler(vector_float3 euler);
|
||||
|
||||
/// Returns a unit-norm quaternion.
|
||||
quaternion_float AAPL_SIMD_OVERLOAD quaternion_normalize(quaternion_float q);
|
||||
|
||||
/// Returns the inverse quaternion of the given quaternion.
|
||||
quaternion_float AAPL_SIMD_OVERLOAD quaternion_inverse(quaternion_float q);
|
||||
|
||||
/// Returns the conjugate quaternion of the given quaternion.
|
||||
quaternion_float AAPL_SIMD_OVERLOAD quaternion_conjugate(quaternion_float q);
|
||||
|
||||
/// Returns the product of the two given quaternions.
|
||||
quaternion_float AAPL_SIMD_OVERLOAD quaternion_multiply(quaternion_float q0, quaternion_float q1);
|
||||
|
||||
/// Returns the quaternion that results from spherically interpolating between the two given quaternions.
|
||||
quaternion_float AAPL_SIMD_OVERLOAD quaternion_slerp(quaternion_float q0, quaternion_float q1, float t);
|
||||
|
||||
/// Returns the vector that results from rotating the given vector by the given unit-norm quaternion.
|
||||
vector_float3 AAPL_SIMD_OVERLOAD quaternion_rotate_vector(quaternion_float q, vector_float3 v);
|
||||
|
||||
/// Returns the quaternion for the given forward and up vectors for right-hand coordinate systems.
|
||||
quaternion_float AAPL_SIMD_OVERLOAD quaternion_from_direction_vectors_right_hand(vector_float3 forward, vector_float3 up);
|
||||
|
||||
/// Returns the quaternion for the given forward and up vectors for left-hand coordinate systems.
|
||||
quaternion_float AAPL_SIMD_OVERLOAD quaternion_from_direction_vectors_left_hand(vector_float3 forward, vector_float3 up);
|
||||
|
||||
/// Returns a vector in the +Z direction for the given quaternion.
|
||||
vector_float3 AAPL_SIMD_OVERLOAD forward_direction_vector_from_quaternion(quaternion_float q);
|
||||
|
||||
/// Returns a vector in the +Y direction for the given quaternion (for a left-handed coordinate system,
|
||||
/// negate for a right-hand coordinate system).
|
||||
vector_float3 AAPL_SIMD_OVERLOAD up_direction_vector_from_quaternion(quaternion_float q);
|
||||
|
||||
/// Returns a vector in the +X direction for the given quaternion (for a left-hand coordinate system,
|
||||
/// negate for a right-hand coordinate system).
|
||||
vector_float3 AAPL_SIMD_OVERLOAD right_direction_vector_from_quaternion(quaternion_float q);
|
||||
+103
-113
@@ -2,8 +2,18 @@
|
||||
// Created by Vicente Ferrari Smith on 26.02.26.
|
||||
//
|
||||
|
||||
#include "init.h"
|
||||
#define NS_PRIVATE_IMPLEMENTATION
|
||||
#define MTL_PRIVATE_IMPLEMENTATION
|
||||
#define MTK_PRIVATE_IMPLEMENTATION
|
||||
#define CA_PRIVATE_IMPLEMENTATION
|
||||
|
||||
#include <Foundation/Foundation.hpp>
|
||||
#include <Metal/Metal.hpp>
|
||||
#include <QuartzCore/QuartzCore.hpp>
|
||||
|
||||
#include "metal.h"
|
||||
#include "../graphics.h"
|
||||
#include "../texture.h"
|
||||
#include <print>
|
||||
#include <iostream>
|
||||
#include <fstream>
|
||||
@@ -12,20 +22,41 @@
|
||||
#include <GLFW/glfw3native.h>
|
||||
#include <objc/message.h>
|
||||
#include <objc/objc.h>
|
||||
#include "vertex_data.h"
|
||||
|
||||
Device metal_device{};
|
||||
MTL::Buffer* triangle_vertex_buffer{};
|
||||
MTL::CommandQueue *queue{};
|
||||
CA::MetalLayer *metal_layer{};
|
||||
MTL::RenderPipelineState *pipeline_state{};
|
||||
CA::MetalDrawable *metal_drawable{};
|
||||
MTL::CommandBuffer* metal_command_buffer{};
|
||||
extern int32_t window_width;
|
||||
extern int32_t window_height;
|
||||
|
||||
MTL::Function *vertex_shader{};
|
||||
MTL::Function *fragment_shader{};
|
||||
Device metal_device{};
|
||||
MTL::CommandQueue *queue{};
|
||||
CA::MetalLayer *metal_layer{};
|
||||
CA::MetalDrawable *metal_drawable{};
|
||||
|
||||
void create_window(GLFWwindow *window) {
|
||||
Renderer renderer;
|
||||
|
||||
void upload_texture(
|
||||
const int w,
|
||||
const int h,
|
||||
const void *pixels,
|
||||
Texture *texture)
|
||||
{
|
||||
MTL::TextureDescriptor *td = MTL::TextureDescriptor::alloc()->init();
|
||||
td->setPixelFormat(MTL::PixelFormatRGBA8Unorm);
|
||||
td->setWidth(w);
|
||||
td->setHeight(h);
|
||||
td->setStorageMode(MTL::StorageModeShared);
|
||||
td->setUsage(MTL::TextureUsageShaderRead);
|
||||
|
||||
texture->p_texture->texture = metal_device.device->newTexture(td);
|
||||
|
||||
MTL::Region region = MTL::Region(0, 0, 0, w, h, 1);
|
||||
NS::UInteger bytesPerRow = 4 * w;
|
||||
|
||||
texture->p_texture->texture->replaceRegion(region, 0, pixels, bytesPerRow);
|
||||
|
||||
td->release();
|
||||
}
|
||||
|
||||
void create_metal_layer(GLFWwindow *window) {
|
||||
void *ns_window = glfwGetCocoaWindow(window);
|
||||
if (!ns_window) {
|
||||
throw std::runtime_error("Failed to get Cocoa window from GLFWwindow");
|
||||
@@ -51,44 +82,11 @@ void create_window(GLFWwindow *window) {
|
||||
metal_layer->setColorspace(p3Space);
|
||||
}
|
||||
|
||||
void encode_render_command(MTL::RenderCommandEncoder *renderCommandEncoder) {
|
||||
renderCommandEncoder->setRenderPipelineState(pipeline_state);
|
||||
renderCommandEncoder->setVertexBuffer(triangle_vertex_buffer, 0, 0);
|
||||
MTL::PrimitiveType typeTriangle = MTL::PrimitiveTypeTriangle;
|
||||
NS::UInteger vertexStart = 0;
|
||||
NS::UInteger vertexCount = 6;
|
||||
renderCommandEncoder->drawPrimitives(typeTriangle, vertexStart, vertexCount);
|
||||
}
|
||||
|
||||
void send_render_command() {
|
||||
metal_command_buffer = queue->commandBuffer();
|
||||
|
||||
MTL::RenderPassDescriptor* renderPassDescriptor = MTL::RenderPassDescriptor::alloc()->init();
|
||||
MTL::RenderPassColorAttachmentDescriptor *cd = renderPassDescriptor->colorAttachments()->object(0);
|
||||
cd->setTexture(metal_drawable->texture());
|
||||
cd->setLoadAction(MTL::LoadActionClear);
|
||||
cd->setClearColor(MTL::ClearColor(
|
||||
100.0f / 255.0f,
|
||||
149.0f / 255.0f,
|
||||
237.0f / 255.0f,
|
||||
1.0
|
||||
));
|
||||
cd->setStoreAction(MTL::StoreActionStore);
|
||||
|
||||
MTL::RenderCommandEncoder* renderCommandEncoder = metal_command_buffer->renderCommandEncoder(renderPassDescriptor);
|
||||
encode_render_command(renderCommandEncoder);
|
||||
renderCommandEncoder->endEncoding();
|
||||
|
||||
metal_command_buffer->presentDrawable(metal_drawable);
|
||||
metal_command_buffer->commit();
|
||||
metal_command_buffer->waitUntilCompleted();
|
||||
|
||||
renderPassDescriptor->release();
|
||||
}
|
||||
|
||||
void LoadMetalShader(const std::string &shader_path,
|
||||
const std::string &vertex_fn_name,
|
||||
const std::string &fragment_fn_name)
|
||||
void load_metal_shader(const std::string &shader_path,
|
||||
const std::string &vertex_fn_name,
|
||||
const std::string &fragment_fn_name,
|
||||
MTL::Function **vertex_shader,
|
||||
MTL::Function **fragment_shader)
|
||||
{
|
||||
NS::Error *error = nullptr;
|
||||
MTL::Library *library = nullptr;
|
||||
@@ -137,80 +135,72 @@ void LoadMetalShader(const std::string &shader_path,
|
||||
}
|
||||
NS::String *vname = NS::String::string(vertex_fn_name.c_str(), NS::UTF8StringEncoding);
|
||||
NS::String *fname = NS::String::string(fragment_fn_name.c_str(), NS::UTF8StringEncoding);
|
||||
vertex_shader = library->newFunction(vname);
|
||||
fragment_shader = library->newFunction(fname);
|
||||
*vertex_shader = library->newFunction(vname);
|
||||
*fragment_shader = library->newFunction(fname);
|
||||
|
||||
if (vertex_shader == nullptr || fragment_shader == nullptr) {
|
||||
if (*vertex_shader == nullptr || *fragment_shader == nullptr) {
|
||||
throw std::runtime_error("Failed to create Metal shader functions");
|
||||
}
|
||||
|
||||
library->release();
|
||||
}
|
||||
|
||||
void create_render_pipeline() {
|
||||
LoadMetalShader("shaders/shader.metal", "vertex_main", "fragment_main");
|
||||
|
||||
MTL::RenderPipelineDescriptor* renderPipelineDescriptor = MTL::RenderPipelineDescriptor::alloc()->init();
|
||||
renderPipelineDescriptor->setLabel(NS::String::string("Triangle Rendering Pipeline", NS::ASCIIStringEncoding));
|
||||
renderPipelineDescriptor->setVertexFunction(vertex_shader);
|
||||
renderPipelineDescriptor->setFragmentFunction(fragment_shader);
|
||||
assert(renderPipelineDescriptor);
|
||||
const MTL::PixelFormat pixel_format = metal_layer->pixelFormat();
|
||||
renderPipelineDescriptor->colorAttachments()->object(0)->setPixelFormat(pixel_format);
|
||||
|
||||
NS::Error* error;
|
||||
pipeline_state = metal_device.device->newRenderPipelineState(renderPipelineDescriptor, &error);
|
||||
renderPipelineDescriptor->release();
|
||||
}
|
||||
|
||||
void create_command_queue() {
|
||||
queue = metal_device.device->newCommandQueue();
|
||||
}
|
||||
|
||||
void create_triangle() {
|
||||
VertexData square_vertices[] = {
|
||||
{{-0.5, -0.5}, {1.0, 0.0, 0.0, 1.0}},
|
||||
{{0.5, -0.5}, {0.0, 1.0, 0.0, 1.0}},
|
||||
{{0.5, 0.5}, {0.0, 0.0, 1.0, 1.0}},
|
||||
|
||||
{{0.5, 0.5}, {0.0, 0.0, 1.0, 1.0}},
|
||||
{{-0.5, 0.5}, {0.0, 1.0, 0.0, 1.0}},
|
||||
{{-0.5, -0.5}, {1.0, 0.0, 0.0, 1.0}},
|
||||
};
|
||||
|
||||
triangle_vertex_buffer = metal_device.device->newBuffer(&square_vertices,
|
||||
sizeof(square_vertices),
|
||||
MTL::ResourceStorageModeShared);
|
||||
|
||||
}
|
||||
|
||||
void graphics_init(GLFWwindow *window) {
|
||||
std::println("wow, we are on macos!! crazy!!");
|
||||
|
||||
create_device();
|
||||
create_window(window);
|
||||
create_triangle();
|
||||
create_command_queue();
|
||||
create_render_pipeline();
|
||||
}
|
||||
|
||||
void graphics_deinit() {
|
||||
|
||||
}
|
||||
|
||||
void begin_frame() {
|
||||
|
||||
}
|
||||
|
||||
void end_frame() {
|
||||
auto pPool = NS::AutoreleasePool::alloc()->init();
|
||||
metal_drawable = metal_layer->nextDrawable();
|
||||
|
||||
send_render_command();
|
||||
|
||||
pPool->release();
|
||||
}
|
||||
|
||||
void create_device() {
|
||||
metal_device.device = MTL::CreateSystemDefaultDevice();
|
||||
}
|
||||
|
||||
void platform_graphics_init(GLFWwindow *window) {
|
||||
std::println("wow, we are on macos!! crazy!!");
|
||||
|
||||
auto slangTargets{ std::to_array<slang::TargetDesc>({ {
|
||||
.format = SLANG_METAL,
|
||||
.profile = slangGlobalSession->findProfile("metallib_2_4"),
|
||||
} })};
|
||||
// auto slangOptions{ std::to_array<slang::CompilerOptionEntry>({ {
|
||||
// slang::CompilerOptionName::EmitSpirvDirectly,
|
||||
// {slang::CompilerOptionValueKind::Int, 1}
|
||||
// } })};
|
||||
const char *search_paths[] = {"shaders"};
|
||||
slang::SessionDesc slangSessionDesc{
|
||||
.targets = slangTargets.data(),
|
||||
.targetCount = SlangInt(slangTargets.size()),
|
||||
.searchPaths = search_paths,
|
||||
.searchPathCount = 1,
|
||||
// .defaultMatrixLayoutMode = SLANG_MATRIX_LAYOUT_COLUMN_MAJOR,
|
||||
};
|
||||
|
||||
slangGlobalSession->createSession(slangSessionDesc, slangSession.writeRef());
|
||||
|
||||
create_device();
|
||||
create_metal_layer(window);
|
||||
create_command_queue();
|
||||
|
||||
renderer = Renderer(window);
|
||||
}
|
||||
|
||||
void graphics_deinit() {
|
||||
queue->release();
|
||||
metal_layer->release();
|
||||
metal_device.device->release();
|
||||
}
|
||||
|
||||
void begin_frame() {
|
||||
renderer.begin_frame();
|
||||
}
|
||||
|
||||
void end_frame(GLFWwindow *window) {
|
||||
auto pPool = NS::AutoreleasePool::alloc()->init();
|
||||
metal_drawable = metal_layer->nextDrawable();
|
||||
|
||||
renderer.end_frame(window);
|
||||
|
||||
pPool->release();
|
||||
}
|
||||
|
||||
void submit_sprite(glm::vec2 pos, const sprite_t &sprite) {
|
||||
renderer.submit_sprite({pos.x, pos.y}, sprite);
|
||||
}
|
||||
+16
-4
@@ -2,8 +2,8 @@
|
||||
// Created by Vicente Ferrari Smith on 26.02.26.
|
||||
//
|
||||
|
||||
#ifndef M_INIT_H
|
||||
#define M_INIT_H
|
||||
#ifndef V_METAL_H
|
||||
#define V_METAL_H
|
||||
|
||||
#include <GLFW/glfw3.h>
|
||||
#define GLFW_EXPOSE_NATIVE_COCOA
|
||||
@@ -17,6 +17,18 @@ struct Device {
|
||||
MTL::Device *device;
|
||||
};
|
||||
|
||||
void create_device();
|
||||
struct PlatformTexture {
|
||||
MTL::Texture *texture;
|
||||
};
|
||||
|
||||
#endif //M_INIT_H
|
||||
struct Queue {
|
||||
MTL::CommandQueue *queue;
|
||||
};
|
||||
|
||||
void load_metal_shader(const std::string &shader_path,
|
||||
const std::string &vertex_fn_name,
|
||||
const std::string &fragment_fn_name,
|
||||
MTL::Function **vertex_shader,
|
||||
MTL::Function **fragment_shader);
|
||||
|
||||
#endif //V_METAL_H
|
||||
+235
-684
File diff suppressed because it is too large.
Load diff
+92
-309
@@ -5,25 +5,13 @@
|
||||
#ifndef V_RENDERER_H
|
||||
#define V_RENDERER_H
|
||||
|
||||
#include "init.h"
|
||||
#include <volk/volk.h>
|
||||
#include "metal.h"
|
||||
#include <GLFW/glfw3.h>
|
||||
#define GLM_FORCE_RADIANS
|
||||
#define GLM_FORCE_DEPTH_ZERO_TO_ONE
|
||||
#define GLM_ENABLE_EXPERIMENTAL
|
||||
#include <glm/glm.hpp>
|
||||
#include <glm/ext/matrix_clip_space.hpp>
|
||||
#include "glm/gtx/string_cast.hpp"
|
||||
#include <vma/vk_mem_alloc.h>
|
||||
#include "../sprite.h"
|
||||
#include "../texture.h"
|
||||
#include <misc.h>
|
||||
#include <array>
|
||||
#include <span>
|
||||
#include <slang/slang.h>
|
||||
#include <slang/slang-com-ptr.h>
|
||||
#include <simd/simd.h>
|
||||
|
||||
inline Slang::ComPtr<slang::IGlobalSession> slangGlobalSession;
|
||||
static const int kMaxFramesInFlight = 3;
|
||||
|
||||
enum class PROJECTION_TYPE : uint8_t {
|
||||
NONE,
|
||||
@@ -34,32 +22,6 @@ enum class PROJECTION_TYPE : uint8_t {
|
||||
COUNT,
|
||||
};
|
||||
|
||||
struct vertex_p2_s2_st2_col4_a1_u32 {
|
||||
glm::vec2 pos;
|
||||
glm::vec2 scale;
|
||||
glm::vec2 uv;
|
||||
glm::vec4 color;
|
||||
float alpha;
|
||||
uint32_t textureID;
|
||||
|
||||
static VkVertexInputBindingDescription getBindingDescription() {
|
||||
return {0, sizeof(vertex_p2_s2_st2_col4_a1_u32), VK_VERTEX_INPUT_RATE_VERTEX};
|
||||
}
|
||||
|
||||
static std::array<VkVertexInputAttributeDescription, 6> getAttributeDescriptions() {
|
||||
return {
|
||||
{
|
||||
{0, 0, VK_FORMAT_R32G32_SFLOAT, offsetof(vertex_p2_s2_st2_col4_a1_u32, pos)},
|
||||
{1, 0, VK_FORMAT_R32G32_SFLOAT, offsetof(vertex_p2_s2_st2_col4_a1_u32, scale)},
|
||||
{2, 0, VK_FORMAT_R32G32_SFLOAT, offsetof(vertex_p2_s2_st2_col4_a1_u32, uv)},
|
||||
{3, 0, VK_FORMAT_R32G32B32A32_SFLOAT, offsetof(vertex_p2_s2_st2_col4_a1_u32, color)},
|
||||
{4, 0, VK_FORMAT_R32_SFLOAT, offsetof(vertex_p2_s2_st2_col4_a1_u32, alpha)},
|
||||
{5, 0, VK_FORMAT_R32_UINT, offsetof(vertex_p2_s2_st2_col4_a1_u32, textureID)},
|
||||
}
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
// commands
|
||||
|
||||
enum class PipelineType : uint8_t {
|
||||
@@ -72,24 +34,24 @@ enum class PipelineType : uint8_t {
|
||||
};
|
||||
|
||||
struct TexturedQuadCmd {
|
||||
glm::vec2 position;
|
||||
glm::vec2 size;
|
||||
glm::vec2 uvMin;
|
||||
glm::vec2 uvMax;
|
||||
glm::vec4 color;
|
||||
uint16_t textureID;
|
||||
simd::float2 pos;
|
||||
simd::float2 scale;
|
||||
simd::float2 uv0;
|
||||
simd::float2 uv1;
|
||||
simd::float4 colour;
|
||||
MTL::Texture *texture;
|
||||
};
|
||||
|
||||
struct ColoredQuadCmd {
|
||||
glm::vec2 pos;
|
||||
glm::vec2 scale;
|
||||
glm::vec4 color;
|
||||
simd::float2 pos;
|
||||
simd::float2 scale;
|
||||
simd::float4 colour;
|
||||
};
|
||||
|
||||
struct LineCmd {
|
||||
glm::vec2 start;
|
||||
glm::vec2 end;
|
||||
glm::vec4 color;
|
||||
simd::float2 start;
|
||||
simd::float2 end;
|
||||
simd::float4 color;
|
||||
};
|
||||
|
||||
// struct TextCmd {
|
||||
@@ -99,11 +61,11 @@ struct LineCmd {
|
||||
// glm::vec4 color;
|
||||
// };
|
||||
|
||||
struct ChunkCmd {
|
||||
VkBuffer vertexBuffer;
|
||||
VkBuffer indexBuffer;
|
||||
uint32_t indexCount;
|
||||
};
|
||||
//struct ChunkCmd {
|
||||
// VkBuffer vertexBuffer;
|
||||
// VkBuffer indexBuffer;
|
||||
// uint32_t indexCount;
|
||||
//};
|
||||
|
||||
struct SortKey {
|
||||
uint16_t depth; // world Z or Y-sorted depth
|
||||
@@ -123,280 +85,101 @@ struct RenderCommand {
|
||||
ColoredQuadCmd colored_quad;
|
||||
LineCmd line;
|
||||
// TextCmd text;
|
||||
ChunkCmd chunk;
|
||||
// ChunkCmd chunk;
|
||||
};
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
struct AllocatedBuffer {
|
||||
VkBuffer buffer;
|
||||
VmaAllocation allocation;
|
||||
VmaAllocationInfo info;
|
||||
};
|
||||
// struct AllocatedBuffer {
|
||||
// VkBuffer buffer;
|
||||
// VmaAllocation allocation;
|
||||
// VmaAllocationInfo info;
|
||||
// };
|
||||
|
||||
struct GPUMeshBuffers {
|
||||
AllocatedBuffer indexBuffer;
|
||||
AllocatedBuffer vertexBuffer;
|
||||
VkDeviceAddress vertexBufferAddress;
|
||||
};
|
||||
// struct GPUMeshBuffers {
|
||||
// AllocatedBuffer indexBuffer;
|
||||
// AllocatedBuffer vertexBuffer;
|
||||
// VkDeviceAddress vertexBufferAddress;
|
||||
// };
|
||||
|
||||
struct Renderer {
|
||||
std::vector<RenderCommand> commands{};
|
||||
|
||||
VkDescriptorSetLayout descriptor_set_layout{};
|
||||
VkPipelineLayout pipelineLayout{};
|
||||
VkPipeline textured_quad_pipeline{};
|
||||
VkPipeline colored_quad_pipeline{};
|
||||
VkPipeline line_pipeline{};
|
||||
VkPipeline text_pipeline{};
|
||||
VkPipeline chunk_pipeline{};
|
||||
VkDescriptorSet set{};
|
||||
|
||||
VkSampler defaultSampler{};
|
||||
MTL::RenderPipelineState *textured_quad_pipeline{};
|
||||
MTL::RenderPipelineState *colored_quad_pipeline{};
|
||||
MTL::RenderPipelineState *line_pipeline{};
|
||||
MTL::RenderPipelineState *text_pipeline{};
|
||||
MTL::RenderPipelineState *chunk_pipeline{};
|
||||
|
||||
uint32_t nextTextureSlot = 0;
|
||||
|
||||
MTL::CommandBuffer *command_buffer{};
|
||||
|
||||
struct Frame {
|
||||
VkCommandPool commandPool{};
|
||||
VkCommandBuffer command_buffer{};
|
||||
|
||||
VkSemaphore imageAvailable{};
|
||||
VkFence in_flight_fence{};
|
||||
|
||||
AllocatedBuffer vertexBuffer{};
|
||||
MTL::Buffer *vertex_buffer{};
|
||||
MTL::Buffer *uniform_buffer{};
|
||||
};
|
||||
|
||||
std::vector<Frame> frames;
|
||||
uint32_t currentFrame = 0;
|
||||
Frame frames[kMaxFramesInFlight];
|
||||
|
||||
VkDescriptorPool descriptorPool{};
|
||||
std::vector<VkDescriptorSet> textureSets{};
|
||||
dispatch_semaphore_t frame_semaphore;
|
||||
uint8_t current_frame = 0;
|
||||
|
||||
// struct Frame {
|
||||
// VkCommandPool commandPool{};
|
||||
// VkCommandBuffer command_buffer{};
|
||||
//
|
||||
// VkSemaphore imageAvailable{};
|
||||
// VkFence in_flight_fence{};
|
||||
//
|
||||
// AllocatedBuffer vertexBuffer{};
|
||||
// };
|
||||
//
|
||||
// std::vector<Frame> frames;
|
||||
// uint32_t currentFrame = 0;
|
||||
//
|
||||
// VkDescriptorPool descriptorPool{};
|
||||
// std::vector<VkDescriptorSet> textureSets{};
|
||||
//
|
||||
void begin_frame();
|
||||
void end_frame();
|
||||
void end_frame(GLFWwindow *window);
|
||||
void flush();
|
||||
|
||||
void submit_sprite(glm::vec2 pos, const sprite_t &sprite);
|
||||
void submit_quad(glm::vec2 pos, glm::vec2 scale);
|
||||
void submit_sprite(simd::float2 pos, const sprite_t &sprite);
|
||||
void submit_quad(simd::float2 pos, simd::float2 scale);
|
||||
|
||||
Renderer() = default;
|
||||
explicit Renderer(GLFWwindow *window);
|
||||
void create_pipeline_layout();
|
||||
void createFrameResources();
|
||||
void create_default_sampler();
|
||||
void recordCommandBuffer(
|
||||
VkCommandBuffer cmd,
|
||||
VkImage image,
|
||||
VkImageView imageView,
|
||||
VkExtent2D extent,
|
||||
VkImageLayout oldLayout,
|
||||
const Frame &frame,
|
||||
const std::vector<vertex_p2_s2_st2_col4_a1_u32> &vertices) const;
|
||||
void immediate_submit(std::function<void(VkCommandBuffer)>&& func) const;
|
||||
void transition_image_layout(VkCommandBuffer cmd, VkImage image, VkImageLayout oldLayout, VkImageLayout newLayout) const;
|
||||
VkImageView create_image_view(VkImage image, VkFormat format) const;
|
||||
AllocatedBuffer create_buffer(size_t allocSize, VkBufferUsageFlags usage, VmaMemoryUsage memoryUsage);
|
||||
void destroy_buffer(const AllocatedBuffer& buffer);
|
||||
// GPUMeshBuffers uploadMesh(std::span<uint32_t> indices, std::span<vertex_p2_st2_col4_a1_u32> vertices);
|
||||
void upload_vertex_buffer(
|
||||
VkCommandBuffer cmd,
|
||||
const Frame &frame,
|
||||
std::span<const vertex_p2_s2_st2_col4_a1_u32> vertices) const;
|
||||
|
||||
[[nodiscard]] VkPipeline get_pipeline(PipelineType type) const;
|
||||
// void bind_material(VkCommandBuffer cmd, uint16_t materialID);
|
||||
void create_descriptor_pool();
|
||||
void update_bindless_slot(uint32_t slot, VkImageView view, VkSampler sampler) const;
|
||||
|
||||
// Returns the resource info so the Manager can store it
|
||||
void upload_texture(
|
||||
int w,
|
||||
int h,
|
||||
const void* pixels,
|
||||
VkImage *image,
|
||||
VmaAllocation *allocation,
|
||||
VkImageView *view,
|
||||
uint32_t *descriptor_index);
|
||||
|
||||
template <typename T>
|
||||
VkPipeline create_graphics_pipeline(
|
||||
VkDevice device,
|
||||
VkPipelineLayout layout,
|
||||
VkFormat colorFormat,
|
||||
// VkShaderModule vertShader,
|
||||
// VkShaderModule fragShader,
|
||||
VkPrimitiveTopology topology,
|
||||
bool enableBlending)
|
||||
{
|
||||
|
||||
auto slangTargets{ std::to_array<slang::TargetDesc>({ {
|
||||
.format = SLANG_SPIRV,
|
||||
.profile = slangGlobalSession->findProfile("spirv_1_4")
|
||||
} })};
|
||||
auto slangOptions{ std::to_array<slang::CompilerOptionEntry>({ {
|
||||
slang::CompilerOptionName::EmitSpirvDirectly,
|
||||
{slang::CompilerOptionValueKind::Int, 1}
|
||||
} })};
|
||||
slang::SessionDesc slangSessionDesc{
|
||||
.targets = slangTargets.data(),
|
||||
.targetCount = SlangInt(slangTargets.size()),
|
||||
.defaultMatrixLayoutMode = SLANG_MATRIX_LAYOUT_COLUMN_MAJOR,
|
||||
.compilerOptionEntries = slangOptions.data(),
|
||||
.compilerOptionEntryCount = uint32_t(slangOptions.size())
|
||||
};
|
||||
Slang::ComPtr<slang::ISession> slangSession;
|
||||
slangGlobalSession->createSession(slangSessionDesc, slangSession.writeRef());
|
||||
|
||||
Slang::ComPtr<slang::IModule> slangModule{
|
||||
slangSession->loadModuleFromSource("triangle", "shaders/shader.slang", nullptr, nullptr)
|
||||
};
|
||||
Slang::ComPtr<ISlangBlob> spirv;
|
||||
slangModule->getTargetCode(0, spirv.writeRef());
|
||||
|
||||
VkShaderModuleCreateInfo shaderModuleCI{
|
||||
.sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO,
|
||||
.codeSize = spirv->getBufferSize(),
|
||||
.pCode = (uint32_t*)spirv->getBufferPointer()
|
||||
};
|
||||
VkShaderModule shaderModule{};
|
||||
vkCreateShaderModule(device, &shaderModuleCI, nullptr, &shaderModule);
|
||||
|
||||
auto vsCode = loadFile("shaders/triangle.vert.spv");
|
||||
auto fsCode = loadFile("shaders/triangle.frag.spv");
|
||||
|
||||
VkShaderModuleCreateInfo smci{
|
||||
.sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO
|
||||
};
|
||||
|
||||
smci.codeSize = vsCode.size();
|
||||
smci.pCode = reinterpret_cast<uint32_t*>(vsCode.data());
|
||||
// VkShaderModule vs;
|
||||
// vkCreateShaderModule(device, &smci, nullptr, &vs);
|
||||
|
||||
smci.codeSize = fsCode.size();
|
||||
smci.pCode = reinterpret_cast<uint32_t*>(fsCode.data());
|
||||
// VkShaderModule fs;
|
||||
// vkCreateShaderModule(device, &smci, nullptr, &fs);
|
||||
|
||||
// --- Shaders ---
|
||||
std::vector<VkPipelineShaderStageCreateInfo> shaderStages{
|
||||
{ .sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO,
|
||||
.stage = VK_SHADER_STAGE_VERTEX_BIT,
|
||||
.module = shaderModule, .pName = "main"},
|
||||
{ .sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO,
|
||||
.stage = VK_SHADER_STAGE_FRAGMENT_BIT,
|
||||
.module = shaderModule, .pName = "main" }
|
||||
};
|
||||
|
||||
// --- Vertex Input (Generic) ---
|
||||
auto binding = T::getBindingDescription();
|
||||
auto attrs = T::getAttributeDescriptions();
|
||||
|
||||
// --- Vertex Input (Matching our vertex_p2_st2_col4 struct) ---
|
||||
VkPipelineVertexInputStateCreateInfo vi{
|
||||
.sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO,
|
||||
.vertexBindingDescriptionCount = 1,
|
||||
.pVertexBindingDescriptions = &binding,
|
||||
.vertexAttributeDescriptionCount = attrs.size(),
|
||||
.pVertexAttributeDescriptions = attrs.data(),
|
||||
};
|
||||
|
||||
// --- Input Assembly (Changes based on Topology parameter) ---
|
||||
VkPipelineInputAssemblyStateCreateInfo ia{VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO};
|
||||
ia.topology = topology;
|
||||
|
||||
// --- Blending (Changes based on enableBlending parameter) ---
|
||||
VkPipelineColorBlendAttachmentState colorBlend{
|
||||
.blendEnable = enableBlending ? VK_TRUE : VK_FALSE,
|
||||
.srcColorBlendFactor = VK_BLEND_FACTOR_SRC_ALPHA,
|
||||
.dstColorBlendFactor = VK_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA,
|
||||
.colorBlendOp = VK_BLEND_OP_ADD,
|
||||
.srcAlphaBlendFactor = VK_BLEND_FACTOR_ONE,
|
||||
.dstAlphaBlendFactor = VK_BLEND_FACTOR_ZERO,
|
||||
.alphaBlendOp = VK_BLEND_OP_ADD,
|
||||
.colorWriteMask = 0xF
|
||||
};
|
||||
|
||||
// --- Boilerplate (Standard 2D Defaults) ---
|
||||
VkPipelineViewportStateCreateInfo vp{
|
||||
VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO,
|
||||
nullptr,
|
||||
0,
|
||||
1,
|
||||
nullptr,
|
||||
1,
|
||||
nullptr
|
||||
};
|
||||
|
||||
VkPipelineRasterizationStateCreateInfo rs{
|
||||
VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO,
|
||||
nullptr,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
VK_POLYGON_MODE_FILL,
|
||||
VK_CULL_MODE_NONE,
|
||||
VK_FRONT_FACE_COUNTER_CLOCKWISE,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
1.0f
|
||||
};
|
||||
|
||||
VkPipelineMultisampleStateCreateInfo ms{
|
||||
VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO,
|
||||
nullptr,
|
||||
0,
|
||||
VK_SAMPLE_COUNT_1_BIT
|
||||
};
|
||||
|
||||
VkPipelineColorBlendStateCreateInfo cb{
|
||||
VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO,
|
||||
nullptr,
|
||||
0,
|
||||
0,
|
||||
VK_LOGIC_OP_AND,
|
||||
1,
|
||||
&colorBlend
|
||||
};
|
||||
|
||||
VkDynamicState dyns[] = { VK_DYNAMIC_STATE_VIEWPORT, VK_DYNAMIC_STATE_SCISSOR };
|
||||
VkPipelineDynamicStateCreateInfo ds{
|
||||
VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO,
|
||||
nullptr,
|
||||
0,
|
||||
2,
|
||||
dyns
|
||||
};
|
||||
|
||||
VkPipelineRenderingCreateInfo rci{
|
||||
VK_STRUCTURE_TYPE_PIPELINE_RENDERING_CREATE_INFO,
|
||||
nullptr,
|
||||
0,
|
||||
1,
|
||||
&colorFormat
|
||||
};
|
||||
|
||||
VkGraphicsPipelineCreateInfo gpci{
|
||||
.sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO,
|
||||
.pNext = &rci,
|
||||
.stageCount = (uint32_t) shaderStages.size(),
|
||||
.pStages = shaderStages.data(),
|
||||
.pVertexInputState = &vi,
|
||||
.pInputAssemblyState = &ia,
|
||||
.pViewportState = &vp,
|
||||
.pRasterizationState = &rs,
|
||||
.pMultisampleState = &ms,
|
||||
.pColorBlendState = &cb,
|
||||
.pDynamicState = &ds,
|
||||
.layout = layout
|
||||
};
|
||||
|
||||
VkPipeline pipeline;
|
||||
vkCreateGraphicsPipelines(device, VK_NULL_HANDLE, 1, &gpci, nullptr, &pipeline);
|
||||
return pipeline;
|
||||
}
|
||||
void create_render_pipeline();
|
||||
void send_render_command(GLFWwindow *window);
|
||||
void encode_render_command(GLFWwindow *window, MTL::RenderCommandEncoder *render_command_encoder);
|
||||
// void create_pipeline_layout();
|
||||
// void createFrameResources();
|
||||
// void create_default_sampler();
|
||||
// void recordCommandBuffer(
|
||||
// VkCommandBuffer cmd,
|
||||
// VkImage image,
|
||||
// VkImageView imageView,
|
||||
// VkExtent2D extent,
|
||||
// VkImageLayout oldLayout,
|
||||
// const Frame &frame,
|
||||
// const std::vector<vertex_p2_s2_st2_col4_a1_u32> &vertices) const;
|
||||
// void immediate_submit(std::function<void(VkCommandBuffer)>&& func) const;
|
||||
// void transition_image_layout(VkCommandBuffer cmd, VkImage image, VkImageLayout oldLayout, VkImageLayout newLayout) const;
|
||||
// VkImageView create_image_view(VkImage image, VkFormat format) const;
|
||||
// AllocatedBuffer create_buffer(size_t allocSize, VkBufferUsageFlags usage, VmaMemoryUsage memoryUsage);
|
||||
// void destroy_buffer(const AllocatedBuffer& buffer);
|
||||
// // GPUMeshBuffers uploadMesh(std::span<uint32_t> indices, std::span<vertex_p2_st2_col4_a1_u32> vertices);
|
||||
// void upload_vertex_buffer(
|
||||
// VkCommandBuffer cmd,
|
||||
// const Frame &frame,
|
||||
// std::span<const vertex_p2_s2_st2_col4_a1_u32> vertices) const;
|
||||
//
|
||||
[[nodiscard]] MTL::RenderPipelineState *get_pipeline(PipelineType type) const;
|
||||
// // void bind_material(VkCommandBuffer cmd, uint16_t materialID);
|
||||
// void create_descriptor_pool();
|
||||
// void update_bindless_slot(uint32_t slot, VkImageView view, VkSampler sampler) const;
|
||||
};
|
||||
|
||||
#endif //V_RENDERER_H
|
||||
@@ -2,7 +2,56 @@
|
||||
// Created by Vicente Ferrari Smith on 27.02.26.
|
||||
//
|
||||
|
||||
#ifndef V_VERTEX_DATA_H
|
||||
#define V_VERTEX_DATA_H
|
||||
#pragma once
|
||||
#include <simd/simd.h>
|
||||
|
||||
#endif //V_VERTEX_DATA_H
|
||||
using namespace simd;
|
||||
|
||||
struct vertex_p2_s2_uv2_c4_a1 {
|
||||
float2 pos;
|
||||
float2 scale;
|
||||
float2 uv;
|
||||
float4 color;
|
||||
float alpha;
|
||||
|
||||
static MTL::VertexDescriptor* vertexDescriptor() {
|
||||
MTL::VertexDescriptor* vd = MTL::VertexDescriptor::alloc()->init();
|
||||
|
||||
// ATTRIBUTE 0 — float2 pos
|
||||
vd->attributes()->object(0)->setFormat(MTL::VertexFormatFloat2);
|
||||
vd->attributes()->object(0)->setOffset(offsetof(vertex_p2_s2_uv2_c4_a1, pos));
|
||||
vd->attributes()->object(0)->setBufferIndex(0);
|
||||
|
||||
// ATTRIBUTE 1 — float2 scale
|
||||
vd->attributes()->object(1)->setFormat(MTL::VertexFormatFloat2);
|
||||
vd->attributes()->object(1)->setOffset(offsetof(vertex_p2_s2_uv2_c4_a1, scale));
|
||||
vd->attributes()->object(1)->setBufferIndex(0);
|
||||
|
||||
// ATTRIBUTE 2 — float2 uv
|
||||
vd->attributes()->object(2)->setFormat(MTL::VertexFormatFloat2);
|
||||
vd->attributes()->object(2)->setOffset(offsetof(vertex_p2_s2_uv2_c4_a1, uv));
|
||||
vd->attributes()->object(2)->setBufferIndex(0);
|
||||
|
||||
// ATTRIBUTE 3 — float4 color
|
||||
vd->attributes()->object(3)->setFormat(MTL::VertexFormatFloat4);
|
||||
vd->attributes()->object(3)->setOffset(offsetof(vertex_p2_s2_uv2_c4_a1, color));
|
||||
vd->attributes()->object(3)->setBufferIndex(0);
|
||||
|
||||
// ATTRIBUTE 4 — float alpha
|
||||
vd->attributes()->object(4)->setFormat(MTL::VertexFormatFloat);
|
||||
vd->attributes()->object(4)->setOffset(offsetof(vertex_p2_s2_uv2_c4_a1, alpha));
|
||||
vd->attributes()->object(4)->setBufferIndex(0);
|
||||
|
||||
// Layout for buffer 0
|
||||
vd->layouts()->object(0)->setStride(sizeof(vertex_p2_s2_uv2_c4_a1));
|
||||
vd->layouts()->object(0)->setStepFunction(MTL::VertexStepFunctionPerVertex);
|
||||
|
||||
return vd;
|
||||
}
|
||||
};
|
||||
|
||||
struct TransformationData {
|
||||
float4x4 model_matrix;
|
||||
float4x4 view_matrix;
|
||||
float4x4 perspective_matrix;
|
||||
};
|
||||
Reference in new issue
Block a user