feat: bench and test

This commit is contained in:
anjingyu 2025-01-15 15:31:07 +08:00
parent 0d985ae7e2
commit 75aa02b34c
11 changed files with 1671 additions and 398 deletions

40
benchtest/CMakeLists.txt Normal file
View File

@ -0,0 +1,40 @@
cmake_minimum_required (VERSION 3.15)
project (benchtest)
# spdlog requires exception enable
# or use the following option:
# add_compile_definitions (SPDLOG_NO_EXCEPTIONS)
set (ADMAKE_DISABLE_ADDRESS_SANITIZER ON)
set (ADMAKE_ENABLE_WARNINGS ON)
include (CMakeListsPub)
set (TARGET_NAME ${CMAKE_PROJECT_NAME})
append_3rd_modules (gtest benchmark)
########### Unit test ###########
file (GLOB_RECURSE TEST_SRC_FILES
"${CMAKE_CURRENT_SOURCE_DIR}/test/*.cpp"
"${CMAKE_CURRENT_SOURCE_DIR}/test/*.c")
add_executable (${TARGET_NAME}_test ${TEST_SRC_FILES})
target_include_directories (${TARGET_NAME}_test
PRIVATE
"${CMAKE_CURRENT_SOURCE_DIR}/test")
target_link_libraries (${TARGET_NAME}_test
PRIVATE
${GTEST_LIB})
########### Benchmark ###########
file (GLOB_RECURSE BENCH_SRC_FILES
"${CMAKE_CURRENT_SOURCE_DIR}/bench/*.cpp"
"${CMAKE_CURRENT_SOURCE_DIR}/bench/*.c")
add_executable (${TARGET_NAME}_bench ${BENCH_SRC_FILES})
target_include_directories (${TARGET_NAME}_bench
PRIVATE
"${CMAKE_CURRENT_SOURCE_DIR}/test"
"${CMAKE_CURRENT_SOURCE_DIR}/bench")
target_link_libraries (${TARGET_NAME}_bench
PRIVATE
${BENCHMARK_LIB})

20
benchtest/bench/main.cpp Normal file
View File

@ -0,0 +1,20 @@
#include "benchmark/benchmark.h"
int main(int argc, char** argv)
{
char arg0_default[] = "benchmark";
char* args_default = arg0_default;
if (!argv) {
argc = 1;
argv = &args_default;
}
::benchmark::Initialize(&argc, argv);
if (::benchmark::ReportUnrecognizedArguments(argc, argv)) {
return 1;
}
::benchmark::RunSpecifiedBenchmarks();
::benchmark::Shutdown();
return 0;
}

928
benchtest/bench/vmath.c Normal file
View File

@ -0,0 +1,928 @@
#include "vmath.h"
/* Vector Operations */
/* Vector2f */
void Vector2f_AddInPlace(Vector2f *o, Vector2f other) {
o->x += other.x;
o->y += other.y;
}
Vector2f Vector2f_Add(Vector2f o, Vector2f other) {
Vector2f r;
r.x = o.x + other.x;
r.y = o.y + other.y;
return r;
}
void Vector2f_SubInPlace(Vector2f *o, Vector2f s) {
o->x = o->x - s.x;
o->y = o->y - s.y;
}
Vector2f Vector2f_Sub(Vector2f o, Vector2f s) {
Vector2f r;
r.x = o.x - s.x;
r.y = o.y - s.y;
return r;
}
void Vector2f_MulInPlace(Vector2f *o, float s) {
o->x *= s;
o->y *= s;
}
Vector2f Vector2f_Mul(Vector2f o, float s) {
Vector2f r;
r.x = o.x * s;
r.y = o.y * s;
return r;
}
void Vector2f_DivInPlace(Vector2f *o, float s) {
Vector2f_MulInPlace(o, 1.f / s);
}
Vector2f Vector2f_Div(Vector2f o, float s) {
return Vector2f_Mul(o, 1.f / s);
}
float Vector2f_Dot(Vector2f u, Vector2f v) {
return u.x * v.x + u.y * v.y;
}
float Vector2f_Cross(Vector2f u, Vector2f v) {
return u.x * v.y - u.y * v.x;
}
float Vector2f_Length(Vector2f v) {
return (float)sqrt(v.x * v.x + v.y * v.y);
}
Vector2f Vector2f_Reflect(Vector2f o, Vector2f normal) {
float idotn2 = (normal.x * o.x + normal.y * o.y) * -2.f;
return (Vector2f){o.x + idotn2 * normal.x, o.y + idotn2 * normal.y};
}
void Vector2f_NormalizeInPlace(Vector2f *o) {
float length = Vector2f_Length(*o);
if (length > 0.f) {
float inv = 1.f / length;
o->x *= inv;
o->y *= inv;
}
}
Vector2f Vector2f_Normalize(Vector2f o) {
float length = Vector2f_Length(o);
if (length > 0) {
float inv = 1.f / length;
return (Vector2f){o.x * inv, o.y * inv};
}
return (Vector2f){0.f, 0.f};
}
Vector2f Vector2f_Lerp(Vector2f a, Vector2f b, float t) {
return (Vector2f){Lerpf(a.x, b.x, t), Lerpf(a.y, b.y, t)};
}
Vector2f Vector2f_Saturate(Vector2f o) {
return (Vector2f){Saturatef(o.x), Saturatef(o.y)};
}
/* Vector3f */
void Vector3f_AddInPlace(Vector3f *o, Vector3f other) {
o->x += other.x;
o->y += other.y;
o->z += other.z;
}
Vector3f Vector3f_Add(Vector3f o, Vector3f other) {
Vector3f r;
r.x = o.x + other.x;
r.y = o.y + other.y;
r.z = o.z + other.z;
return r;
}
void Vector3f_SubInPlace(Vector3f *o, Vector3f s) {
o->x = o->x - s.x;
o->y = o->y - s.y;
o->z = o->z - s.z;
}
Vector3f Vector3f_Sub(Vector3f o, Vector3f s) {
Vector3f r;
r.x = o.x - s.x;
r.y = o.y - s.y;
r.z = o.z - s.z;
return r;
}
void Vector3f_MulInPlace(Vector3f *o, float s) {
o->x *= s;
o->y *= s;
o->z *= s;
}
Vector3f Vector3f_Mul(Vector3f o, float s) {
Vector3f r;
r.x = o.x * s;
r.y = o.y * s;
r.z = o.z * s;
return r;
}
void Vector3f_DivInPlace(Vector3f *o, float s) {
Vector3f_MulInPlace(o, 1.f / s);
}
Vector3f Vector3f_Div(Vector3f o, float s) {
return Vector3f_Mul(o, 1.f / s);
}
float Vector3f_Dot(Vector3f u, Vector3f v) {
return u.x * v.x + u.y * v.y + u.z * v.z;
}
Vector3f Vector3f_Cross(Vector3f u, Vector3f v) {
return (Vector3f){u.y * v.z - u.z * v.y, u.z * v.x - u.x * v.z,
u.x * v.y - u.y * v.x};
}
float Vector3f_Length(Vector3f v) {
return (float)sqrt(v.x * v.x + v.y * v.y + v.z * v.z);
}
void Vector3f_NormalizeInPlace(Vector3f *o) {
float length = Vector3f_Length(*o);
if (length > 0.f) {
float inv = 1.f / length;
o->x *= inv;
o->y *= inv;
o->z *= inv;
}
}
Vector3f Vector3f_Normalize(Vector3f o) {
float length = Vector3f_Length(o);
if (length > 0.f) {
float inv = 1.f / length;
return (Vector3f){o.x * inv, o.y * inv, o.z * inv};
}
return (Vector3f){0.f, 0.f, 0.f};
}
Vector3f Vector3f_Lerp(Vector3f a, Vector3f b, float t) {
return (Vector3f){Lerpf(a.x, b.x, t), Lerpf(a.y, b.y, t), Lerpf(a.z, b.z, t)};
}
Vector3f Vector3f_Saturate(Vector3f o) {
return (Vector3f){Saturatef(o.x), Saturatef(o.y), Saturatef(o.z)};
}
/* Ray */
Point3f Rayf_At(Rayf *o, float t) {
return Vector3f_Add(o->origin, Vector3f_Mul(o->direction, t));
}
/* Matrix Operations */
/* Matrix 3x3 */
double Matrix3x3f_Det(const Matrix3x3f *o) {
float ret = 0;
float **m = (float **)o->m;
ret += m[0][0] * m[1][1] * m[2][2] + m[1][0] * m[2][1] * m[0][2] +
m[2][0] * m[0][1] * m[1][2];
ret -= m[2][0] * m[1][1] * m[0][2] + m[0][0] * m[2][1] * m[1][2] +
m[1][0] * m[0][1] * m[2][2];
return ret;
}
void Matrix3x3f_ScaleInPlace(Matrix3x3f *o, float s) {
o->m11 *= s;
o->m12 *= s;
o->m13 *= s;
o->m21 *= s;
o->m22 *= s;
o->m23 *= s;
o->m31 *= s;
o->m32 *= s;
o->m33 *= s;
}
Matrix3x3f Matrix3x3f_Scale(const Matrix3x3f *o, float s) {
Matrix3x3f r;
r.m11 = o->m11 * s;
r.m12 = o->m12 * s;
r.m13 = o->m13 * s;
r.m21 = o->m21 * s;
r.m22 = o->m22 * s;
r.m23 = o->m23 * s;
r.m31 = o->m31 * s;
r.m32 = o->m32 * s;
r.m33 = o->m33 * s;
return r;
}
void Matrix3x3f_Invert(const Matrix3x3f *o, Matrix3x3f *dest) {
float det;
float **m = (float **)o->m;
float a = m[0][0], b = m[0][1], c = m[0][2], d = m[1][0], e = m[1][1],
f = m[1][2], g = m[2][0], h = m[2][1], i = m[2][2];
float **dm = (float **)dest->m;
dm[0][0] = e * i - f * h;
dm[0][1] = -(b * i - h * c);
dm[0][2] = b * f - e * c;
dm[1][0] = -(d * i - g * f);
dm[1][1] = a * i - c * g;
dm[1][2] = -(a * f - d * c);
dm[2][0] = d * h - g * e;
dm[2][1] = -(a * h - g * b);
dm[2][2] = a * e - b * d;
det = 1.0f / (a * dm[0][0] + b * dm[1][0] + c * dm[2][0]);
Matrix3x3f_Scale(dest, det);
}
void Matrix3x3f_TransposeInPlace(Matrix3x3f *o) {
#define _SWAP(a, b) (((a) ^ (b)) && ((b) ^= (a) ^= (b), (a) ^= (b)))
union {
float f;
int i;
} x, y;
x.f = o->m12, y.f = o->m21;
_SWAP(x.i, y.i);
x.f = o->m13, y.f = o->m31;
_SWAP(x.i, y.i);
x.f = o->m21, y.f = o->m12;
_SWAP(x.i, y.i);
x.f = o->m23, y.f = o->m32;
_SWAP(x.i, y.i);
x.f = o->m31, y.f = o->m13;
_SWAP(x.i, y.i);
x.f = o->m32, y.f = o->m23;
_SWAP(x.i, y.i);
#undef _SWAP
}
Vector3f Matrix3x3f_MulVector3f(const Matrix3x3f *o, Vector3f v) {
Vector3f dest;
dest.x = o->m11 * v.x + o->m21 * v.y + o->m31 * v.z;
dest.y = o->m12 * v.x + o->m22 * v.y + o->m32 * v.z;
dest.x = o->m13 * v.x + o->m23 * v.y + o->m33 * v.z;
return dest;
}
Matrix3x3f Matrix3x3f_InvertTranspose(const Matrix3x3f *o) {
Matrix3x3f dest;
Matrix3x3f_Invert(o, &dest);
Matrix3x3f_TransposeInPlace(&dest);
return dest;
}
Vector3f Vector3f_Barycentric(const Vector2i tri[3], Vector2i p) {
Matrix3x3f a = {(float)tri[0].x, (float)tri[0].y, 1.0f,
(float)tri[1].x, (float)tri[1].y, 1.0f,
(float)tri[2].x, (float)tri[2].y, 1.0f};
if (Matrix3x3f_Det(&a) < 1e-3) {
return (Vector3f){
-1, 1, 1}; // for a degenerate triangle generate negative coordinates,
// it will be thrown away by the rasterizator
}
Matrix3x3f dest = Matrix3x3f_InvertTranspose(&a);
return Matrix3x3f_MulVector3f(&dest,
(Vector3f){(float)p.x, (float)p.y, 1.0f});
}
Vector3f Vector2i_Barycentric(const Vector2i tri[3], const Vector2i p) {
Vector3f r;
float det = (tri[1].y - tri[2].y) * (tri[0].x - tri[2].x) +
(tri[2].x - tri[1].x) * (tri[0].y - tri[2].y);
r.x = ((tri[1].y - tri[2].y) * (p.x - tri[2].x) +
(tri[2].x - tri[1].x) * (p.y - tri[2].y)) /
det;
r.y = ((tri[2].y - tri[0].y) * (p.x - tri[2].x) +
(tri[0].x - tri[2].x) * (p.y - tri[2].y)) /
det;
r.z = 1.f - r.v[0] - r.v[1];
return r;
}
float Vector4f_Length(Vector4f v) { return Vector3f_Length(v.xyz); }
Vector4f Vector4f_Add(Vector4f x, Vector4f y) {
Vector4f z;
z.xyz = Vector3f_Add(x.xyz, y.xyz);
z.w = 1.f;
return z;
}
Vector4f Vector4f_Sub(Vector4f x, Vector4f y) {
Vector4f z;
z.xyz = Vector3f_Sub(x.xyz, y.xyz);
z.w = 1.f;
return z;
}
float Vector4f_Dot(Vector4f x, Vector4f y) {
return Vector3f_Dot(x.xyz, y.xyz);
}
Vector4f Vector4f_Cross(Vector4f x, Vector4f y) {
Vector4f z;
z.xyz = Vector3f_Cross(x.xyz, y.xyz);
z.w = 1.f;
return z;
}
Vector4f Vector4f_Lerp(Vector4f x1, Vector4f x2, float t) {
Vector4f z;
z.xyz = Vector3f_Lerp(x1.xyz, x2.xyz, t);
z.w = 1.0f;
return z;
}
void Vector4f_NormalizeInPlace(Vector4f *v) {
Vector3f_NormalizeInPlace(&v->xyz);
}
Vector4f Vector4f_Normalize(Vector4f v) {
Vector4f r = {0.f, 0.f, 0.f, 1.f};
r.xyz = Vector3f_Normalize(v.xyz);
return r;
}
/* Quaternion Operations */
float Quaternionf_Dot(Quaternionf a, Quaternionf b) {
return a.x * b.x + a.y * b.y + a.z * b.z + a.w * b.w;
}
float Quaternionf_Length(Quaternionf q) {
return (float)sqrt(Quaternionf_Dot(q, q));
}
Quaternionf Quaternionf_Normalize(Quaternionf q) {
float factor = 1 / Quaternionf_Length(q);
return (Quaternionf){q.x * factor, q.y * factor, q.z * factor, q.w * factor};
}
void Quaternionf_SetIdentity(Quaternionf *q) {
q->x = 0.f;
q->y = 0.f;
q->z = 0.f;
q->w = 1.f;
}
// From D3DXMath
//
// Reference:
// https://en.wikipedia.org/wiki/Conversion_between_quaternions_and_Euler_angles#Source_code
Quaternionf
Quaternionf_RotationRollPitchYaw(float pitch, float yaw, float roll) {
Quaternionf q;
// The math format: // roll (x), pitch (y), yaw (z), angles are in radians
// double cr = cos(roll * 0.5);
// double sr = sin(roll * 0.5);
// double cp = cos(pitch * 0.5);
// double sp = sin(pitch * 0.5);
// double cy = cos(yaw * 0.5);
// double sy = sin(yaw * 0.5);
//
// q.w = cr * cp * cy + sr * sp * sy;
// q.x = sr * cp * cy - cr * sp * sy;
// q.y = cr * sp * cy + sr * cp * sy;
// q.z = cr * cp * sy - sr * sp * cy;
// The D3DXMath format(game format): pitch (x), yaw (y), roll (z)
double cp = cos(pitch * 0.5);
double sp = sin(pitch * 0.5);
double cy = cos(yaw * 0.5);
double sy = sin(yaw * 0.5);
double cr = cos(roll * 0.5);
double sr = sin(roll * 0.5);
q.w = cr * cp * cy + sr * sp * sy;
q.x = cr * sp * cy + sr * cp * sy;
q.y = cr * cp * sy - sr * sp * cy;
q.z = sr * cp * cy - cr * sp * sy;
return q;
}
/*
* For spherical linear interpolation, see
* 3D Math Primer for Graphics and Game Development, 2nd Edition, Chapter 8
*/
Quaternionf Quaternionf_Slerp(Quaternionf a, Quaternionf b,
float t) {
float cos_angle = Quaternionf_Dot(a, b);
if (cos_angle < 0) {
b = (Quaternionf){-b.x, -b.y, -b.z, -b.w};
cos_angle = -cos_angle;
}
if (cos_angle > 1 - EPSILON) {
float x = Lerpf(a.x, b.x, t);
float y = Lerpf(a.y, b.y, t);
float z = Lerpf(a.z, b.z, t);
float w = Lerpf(a.w, b.w, t);
return (Quaternionf){x, y, z, w};
} else {
float angle = (float)acos(cos_angle);
float sin_angle_inv = 1.f / (float)sin(angle);
float angle_a = (1 - t) * angle;
float angle_b = t * angle;
float factor_a = (float)sin(angle_a) * sin_angle_inv;
float factor_b = (float)sin(angle_b) * sin_angle_inv;
float x = factor_a * a.x + factor_b * b.x;
float y = factor_a * a.y + factor_b * b.y;
float z = factor_a * a.z + factor_b * b.z;
float w = factor_a * a.w + factor_b * b.w;
return (Quaternionf){x, y, z, w};
}
}
Matrix4x4f Matrix4x4f_Add(Matrix4x4f a, Matrix4x4f b) {
Matrix4x4f r;
int i, j;
for (i = 0; i < 4; i++) {
for (j = 0; j < 4; j++) {
r.m[i][j] = a.m[i][j] + b.m[i][j];
}
}
return r;
}
Matrix4x4f Matrix4x4f_Sub(Matrix4x4f a, Matrix4x4f b) {
Matrix4x4f r;
int i, j;
for (i = 0; i < 4; i++) {
for (j = 0; j < 4; j++) {
r.m[i][j] = a.m[i][j] - b.m[i][j];
}
}
return r;
}
Matrix4x4f Matrix4x4f_MulMatrix4x4(Matrix4x4f o,
Matrix4x4f other) {
Matrix4x4f r;
int i, j;
for (i = 0; i < 4; i++) {
for (j = 0; j < 4; j++) {
r.m[j][i] = (o.m[j][0] * other.m[0][i]) + (o.m[j][1] * other.m[1][i]) +
(o.m[j][2] * other.m[2][i]) + (o.m[j][3] * other.m[3][i]);
}
}
return r;
}
void Matrix4x4f_ScaleInPlace(Matrix4x4f *o, float f) {
int i, j;
for (i = 0; i < 4; i++) {
for (j = 0; j < 4; j++) {
o->m[i][j] *= f;
}
}
}
Matrix4x4f Matrix4x4f_Scale(Matrix4x4f o, float f) {
Matrix4x4f r;
int i, j;
for (i = 0; i < 4; i++) {
for (j = 0; j < 4; j++) {
r.m[i][j] = o.m[i][j] * f;
}
}
return r;
}
int Matrix4x4f_Invert(Matrix4x4f o, Matrix4x4f *inv_out) {
Matrix4x4f inv;
float det;
inv.m11 = o.m22 * o.m33 * o.m44 - o.m22 * o.m34 * o.m43 -
o.m32 * o.m23 * o.m44 + o.m32 * o.m24 * o.m43 +
o.m42 * o.m23 * o.m34 - o.m43 * o.m24 * o.m33;
inv.m21 = -o.m21 * o.m33 * o.m44 + o.m21 * o.m34 * o.m43 + o.m31 * o.m23 * o.m44 -
o.m31 * o.m24 * o.m43 - o.m41 * o.m23 * o.m34 + o.m41 * o.m24 * o.m33;
inv.m31 = o.m21 * o.m32 * o.m44 - o.m21 * o.m34 * o.m43 - o.m31 * o.m22 * o.m44 +
o.m31 * o.m24 * o.m43 + o.m41 * o.m22 * o.m34 - o.m41 * o.m24 * o.m32;
inv.m41 = -o.m21 * o.m32 * o.m43 + o.m21 * o.m33 * o.m43 + o.m31 * o.m22 * o.m43 -
o.m31 * o.m23 * o.m43 - o.m41 * o.m22 * o.m33 + o.m41 * o.m23 * o.m32;
inv.m12 = -o.m12 * o.m33 * o.m44 + o.m12 * o.m34 * o.m43 + o.m32 * o.m13 * o.m44 -
o.m32 * o.m14 * o.m43 - o.m43 * o.m13 * o.m34 + o.m43 * o.m14 * o.m33;
inv.m22 = o.m11 * o.m33 * o.m44 - o.m11 * o.m34 * o.m43 - o.m31 * o.m13 * o.m44 +
o.m31 * o.m14 * o.m43 + o.m41 * o.m13 * o.m34 - o.m41 * o.m14 * o.m33;
inv.m32 = -o.m11 * o.m32 * o.m44 + o.m11 * o.m34 * o.m43 + o.m31 * o.m12 * o.m44 -
o.m31 * o.m14 * o.m43 - o.m41 * o.m12 * o.m34 + o.m41 * o.m14 * o.m32;
inv.m42 = o.m11 * o.m32 * o.m43 - o.m11 * o.m33 * o.m43 - o.m31 * o.m12 * o.m43 +
o.m31 * o.m13 * o.m43 + o.m41 * o.m12 * o.m33 - o.m41 * o.m13 * o.m32;
inv.m13 = o.m12 * o.m23 * o.m44 - o.m12 * o.m24 * o.m43 - o.m22 * o.m13 * o.m44 +
o.m22 * o.m14 * o.m43 + o.m43 * o.m13 * o.m24 - o.m43 * o.m14 * o.m23;
inv.m23 = -o.m11 * o.m23 * o.m44 + o.m11 * o.m24 * o.m43 + o.m21 * o.m13 * o.m44 -
o.m21 * o.m14 * o.m43 - o.m41 * o.m13 * o.m24 + o.m41 * o.m14 * o.m23;
inv.m33 = o.m11 * o.m22 * o.m44 - o.m11 * o.m24 * o.m43 - o.m21 * o.m12 * o.m44 +
o.m21 * o.m14 * o.m43 + o.m41 * o.m12 * o.m24 - o.m41 * o.m14 * o.m22;
inv.m43 = -o.m11 * o.m22 * o.m43 + o.m11 * o.m23 * o.m43 + o.m21 * o.m12 * o.m43 -
o.m21 * o.m13 * o.m43 - o.m41 * o.m12 * o.m23 + o.m41 * o.m13 * o.m22;
inv.m14 = -o.m12 * o.m23 * o.m34 + o.m12 * o.m24 * o.m33 + o.m22 * o.m13 * o.m34 -
o.m22 * o.m14 * o.m33 - o.m32 * o.m13 * o.m24 + o.m32 * o.m14 * o.m23;
inv.m24 = o.m11 * o.m23 * o.m34 - o.m11 * o.m24 * o.m33 - o.m21 * o.m13 * o.m34 +
o.m21 * o.m14 * o.m33 + o.m31 * o.m13 * o.m24 - o.m31 * o.m14 * o.m23;
inv.m34 = -o.m11 * o.m22 * o.m34 + o.m11 * o.m24 * o.m32 + o.m21 * o.m12 * o.m34 -
o.m21 * o.m14 * o.m32 - o.m31 * o.m12 * o.m24 + o.m31 * o.m14 * o.m22;
inv.m44 = o.m11 * o.m22 * o.m33 - o.m11 * o.m23 * o.m32 - o.m21 * o.m12 * o.m33 +
o.m21 * o.m13 * o.m32 + o.m31 * o.m12 * o.m23 - o.m31 * o.m13 * o.m22;
det = o.m11 * inv.m11 + o.m12 * inv.m21 + o.m13 * inv.m31 + o.m14 * inv.m41;
if (det == 0.f) {
return 0;
}
*inv_out = Matrix4x4f_Scale(inv, 1.f / det);
return 1;
}
// y = x * m
void Matrix4x4f_Apply(Vector4f *y, const Vector4f *x,
const Matrix4x4f *m) {
float X = x->x, Y = x->y, Z = x->z, W = x->w;
y->x = X * m->m[0][0] + Y * m->m[1][0] + Z * m->m[2][0] + W * m->m[3][0];
y->y = X * m->m[0][1] + Y * m->m[1][1] + Z * m->m[2][1] + W * m->m[3][1];
y->z = X * m->m[0][2] + Y * m->m[1][2] + Z * m->m[2][2] + W * m->m[3][2];
y->w = X * m->m[0][3] + Y * m->m[1][3] + Z * m->m[2][3] + W * m->m[3][3];
}
void Matrix4x4f_SetZero(Matrix4x4f *m) {
memset(m->m, 0, sizeof(float) * 16);
}
void Matrix4x4f_SetIdentity(Matrix4x4f *m) {
Matrix4x4f_SetZero(m);
m->m11 = m->m22 = m->m33 = m->m44 = 1.0f;
}
void Matrix4x4f_SetTranslate(Matrix4x4f *m, float x, float y,
float z) {
Matrix4x4f_SetIdentity(m);
m->m41 = x;
m->m42 = y;
m->m43 = z;
}
void Matrix4x4f_SetScale(Matrix4x4f *m, float x, float y,
float z) {
Matrix4x4f_SetIdentity(m);
m->m11 = x;
m->m22 = y;
m->m33 = z;
}
void Matrix4x4f_SetRotate(Matrix4x4f *m, float x, float y,
float z, float theta) {
float qsin = (float)sin(theta * 0.5f);
float qcos = (float)cos(theta * 0.5f);
Vector4f vec = {x, y, z, 1.0f};
float w = qcos;
Vector4f_NormalizeInPlace(&vec);
x = vec.x * qsin;
y = vec.y * qsin;
z = vec.z * qsin;
m->m11 = 1 - 2 * y * y - 2 * z * z;
m->m21 = 2 * x * y - 2 * w * z;
m->m31 = 2 * x * z + 2 * w * y;
m->m12 = 2 * x * y + 2 * w * z;
m->m22 = 1 - 2 * x * x - 2 * z * z;
m->m32 = 2 * y * z - 2 * w * x;
m->m13 = 2 * x * z - 2 * w * y;
m->m23 = 2 * y * z + 2 * w * x;
m->m33 = 1 - 2 * x * x - 2 * y * y;
m->m14 = m->m24 = m->m34 = 0.f;
m->m41 = m->m42 = m->m43 = 0.f;
m->m44 = 1.f;
}
void Matrix4x4f_SetLookAt(Matrix4x4f *m, Vector4f eye, Vector4f at,
Vector4f up) {
Vector4f xaxis, yaxis, zaxis;
zaxis = Vector4f_Sub(at, eye);
Vector4f_NormalizeInPlace(&zaxis);
xaxis = Vector4f_Cross(up, zaxis);
Vector4f_NormalizeInPlace(&xaxis);
yaxis = Vector4f_Cross(zaxis, xaxis);
m->m11 = xaxis.x;
m->m21 = xaxis.y;
m->m31 = xaxis.z;
m->m41 = -Vector4f_Dot(xaxis, eye);
m->m12 = yaxis.x;
m->m22 = yaxis.y;
m->m32 = yaxis.z;
m->m42 = -Vector4f_Dot(yaxis, eye);
m->m13 = zaxis.x;
m->m23 = zaxis.y;
m->m33 = zaxis.z;
m->m43 = -Vector4f_Dot(zaxis, eye);
m->m14 = m->m24 = m->m34 = 0.f;
m->m44 = 1.f;
}
// D3DXMatrixPerspectiveFovLH
void Matrix4x4f_SetPerspective(Matrix4x4f *m, float fovy, float aspect,
float zn, float zf) {
float fax = 1.0f / (float)tan(fovy * 0.5f);
Matrix4x4f_SetZero(m);
m->m11 = (float)(fax / aspect);
m->m22 = (float)(fax);
m->m33 = zf / (zf - zn);
m->m43 = -zn * zf / (zf - zn);
m->m34 = 1;
}
typedef struct {
Matrix4x4f world; // 世界坐标变换
Matrix4x4f view; // 摄影机坐标变换
Matrix4x4f projection; // 投影变换
Matrix4x4f transform; // transform = world * view * projection
float w, h; // 屏幕大小
} Transform;
// 矩阵更新,计算 transform = world * view * projection
void Transform_Update(Transform *ts) {
ts->transform = Matrix4x4f_MulMatrix4x4(
Matrix4x4f_MulMatrix4x4(ts->world, ts->view), ts->projection);
}
// 初始化,设置屏幕长宽
void Transform_Init(Transform *ts, int width, int height) {
float aspect = (float)width / ((float)height);
Matrix4x4f_SetIdentity(&ts->world);
Matrix4x4f_SetIdentity(&ts->view);
Matrix4x4f_SetPerspective(&ts->projection, 3.1415926f * 0.5f, aspect, 1.0f,
500.0f);
ts->w = (float)width;
ts->h = (float)height;
Transform_Update(ts);
}
// 将矢量 x 进行 project
void Transform_Apply(const Transform *ts, Vector4f *y,
const Vector4f *x) {
Matrix4x4f_Apply(y, x, &ts->transform);
}
// 检查齐次坐标同 cvv 的边界用于视锥裁剪
int Transform_CheckCvv(const Vector4f *v) {
float w = v->w;
int check = 0;
if (v->z < 0.0f)
check |= 1;
if (v->z > w)
check |= 2;
if (v->x < -w)
check |= 4;
if (v->x > w)
check |= 8;
if (v->y < -w)
check |= 16;
if (v->y > w)
check |= 32;
return check;
}
// 归一化,得到屏幕坐标
void Transform_Homogenize(const Transform *ts, Vector4f *y,
const Vector4f *x) {
float rhw = 1.0f / x->w;
y->x = (x->x * rhw + 1.0f) * ts->w * 0.5f;
y->y = (1.0f - x->y * rhw) * ts->h * 0.5f;
y->z = x->z * rhw;
y->w = 1.0f;
}
//=====================================================================
// 几何计算:顶点、扫描线、边缘、矩形、步长计算
//=====================================================================
typedef struct {
float r, g, b;
} Color3f;
typedef struct {
float u, v;
} Texcoord2f;
typedef struct {
Point4f pos;
Texcoord2f tc;
Color3f color;
float rhw;
} Vertexf;
typedef struct {
Vertexf v, v1, v2;
} Edgef;
typedef struct {
float top, bottom;
Edgef left, right;
} Trapezoidf;
typedef struct {
Vertexf v, step;
int x, y, w;
} Scanlinef;
void Vertexf_RhwInit(Vertexf *v) {
float rhw = 1.0f / v->pos.w;
v->rhw = rhw;
v->tc.u *= rhw;
v->tc.v *= rhw;
v->color.r *= rhw;
v->color.g *= rhw;
v->color.b *= rhw;
}
void Vertexf_Interpolate(Vertexf *y, const Vertexf *x1,
const Vertexf *x2, float t) {
y->pos = Vector4f_Lerp(x1->pos, x2->pos, t);
y->tc.u = Interpolatef(x1->tc.u, x2->tc.u, t);
y->tc.v = Interpolatef(x1->tc.v, x2->tc.v, t);
y->color.r = Interpolatef(x1->color.r, x2->color.r, t);
y->color.g = Interpolatef(x1->color.g, x2->color.g, t);
y->color.b = Interpolatef(x1->color.b, x2->color.b, t);
y->rhw = Interpolatef(x1->rhw, x2->rhw, t);
}
void Vertexf_Division(Vertexf *y, const Vertexf *x1, const Vertexf *x2,
float w) {
float inv = 1.0f / w;
y->pos.x = (x2->pos.x - x1->pos.x) * inv;
y->pos.y = (x2->pos.y - x1->pos.y) * inv;
y->pos.z = (x2->pos.z - x1->pos.z) * inv;
y->pos.w = (x2->pos.w - x1->pos.w) * inv;
y->tc.u = (x2->tc.u - x1->tc.u) * inv;
y->tc.v = (x2->tc.v - x1->tc.v) * inv;
y->color.r = (x2->color.r - x1->color.r) * inv;
y->color.g = (x2->color.g - x1->color.g) * inv;
y->color.b = (x2->color.b - x1->color.b) * inv;
y->rhw = (x2->rhw - x1->rhw) * inv;
}
void Vertexf_Add(Vertexf *y, const Vertexf *x) {
y->pos.x += x->pos.x;
y->pos.y += x->pos.y;
y->pos.z += x->pos.z;
y->pos.w += x->pos.w;
y->rhw += x->rhw;
y->tc.u += x->tc.u;
y->tc.v += x->tc.v;
y->color.r += x->color.r;
y->color.g += x->color.g;
y->color.b += x->color.b;
}
// 根据三角形生成 0-2 个梯形,并且返回合法梯形的数量
int Trapezoidf_InitTriangle(Trapezoidf *trap, const Vertexf *p1,
const Vertexf *p2, const Vertexf *p3) {
const Vertexf *p;
float k, x;
if (p1->pos.y > p2->pos.y) {
p = p1, p1 = p2, p2 = p;
}
if (p1->pos.y > p3->pos.y) {
p = p1, p1 = p3, p3 = p;
}
if (p2->pos.y > p3->pos.y) {
p = p2, p2 = p3, p3 = p;
}
if (p1->pos.y == p2->pos.y && p1->pos.y == p3->pos.y) {
return 0;
}
if (p1->pos.x == p2->pos.x && p1->pos.x == p3->pos.x) {
return 0;
}
if (p1->pos.y == p2->pos.y) { // triangle down
if (p1->pos.x > p2->pos.x) {
p = p1, p1 = p2, p2 = p;
}
trap[0].top = p1->pos.y;
trap[0].bottom = p3->pos.y;
trap[0].left.v1 = *p1;
trap[0].left.v2 = *p3;
trap[0].right.v1 = *p2;
trap[0].right.v2 = *p3;
return (trap[0].top < trap[0].bottom) ? 1 : 0;
}
if (p2->pos.y == p3->pos.y) { // triangle up
if (p2->pos.x > p3->pos.x) {
p = p2, p2 = p3, p3 = p;
}
trap[0].top = p1->pos.y;
trap[0].bottom = p3->pos.y;
trap[0].left.v1 = *p1;
trap[0].left.v2 = *p2;
trap[0].right.v1 = *p1;
trap[0].right.v2 = *p3;
return (trap[0].top < trap[0].bottom) ? 1 : 0;
}
trap[0].top = p1->pos.y;
trap[0].bottom = p2->pos.y;
trap[1].top = p2->pos.y;
trap[1].bottom = p3->pos.y;
k = (p3->pos.y - p1->pos.y) / (p2->pos.y - p1->pos.y);
x = p1->pos.x + (p2->pos.x - p1->pos.x) * k;
if (x <= p3->pos.x) { // triangle left
trap[0].left.v1 = *p1;
trap[0].left.v2 = *p2;
trap[0].right.v1 = *p1;
trap[0].right.v2 = *p3;
trap[1].left.v1 = *p2;
trap[1].left.v2 = *p3;
trap[1].right.v1 = *p1;
trap[1].right.v2 = *p3;
} else { // triangle right
trap[0].left.v1 = *p1;
trap[0].left.v2 = *p3;
trap[0].right.v1 = *p1;
trap[0].right.v2 = *p2;
trap[1].left.v1 = *p1;
trap[1].left.v2 = *p3;
trap[1].right.v1 = *p2;
trap[1].right.v2 = *p3;
}
return 2;
}
// 按照 Y 坐标计算出左右两条边纵坐标等于 Y 的顶点
void Trapezoidf_EdgeInterpolate(Trapezoidf *trap, float y) {
float s1 = trap->left.v2.pos.y - trap->left.v1.pos.y;
float s2 = trap->right.v2.pos.y - trap->right.v1.pos.y;
float t1 = (y - trap->left.v1.pos.y) / s1;
float t2 = (y - trap->right.v1.pos.y) / s2;
Vertexf_Interpolate(&trap->left.v, &trap->left.v1, &trap->left.v2, t1);
Vertexf_Interpolate(&trap->right.v, &trap->right.v1, &trap->right.v2, t2);
}
// 根据左右两边的端点,初始化计算出扫描线的起点和步长
void Trapezoidf_InitScanline(const Trapezoidf *trap, Scanlinef *scanline,
int y) {
float width = trap->right.v.pos.x - trap->left.v.pos.x;
scanline->x = (int)(trap->left.v.pos.x + 0.5f);
scanline->w = (int)(trap->right.v.pos.x + 0.5f) - scanline->x;
scanline->y = y;
scanline->v = trap->left.v;
if (trap->left.v.pos.x >= trap->right.v.pos.x) {
scanline->w = 0;
}
Vertexf_Division(&scanline->step, &trap->left.v, &trap->right.v, width);
}

109
benchtest/bench/vmath.h Normal file
View File

@ -0,0 +1,109 @@
#pragma once
#include <stdint.h>
#include <stdlib.h> /**< rand */
#include <math.h> /**< abs */
#include <string.h> /**< memset */
#if defined(__cplusplus)
extern "C" {
#endif /* __cplusplus */
#define EPSILON 1e-5f
#define INTERPOLATE(a, b, t) ((a) + (((b) - (a)) * (t)))
#define CLAMP(x, min, max) ((x) < (min)) ? (min) : (((x) > (max)) ? (max) : (x))
#define SATURATE(f) ((f) < 0 ? 0 : ((f) > 1 ? 1 : (f)))
/* Vector Definitions */
typedef union {
struct {
float x, y;
};
float v[2];
} Vector2f;
typedef union {
struct {
int x, y;
};
int v[2];
} Vector2i;
typedef union {
struct {
float x, y, z;
};
float v[3];
Vector2f xy;
} Vector3f;
typedef union {
struct {
float x, y, z, w;
};
float v[4];
Vector3f xyz;
Vector2f xy;
} Vector4f;
/* Matrix Definitions, D3D math */
typedef union {
struct {
float m11, m12, m13, m14;
float m21, m22, m23, m24;
float m31, m32, m33, m34;
float m41, m42, m43, m44;
};
struct {
Vector4f row1;
Vector4f row2;
Vector4f row3;
Vector4f row4;
};
float m[4][4];
} Matrix4x4f;
typedef union {
struct {
float m11, m12, m13;
float m21, m22, m23;
float m31, m32, m33;
};
struct {
Vector3f row1;
Vector3f row2;
Vector3f row3;
};
float m[3][3];
} Matrix3x3f;
typedef Vector3f Point3f;
typedef Vector4f Point4f;
typedef Vector4f Quaternionf;
typedef struct {
Point3f origin;
Vector3f direction;
} Rayf;
/* Common Math Functions */
/* interpolationt [0, 1] */
static inline float Interpolatef(float x1, float x2, float t) {
return INTERPOLATE(x1, x2, t);
}
#define Lerpf Interpolatef
static inline float Clampf(float f, float min, float max) {
return CLAMP(f, min, max);
}
static inline float Saturatef(float f) { return SATURATE(f); }
static inline float Randomf() { return rand() / ((float)RAND_MAX + 1.f); }
#if defined(__cplusplus)
}
#endif /* __cplusplus */

View File

@ -0,0 +1,28 @@
#include "benchmark/benchmark.h"
#include <string.h>
#include "vmath.h"
static void BM_ValuePass(::benchmark::State& state)
{
for (auto _ : state) {
// Generate a huge ini file in CWD
state.PauseTiming();
// Prepare
state.ResumeTiming();
}
}
BENCHMARK(BM_ValuePass)->Unit(::benchmark::kMillisecond);
static void BM_PointerPass(::benchmark::State& state)
{
for (auto _ : state) {
// Generate a huge ini file in CWD
state.PauseTiming();
// Prepare
state.ResumeTiming();
}
}
BENCHMARK(BM_PointerPass)->Unit(::benchmark::kMillisecond);

7
benchtest/test/main.cpp Normal file
View File

@ -0,0 +1,7 @@
#include "gtest/gtest.h"
int main(int argc, char** argv)
{
::testing::InitGoogleTest(&argc, argv);
return RUN_ALL_TESTS();
}

View File

@ -0,0 +1,6 @@
#include "gtest/gtest.h"
TEST(Basic, Basic)
{
}

File diff suppressed because it is too large Load Diff

View File

@ -309,7 +309,7 @@ swwModel *swwModel_CreateFromFile(const char *filepath) {
token = strtok_r(NULL, delimiters, &last);
i++;
}
VertexVector_PushBack(&o->norms, Vector3f_Normalize(&v));
VertexVector_PushBack(&o->norms, Vector3f_Normalize(v));
} else if (len >= 3 && line[0] == 'v' && line[1] == 't' && line[2] == ' ') {
// vt 0 1
Vector2f uv;

View File

@ -351,7 +351,7 @@ void DrawBox(Device *device, float theta) {
void Camera_AtZero(Device *device, float x, float y, float z) {
Point4f eye = {x, y, z, 1}, at = {0, 0, 0, 1}, up = {0, 0, 1, 1};
Matrix4x4f_SetLookAt(&device->transform.view, &eye, &at, &up);
Matrix4x4f_SetLookAt(&device->transform.view, eye, at, up);
Transform_Update(&device->transform);
}

View File

@ -22,6 +22,57 @@ typedef struct {
SceneFunc fs[MAX_SCENE];
} UserData;
static inline Vector3f RandomInUnitDisk() {
static const Vector3f kPv = {1, 1, 0};
Vector3f p;
do {
Vector3f rp = {Randomf(), Randomf(), 0};
p = Vector3f_Sub(rp, kPv);
Vector3f_MulInPlace(&p, 2.0);
} while (Vector3f_Dot(p, p) >= 1.0);
return p;
}
typedef struct {
Vector3f origin;
Vector3f lower_left_corner;
Vector3f horizontal;
Vector3f vertical;
Vector3f u;
Vector3f v;
Vector3f w;
float lens_radius;
} Camera;
void Camera_Construct(Camera *o, Vector3f lookfrom, Vector3f lookat, Vector3f vup, float vfov, float aspect, float aperture, float focus_dist) {
// vfov is top to bottom in degrees
o->lens_radius = aperture / 2;
float theta = vfov * M_PI / 180.f;
float half_height = tan(theta / 2);
float half_width = aspect * half_height;
o->origin = lookfrom;
o->w = Vector3f_Normalize(Vector3f_Sub(lookfrom, lookat));
o->u = Vector3f_Normalize(Vector3f_Cross(vup, o->w));
o->v = Vector3f_Cross(o->w, o->u);
// o->lower_left_corner = o->origin - half_width * focus_dist * o->u - half_height * focus_dist * o->v - focus_dist * o->w;
o->lower_left_corner = Vector3f_Sub(o->origin, Vector3f_Mul(o->u, half_width * focus_dist));
Vector3f_SubInPlace(&o->lower_left_corner, Vector3f_Mul(o->v, half_height * focus_dist));
Vector3f_SubInPlace(&o->lower_left_corner, Vector3f_Mul(o->w, focus_dist));
o->horizontal = Vector3f_Mul(o->u, 2 * half_width * focus_dist);
o->vertical = Vector3f_Mul(o->v, 2 * half_height * focus_dist);
}
Rayf Camera_GetRay(Camera *o, float s, float t) {
Vector3f rd = Vector3f_Mul(RandomInUnitDisk(), o->lens_radius);
Vector3f offset = Vector3f_Add(Vector3f_Mul(o->u, rd.x), Vector3f_Mul(o->v, rd.y));
Vector3f direction = Vector3f_Add(o->lower_left_corner, Vector3f_Mul(o->horizontal, s));
Vector3f_AddInPlace(&direction, Vector3f_Mul(o->vertical, t));
Vector3f_SubInPlace(&direction, Vector3f_Add(o->origin, offset));
return (Rayf){Vector3f_Add(o->origin, offset), direction};
}
void OnKey(swwWindow *o, swwKeycode key, int pressed) {
UserData *ud = swwWindow_GetUserData(o);
if (key == swwKeycode_ESCAPE && pressed) {
@ -80,8 +131,8 @@ void Scene1(swwWindow *o) {
}
}
uint32_t RayColor(Ray *ray) {
Vector3f unit_direction = Vector3f_Normalize(&ray->direction);
uint32_t RayColor(Rayf *ray) {
Vector3f unit_direction = Vector3f_Normalize(ray->direction);
float t = 0.5f * (unit_direction.y + 1.f);
return Color_Lerp(kWhite, Color_RGB(128, 179, 255), t);
}
@ -104,35 +155,35 @@ void Scene2(swwWindow *o) {
Vector3f viewport_v = {0, -vh, 0};
// Calculate the horizontal and vertical delta vectors from pixel to pixel.
Vector3f pixel_delta_u = Vector3f_Div(&viewport_u, w);
Vector3f pixel_delta_v = Vector3f_Div(&viewport_v, h);
Vector3f pixel_delta_u = Vector3f_Div(viewport_u, w);
Vector3f pixel_delta_v = Vector3f_Div(viewport_v, h);
// Calculate the location of the upper left pixel.
// auto viewport_upper_left = camera_center - vec3(0, 0, focal_length) -
// viewport_u/2 - viewport_v/2;
Vector3f focal_length_v = {0, 0, -focal_length};
Vector3f vpu2 = Vector3f_Div(&viewport_u, 2);
Vector3f vpv2 = Vector3f_Div(&viewport_v, 2);
Vector3f_SubInPlace(&focal_length_v, &vpu2);
Vector3f_SubInPlace(&focal_length_v, &vpv2);
Point3f viewport_upper_left = Vector3f_Add(&camera_center, &focal_length_v);
Vector3f vpu2 = Vector3f_Div(viewport_u, 2);
Vector3f vpv2 = Vector3f_Div(viewport_v, 2);
Vector3f_SubInPlace(&focal_length_v, vpu2);
Vector3f_SubInPlace(&focal_length_v, vpv2);
Point3f viewport_upper_left = Vector3f_Add(camera_center, focal_length_v);
// auto pixel00_loc = viewport_upper_left + 0.5 * (pixel_delta_u +
// pixel_delta_v);
Vector3f pds = Vector3f_Add(&pixel_delta_u, &pixel_delta_v);
Vector3f pds = Vector3f_Add(pixel_delta_u, pixel_delta_v);
Vector3f_MulInPlace(&pds, 0.5);
Point3f pixel00_loc = Vector3f_Add(&viewport_upper_left, &pds);
Point3f pixel00_loc = Vector3f_Add(viewport_upper_left, pds);
Ray r = {{0, 0, 0}, {0, 0, 0}};
Rayf r = {{0, 0, 0}, {0, 0, 0}};
// Render
for (int y = 0; y < h; ++y) {
for (int x = 0; x < w; ++x) {
// auto pixel_center = pixel00_loc + (x * pixel_delta_u) + (y *
// pixel_delta_v);
Vector3f pixel_u = Vector3f_Mul(&pixel_delta_u, x);
Vector3f pixel_v = Vector3f_Mul(&pixel_delta_v, y);
Vector3f pixel_uv = Vector3f_Add(&pixel_u, &pixel_v);
Vector3f pixel_center = Vector3f_Add(&pixel00_loc, &pixel_uv);
Vector3f ray_direction = Vector3f_Sub(&pixel_center, &camera_center);
Vector3f pixel_u = Vector3f_Mul(pixel_delta_u, x);
Vector3f pixel_v = Vector3f_Mul(pixel_delta_v, y);
Vector3f pixel_uv = Vector3f_Add(pixel_u, pixel_v);
Vector3f pixel_center = Vector3f_Add(pixel00_loc, pixel_uv);
Vector3f ray_direction = Vector3f_Sub(pixel_center, camera_center);
r.origin = camera_center;
r.direction = ray_direction;