Skip to content

Commit

Permalink
Merge pull request #67 from nodec-project/feature/cxx17
Browse files Browse the repository at this point in the history
CHANGE: Update cxx17
  • Loading branch information
ContentsViewer authored Aug 12, 2024
2 parents b208cd0 + 44c0066 commit 3840dcb
Show file tree
Hide file tree
Showing 18 changed files with 320 additions and 61 deletions.
2 changes: 1 addition & 1 deletion CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ add_library(${PROJECT_NAME} STATIC
src/nodec/unicode.cpp
)

target_compile_features(${PROJECT_NAME} PUBLIC cxx_std_14)
target_compile_features(${PROJECT_NAME} PUBLIC cxx_std_17)

target_include_directories(
${PROJECT_NAME}
Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -53,4 +53,4 @@ The list of projects using `nodec` framework.

## Requirements

* C++14
* C++17
2 changes: 1 addition & 1 deletion README_jp.md
Original file line number Diff line number Diff line change
Expand Up @@ -51,4 +51,4 @@ OSやSDKと仲がいい。

## 必須環境

* C++14
* C++17
49 changes: 49 additions & 0 deletions include/nodec/gfx/bouding_box.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
#ifndef NODEC__GFX__BOUNDING_BOX_HPP_
#define NODEC__GFX__BOUNDING_BOX_HPP_

#include "../vector3.hpp"

namespace nodec {
namespace gfx {

struct BoundingBox {
static constexpr BoundingBox from_minmax(const Vector3f &min, const Vector3f &max) {
BoundingBox result;
result.set_minmax(min, max);
return result;
}

Vector3f center;
Vector3f extents;

constexpr BoundingBox()
: center{0.f, 0.f, 0.f}, extents{0.f, 0.f, 0.f} {}

constexpr BoundingBox(const Vector3f &center, const Vector3f &extents)
: center(center), extents(extents) {}

constexpr Vector3f(min)() const {
return center - extents;
}

constexpr Vector3f(max)() const {
return center + extents;
}

constexpr void set_minmax(const Vector3f &min, const Vector3f &max) {
center = (min + max) / 2.0f;
extents = (max - min) / 2.0f;
}
};

inline constexpr bool operator==(const BoundingBox &lhs, const BoundingBox &rhs) {
return lhs.center == rhs.center && lhs.extents == rhs.extents;
}

inline constexpr bool operator!=(const BoundingBox &lhs, const BoundingBox &rhs) {
return !(lhs == rhs);
}

} // namespace gfx
} // namespace nodec
#endif
128 changes: 128 additions & 0 deletions include/nodec/gfx/frustum.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,128 @@
#ifndef NODEC__GFX__FRUSTUM_HPP_
#define NODEC__GFX__FRUSTUM_HPP_

#include "../math/math.hpp"
#include "../vector3.hpp"
#include "bouding_box.hpp"

namespace nodec {
namespace gfx {

struct Plane {
//! Normal vector (Unit vector) of the plane.
Vector3f normal{0.f, 1.f, 0.f};

//! Distance from original to the nearest point of the plane.
float distance{0.f};

constexpr Plane(const Vector3f &p, const Vector3f &n)
: normal(math::normalize(n)), distance(math::dot(p, normal)) {}

constexpr Plane()
: normal{0.f, 1.f, 0.f}, distance{0.f} {}
};

struct Frustum {
union {
struct {
Plane near_plane;
Plane far_plane;
Plane left_plane;
Plane right_plane;
Plane top_plane;
Plane bottom_plane;
};
Plane planes[6];
};
constexpr Frustum()
: near_plane{}, far_plane{}, left_plane{}, right_plane{}, top_plane{}, bottom_plane{} {}
};

/**
* @brief Set the frustum from camera lh object
*
* @param position
* @param forward
* @param up
* @param right
* @param aspect w/h
* @param fov
* @param z_near
* @param z_far
* @param frustum
*/
inline void set_frustum_from_projection_lh(const Vector3f &position,
const Vector3f forward, const Vector3f &up, const Vector3f &right,
float aspect, float fov, float z_near, float z_far, Frustum &frustum) {
const float half_v_side = z_far * std::tanhf(fov * .5f);
const float half_h_side = half_v_side * aspect;
Vector3f front_mult_far = z_far * forward;

frustum.near_plane = Plane{position + z_near * forward, forward};
frustum.far_plane = Plane{position + front_mult_far, -forward};
frustum.right_plane = Plane{
position, math::cross(front_mult_far + right * half_h_side, up)};
frustum.left_plane = Plane{
position, math::cross(front_mult_far - right * half_h_side, -up)};
frustum.top_plane = Plane{
position, math::cross(front_mult_far + up * half_v_side, -right)};
frustum.bottom_plane = Plane{
position, math::cross(front_mult_far - up * half_v_side, right)};
}

inline void set_frustum_from_orthographic(const Vector3f &position,
const Vector3f forward, const Vector3f &up, const Vector3f &right,
float width, float height, float z_near, float z_far, Frustum &frustum) {
const Vector3f half_right = right * width / 2.f;
const Vector3f half_up = up * height / 2.f;
frustum.near_plane = Plane{position + z_near * forward, forward};
frustum.far_plane = Plane{position + z_far * forward, -forward};
frustum.right_plane = Plane{position + half_right, -right};
frustum.left_plane = Plane{position - half_right, right};
frustum.top_plane = Plane{position + half_up, -up};
frustum.bottom_plane = Plane{position - half_up, up};
}

inline float distance(const Plane &plane, const Vector3f &point) {
return math::dot(plane.normal, point) - plane.distance;
}

inline bool intersects(const Plane &plane, const BoundingBox &bounds) {
// Compute the projection interval radius of b onto L(t) = b.c + t * p.n
const float r = bounds.extents.x * std::abs(plane.normal.x) + bounds.extents.y * std::abs(plane.normal.y) + bounds.extents.z * std::abs(plane.normal.z);
return -r <= distance(plane, bounds.center);
}

inline bool intersects(const Frustum &frustum, const BoundingBox &bounds, const Matrix4x4f &bounds_local_to_world) {
const Vector4f global_center = bounds_local_to_world * Vector4f(bounds.center, 1.0f);

const Vector3f right = Vector3f(bounds_local_to_world.m[0], bounds_local_to_world.m[1], bounds_local_to_world.m[2]) * bounds.extents.x;
const Vector3f up = Vector3f(bounds_local_to_world.m[4], bounds_local_to_world.m[5], bounds_local_to_world.m[6]) * bounds.extents.y;
const Vector3f forward = Vector3f(bounds_local_to_world.m[8], bounds_local_to_world.m[9], bounds_local_to_world.m[10]) * bounds.extents.z;

const float new_ii = std::abs(math::dot(Vector3f(1.f, 0.f, 0.f), right))
+ std::abs(math::dot(Vector3f(1.f, 0.f, 0.f), up))
+ std::abs(math::dot(Vector3f(1.f, 0.f, 0.f), forward));

const float new_ij = std::abs(math::dot(Vector3f(0.f, 1.f, 0.f), right))
+ std::abs(math::dot(Vector3f(0.f, 1.f, 0.f), up))
+ std::abs(math::dot(Vector3f(0.f, 1.f, 0.f), forward));

const float new_ik = std::abs(math::dot(Vector3f(0.f, 0.f, 1.f), right))
+ std::abs(math::dot(Vector3f(0.f, 0.f, 1.f), up))
+ std::abs(math::dot(Vector3f(0.f, 0.f, 1.f), forward));

const BoundingBox global_bounds(Vector3f(global_center.x, global_center.y, global_center.z), Vector3f(new_ii, new_ij, new_ik));

return (intersects(frustum.left_plane, global_bounds)
&& intersects(frustum.right_plane, global_bounds)
&& intersects(frustum.top_plane, global_bounds)
&& intersects(frustum.bottom_plane, global_bounds)
&& intersects(frustum.near_plane, global_bounds)
&& intersects(frustum.far_plane, global_bounds));
}

} // namespace gfx
} // namespace nodec

#endif
52 changes: 33 additions & 19 deletions include/nodec/math/gfx.hpp → include/nodec/gfx/gfx.hpp
Original file line number Diff line number Diff line change
@@ -1,10 +1,9 @@
#ifndef NODEC__MATH__GFX_HPP_
#define NODEC__MATH__GFX_HPP_
#ifndef NODEC__GFX__GFX_HPP_
#define NODEC__GFX__GFX_HPP_

#include <nodec/math/math.hpp>
#include "../math/math.hpp"

namespace nodec {
namespace math {

/**
* math utils for graphics
Expand All @@ -29,6 +28,22 @@ inline Vector3f rotate(const Vector3f &v, const Quaternionf &q) {
v.z + z * q.w + (q.x * y - q.y * x)};
}

inline Matrix4x4f translation_matrix(const Vector3f &t) {
return {
1.0f, 0.0f, 0.0f, t.x,
0.0f, 1.0f, 0.0f, t.y,
0.0f, 0.0f, 1.0f, t.z,
0.0f, 0.0f, 0.0f, 1.0f};
}

inline Matrix4x4f scale_matrix(const float x, const float y, const float z) {
return {
x, 0.0f, 0.0f, 0.0f,
0.0f, y, 0.0f, 0.0f,
0.0f, 0.0f, z, 0.0f,
0.0f, 0.0f, 0.0f, 1.0f};
}

inline Quaternionf quaternion_from_rotation_matrix(const Matrix4x4f &matrix) {
float sqrt;
float half;
Expand Down Expand Up @@ -151,9 +166,9 @@ inline bool decompose_trs(const Matrix4x4f &trs, TRSComponents &components) {
}

inline Quaternionf quaternion_from_angle_axis(const float &angle_deg, const Vector3f &axis) {
auto theta = angle_deg * deg2rad<float> / 2.0f;
auto theta = angle_deg * math::deg2rad<float> / 2.0f;
auto s = std::sin(theta);
auto a = normalize(axis);
auto a = math::normalize(axis);
return {a.x * s, a.y * s, a.z * s, std::cos(theta)};
}

Expand Down Expand Up @@ -182,19 +197,19 @@ inline Vector3f euler_angles_xyz(const Quaternionf &rotation) {
float cos_z = 2 * (rotation.x * rotation.x + rotation.w * rotation.w) - 1;
angles.z = std::atan2(sin_z, cos_z);

return angles * rad2deg<float>;
return angles * math::rad2deg<float>;
}

/**
* Rx * Ry * Rz = R
*/
inline Quaternionf euler_angles_xyz(const Vector3f &euler) {
float cx = std::cos(euler.x * 0.5f * deg2rad<float>);
float sy = std::sin(euler.y * 0.5f * deg2rad<float>);
float sz = std::sin(euler.z * 0.5f * deg2rad<float>);
float sx = std::sin(euler.x * 0.5f * deg2rad<float>);
float cy = std::cos(euler.y * 0.5f * deg2rad<float>);
float cz = std::cos(euler.z * 0.5f * deg2rad<float>);
float cx = std::cos(euler.x * 0.5f * math::deg2rad<float>);
float sy = std::sin(euler.y * 0.5f * math::deg2rad<float>);
float sz = std::sin(euler.z * 0.5f * math::deg2rad<float>);
float sx = std::sin(euler.x * 0.5f * math::deg2rad<float>);
float cy = std::cos(euler.y * 0.5f * math::deg2rad<float>);
float cz = std::cos(euler.z * 0.5f * math::deg2rad<float>);

return {
cx * sy * sz + sx * cy * cz,
Expand All @@ -206,11 +221,11 @@ inline Quaternionf euler_angles_xyz(const Vector3f &euler) {
inline Quaternionf look_rotation(const Vector3f &forward, const Vector3f &upwards = Vector3f(0.f, 1.f, 0.f)) {
// https://stackoverflow.com/questions/53143175/writing-a-lookat-function

auto z = normalize(forward);
auto x = cross(upwards, z);
x = normalize(x);
auto y = cross(z, x);
y = normalize(y);
auto z = math::normalize(forward);
auto x = math::cross(upwards, z);
x = math::normalize(x);
auto y = math::cross(z, x);
y = math::normalize(y);

Matrix4x4f matrix(
x.x, y.x, z.x, 0.f,
Expand All @@ -221,7 +236,6 @@ inline Quaternionf look_rotation(const Vector3f &forward, const Vector3f &upward
}

} // namespace gfx
} // namespace math
} // namespace nodec

#endif
9 changes: 7 additions & 2 deletions include/nodec/math/math.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ inline T norm(const Quaternion<T> &q) {
}

template<typename T>
inline T normalize(const T &v) {
inline constexpr T normalize(const T &v) {
return v / norm(v);
}

Expand All @@ -72,7 +72,7 @@ inline T dot(const Vector2<T> &a, const Vector2<T> &b) {
}

template<typename T>
inline T dot(const Vector3<T> &a, const Vector3<T> &b) {
inline constexpr T dot(const Vector3<T> &a, const Vector3<T> &b) {
return a.x * b.x + a.y * b.y + a.z * b.z;
}

Expand All @@ -81,6 +81,11 @@ inline T dot(const Vector4<T> &a, const Vector4<T> &b) {
return a.x * b.x + a.y * b.y + a.z * b.z + a.w * b.w;
}

/**
* @brief Calculate cross product.
*
* @note This equation is same on left-handed and right-handed coordinate system.
*/
template<typename T>
inline Vector3<T> cross(const Vector3<T> &a, const Vector3<T> &b) {
return {
Expand Down
Loading

0 comments on commit 3840dcb

Please sign in to comment.