diff --git a/ashura/engine/font_atlas.h b/ashura/engine/font_atlas.h index 6efd6c586..e6a7c5a03 100644 --- a/ashura/engine/font_atlas.h +++ b/ashura/engine/font_atlas.h @@ -20,7 +20,7 @@ struct CpuFontAtlas ImageLayerSpan span() const { - return ImageLayerSpan{.channels = ::ash::span(channels), + return ImageLayerSpan{.channels = ash::span(channels), .width = extent.x, .height = extent.y, .layers = num_layers}; diff --git a/ashura/engine/text_compositor.h b/ashura/engine/text_compositor.h index 181f3026f..5cbb265ca 100644 --- a/ashura/engine/text_compositor.h +++ b/ashura/engine/text_compositor.h @@ -101,8 +101,8 @@ struct [[nodiscard]] TextCursor constexpr Slice32 as_slice(u32 len) const { - u32 rfirst = (u32)::ash::clamp(first, (i64) 0, (i64) len); - u32 rlast = (u32)::ash::clamp(last, (i64) 0, (i64) len); + u32 rfirst = (u32) ash::clamp(first, (i64) 0, (i64) len); + u32 rlast = (u32) ash::clamp(last, (i64) 0, (i64) len); if (rfirst > rlast) { swap(rfirst, rlast); @@ -138,8 +138,8 @@ struct [[nodiscard]] TextCursor { return TextCursor{}; } - return TextCursor{::ash::clamp(first, (i64) 0, (i64) (len - 1)), - ::ash::clamp(last, (i64) 0, (i64) (len - 1))}; + return TextCursor{ash::clamp(first, (i64) 0, (i64) (len - 1)), + ash::clamp(last, (i64) 0, (i64) (len - 1))}; } }; diff --git a/ashura/std/async.h b/ashura/std/async.h index e5f107822..4ffbf4265 100644 --- a/ashura/std/async.h +++ b/ashura/std/async.h @@ -828,17 +828,17 @@ TaskInfo to_task_info(F &frame) fn(&frame, [](F *frame, void *mem) { new (mem) F{(F &&) (*frame)}; }); TaskInfo::Uninit uninit = [](void *f) { - F *frame = (F *) f; + F *frame = reinterpret_cast(f); frame->~F(); }; TaskInfo::Poll poll = [](void *f) -> bool { - F *frame = (F *) f; + F *frame = reinterpret_cast(f); return frame->poll(); }; TaskInfo::Run run = [](void *f) -> bool { - F *frame = (F *) f; + F *frame = reinterpret_cast(f); return frame->run(); }; @@ -1060,7 +1060,7 @@ template void once(Tuple fns, P poll = {}, TaskSchedule schedule = {}) { TaskBody body{[fns = std::move(fns)]() mutable -> bool { - ::ash::fold(fns); + ash::fold(fns); return false; }, std::move(poll)}; diff --git a/ashura/std/fs.h b/ashura/std/fs.h index 076b49ffa..0b8e163cb 100644 --- a/ashura/std/fs.h +++ b/ashura/std/fs.h @@ -186,8 +186,7 @@ Result read_file(Span path, Vec &buff); inline Result<> path_append(Vec &path, Span tail) { - if (!path.is_empty() && path[path.size() - 1] != '/' && - path[path.size() - 1] != '\\') + if (!path.is_empty() && path.last() != '/' && path.last() != '\\') { if (!path.push('/')) { diff --git a/ashura/std/math.h b/ashura/std/math.h index 3b61d3cb4..14527f01c 100644 --- a/ashura/std/math.h +++ b/ashura/std/math.h @@ -110,6 +110,24 @@ constexpr f64 to_radians(f64 degree) return PI * degree * 0.00555555555; } +inline f32 sqrt(f32 x) +{ + return std::sqrt(x); +} + +inline f64 sqrt(f64 x) +{ + return std::sqrt(x); +} + +constexpr f32 invsqrt(f32 x) +{ + // (enable only on IEEE 754) + static_assert(std::numeric_limits::is_iec559); + f32 const y = std::bit_cast(0x5F3759DF - (std::bit_cast(x) >> 1)); + return y * (1.5F - (x * 0.5F * y * y)); +} + /// @brief Calculate log base 2 of an unsigned integer. Undefined behaviour if /// value is 0 constexpr u8 ulog2(u8 value) @@ -241,6 +259,87 @@ constexpr T catmull_rom(T const &p0, T const &p1, T const &p2, T const &p3, (-p0 + 3 * p1 - 3 * p2 + p3) * t * t * t); } +/// @brief Elastic Easing +/// @param amplitude strength of the elastic effect (default = 1.0) +/// @param period length of the oscillation (default = 0.3) +/// @note Based on Robert Penner's elastic easing +/// (http://robertpenner.com/easing/) +inline f32 elastic(f32 amplitude, f32 period, f32 t) +{ + constexpr f32 TWO_PI = 2.0F * PI; + f32 const s = (period / TWO_PI) * std::asin(1 / amplitude); + f32 const factor = amplitude * std::pow(2.0F, -10.0F * t) * + std::sin((t - s) * (TWO_PI / period)) + + 1.0F; + return factor; +} + +/// @brief EaseOut Bounce +/// @param strength strength of the bounce effect (default = 1.0) +/// @note Based on Robert Penner's easeOutBounce +/// (http://robertpenner.com/easing/) +constexpr f32 bounce(f32 strength, f32 t) +{ + // Inverse the time to create an ease-out effect + t = 1.0F - t; + + if (t < (1.0F / 2.75F)) + { + return 1.0F - (7.5625F * t * t * strength); + } + else if (t < (2.0F / 2.75F)) + { + t -= 1.5F / 2.75F; + return 1.0F - (7.5625F * t * t * strength + 0.75F); + } + else if (t < (2.5F / 2.75F)) + { + t -= 2.25F / 2.75F; + return 1.0F - (7.5625F * t * t * strength + 0.9375F); + } + else + { + t -= 2.625F / 2.75F; + return 1.0F - (7.5625F * t * t * strength + 0.984375F); + } +} + +/// @brief Spring-based Elastic Easing based on simple harmonic motion with +/// damping +/// +/// The default behavior is a tight spring effect, tune the parameters to give +/// a desired effect. +/// @param mass: Oscillator mass (default: 1.0) +/// @param stiffness: Spring constant (default: 20.0) +/// @param damping: Damping coefficient (default: 10.0F) +/// +/// @note https://www.ryanjuckett.com/damped-springs/ +/// +inline f32 spring(f32 mass, f32 stiffness, f32 damping, f32 t) +{ + // Calculate critical damping factors + f32 const omega0 = std::sqrt(stiffness / mass); + f32 const critical_damping = 2.0F * std::sqrt(mass * stiffness); + f32 const damping_ratio = damping / critical_damping; + + // Underdamped + if (damping_ratio < 1.0F) + { + f32 const omega_d = + omega0 * std::sqrt(1.0F - damping_ratio * damping_ratio); + return 1.0F - + std::exp(-damping_ratio * omega0 * t) * + (std::cos(omega_d * t) + + (damping_ratio * omega0 / omega_d) * std::sin(omega_d * t)); + } + + // Overdamped or critically damped + f32 const alpha = -damping_ratio * omega0; + f32 const beta = omega0 * std::sqrt(damping_ratio * damping_ratio - 1.0F); + return 1.0F - (std::exp(alpha * t) * + (std::cosh(beta * t) + (alpha / beta) * std::sinh(beta * t))); +} + constexpr f32 step(f32 a, f32 t) { return (t < a) ? 0.0F : 1.0F; @@ -1384,27 +1483,19 @@ constexpr Vec3I cross(Vec3I a, Vec3I b) a.x * b.y - a.y * b.x}; } -constexpr f32 inverse_sqrt(f32 num) -{ - // (enable only on IEEE 754) - static_assert(std::numeric_limits::is_iec559); - f32 const y = std::bit_cast(0x5F3759DF - (std::bit_cast(num) >> 1)); - return y * (1.5F - (num * 0.5F * y * y)); -} - constexpr Vec2 normalize(Vec2 a) { - return a * inverse_sqrt(dot(a, a)); + return a * invsqrt(dot(a, a)); } constexpr Vec3 normalize(Vec3 a) { - return a * inverse_sqrt(dot(a, a)); + return a * invsqrt(dot(a, a)); } constexpr Vec4 normalize(Vec4 a) { - return a * inverse_sqrt(dot(a, a)); + return a * invsqrt(dot(a, a)); } struct Mat2 diff --git a/ashura/std/str.h b/ashura/std/str.h index 5e32e2f30..7a26e4f82 100644 --- a/ashura/std/str.h +++ b/ashura/std/str.h @@ -29,7 +29,7 @@ Result<> join(Span const> strings, Span delimiter, } } - if (!out.extend_copy(strings[strings.size() - 1])) + if (!out.extend_copy(strings.last())) { out.resize_uninit(initial_size).unwrap(); return Err{}; diff --git a/ashura/std/types.h b/ashura/std/types.h index a8e7454e5..d53b8c817 100644 --- a/ashura/std/types.h +++ b/ashura/std/types.h @@ -857,7 +857,7 @@ struct Array T data_[SIZE]{}; - constexpr bool is_empty() const + static constexpr bool is_empty() { return false; } @@ -872,36 +872,87 @@ struct Array return data_; } - constexpr usize size() const + static constexpr usize size() { return SIZE; } - constexpr usize size_bytes() const + static constexpr u32 size32() + { + return (u32) SIZE; + } + + static constexpr u64 size64() + { + return (u64) SIZE; + } + + static constexpr usize capacity() + { + return SIZE; + } + + static constexpr usize size_bytes() { return sizeof(T) * SIZE; } - constexpr T const *begin() const + constexpr T *begin() { return data_; } - constexpr T *begin() + constexpr T const *begin() const { return data_; } - constexpr T const *end() const + constexpr T *end() { return data_ + SIZE; } - constexpr T *end() + constexpr T const *end() const { return data_ + SIZE; } + constexpr T &first() + { + return get(0); + } + + constexpr T const &first() const + { + return get(0); + } + + constexpr T &last() + { + return get(SIZE - 1); + } + + constexpr T const &last() const + { + return get(SIZE - 1); + } + + constexpr T &get(usize index) + { + return data_[index]; + } + + constexpr T const &get(usize index) const + { + return data_[index]; + } + + template + constexpr void set(usize index, Args &&...args) + { + data_[index] = T{((Args &&) args)...}; + } + constexpr T &operator[](usize index) { return data_[index]; @@ -912,12 +963,12 @@ struct Array return data_[index]; } - constexpr operator T const *() const + constexpr operator T *() { return data_; } - constexpr operator T *() + constexpr operator T const *() const { return data_; } @@ -1006,6 +1057,16 @@ struct Span return data_ + size_; } + constexpr T &first() const + { + return get(0); + } + + constexpr T &last() const + { + return get(size_ - 1); + } + constexpr T &operator[](usize index) const { return data_[index]; @@ -1072,7 +1133,8 @@ struct Span template Span reinterpret() const { - return Span{(U *) data_, (sizeof(T) * size_) / sizeof(U)}; + return Span{reinterpret_cast(data_), + (sizeof(T) * size_) / sizeof(U)}; } }; @@ -1335,47 +1397,47 @@ struct BitSpan constexpr bool operator[](usize index) const { - return ::ash::get_bit(repr_, index); + return ash::get_bit(repr_, index); } constexpr bool get(usize index) const { - return ::ash::get_bit(repr_, index); + return ash::get_bit(repr_, index); } constexpr void set(usize index, bool value) const { - ::ash::assign_bit(repr_, index, value); + ash::assign_bit(repr_, index, value); } constexpr bool get_bit(usize index) const { - return ::ash::get_bit(repr_, index); + return ash::get_bit(repr_, index); } constexpr bool set_bit(usize index) const { - return ::ash::set_bit(repr_, index); + return ash::set_bit(repr_, index); } constexpr bool clear_bit(usize index) const { - return ::ash::clear_bit(repr_, index); + return ash::clear_bit(repr_, index); } constexpr void flip_bit(usize index) const { - ::ash::flip_bit(repr_, index); + ash::flip_bit(repr_, index); } constexpr usize find_set_bit() { - return min(::ash::find_set_bit(repr_), size()); + return min(ash::find_set_bit(repr_), size()); } constexpr usize find_clear_bit() { - return min(::ash::find_clear_bit(repr_), size()); + return min(ash::find_clear_bit(repr_), size()); } constexpr operator BitSpan() const @@ -1461,7 +1523,7 @@ template struct PFnTraits { using Ptr = R (*)(Args...); - using Fn = ::ash::Fn; + using Fn = ash::Fn; using Return = R; using Thunk = PFnThunk; }; @@ -1491,7 +1553,7 @@ template struct MemberFnTraits { using Ptr = R (*)(Args...); - using Fn = ::ash::Fn; + using Fn = ash::Fn; using Type = T; using Return = R; using Thunk = FunctorThunk; @@ -1502,7 +1564,7 @@ template struct MemberFnTraits { using Ptr = R (*)(Args...); - using Fn = ::ash::Fn; + using Fn = ash::Fn; using Type = T const; using Return = R; using Thunk = FunctorThunk; diff --git a/ashura/std/vec.h b/ashura/std/vec.h index 0db39c2bc..767d7f9d6 100644 --- a/ashura/std/vec.h +++ b/ashura/std/vec.h @@ -84,6 +84,11 @@ struct [[nodiscard]] Vec return size_; } + constexpr usize size_bytes() const + { + return sizeof(T) * size_; + } + constexpr u32 size32() const { return (u32) size_; @@ -109,9 +114,19 @@ struct [[nodiscard]] Vec return data() + size_; } + constexpr T &first() const + { + return get(0); + } + + constexpr T &last() const + { + return get(size_ - 1); + } + constexpr T &operator[](usize index) const { - return data()[index]; + return get(index); } constexpr T &get(usize index) const @@ -449,7 +464,7 @@ struct [[nodiscard]] Vec constexpr void swap(usize a, usize b) const { - ::ash::swap(data()[a], data()[b]); + ash::swap(data()[a], data()[b]); } constexpr Result<> resize_uninit(usize new_size) @@ -604,6 +619,11 @@ struct [[nodiscard]] PinVec return size_; } + constexpr usize size_bytes() const + { + return sizeof(T) * size_; + } + constexpr u32 size32() const { return (u32) size_; @@ -629,9 +649,19 @@ struct [[nodiscard]] PinVec return data() + size_; } + constexpr T &first() const + { + return get(0); + } + + constexpr T &last() const + { + return get(size_ - 1); + } + constexpr T &operator[](usize index) const { - return data()[index]; + return get(index); } constexpr T &get(usize index) const @@ -732,11 +762,6 @@ struct [[nodiscard]] BitVec constexpr ~BitVec() = default; - constexpr bool operator[](usize index) const - { - return ::ash::get_bit(span(repr_), index); - } - constexpr Vec const &repr() const { return repr_; @@ -784,34 +809,49 @@ struct [[nodiscard]] BitVec bit_size_ = 0; } + constexpr bool operator[](usize index) const + { + return get(index); + } + + constexpr bool first() const + { + return get(0); + } + + constexpr bool last() const + { + return get(bit_size_ - 1); + } + constexpr bool get(usize index) const { - return ::ash::get_bit(span(repr_), index); + return ash::get_bit(span(repr_), index); } constexpr void set(usize index, bool value) const { - ::ash::assign_bit(span(repr_), index, value); + ash::assign_bit(span(repr_), index, value); } constexpr bool get_bit(usize index) const { - return ::ash::get_bit(span(repr_), index); + return get(index); } constexpr bool set_bit(usize index) const { - return ::ash::set_bit(span(repr_), index); + return ash::set_bit(span(repr_), index); } constexpr bool clear_bit(usize index) const { - return ::ash::clear_bit(span(repr_), index); + return ash::clear_bit(span(repr_), index); } constexpr void flip_bit(usize index) const { - ::ash::flip_bit(span(repr_), index); + ash::flip_bit(span(repr_), index); } constexpr Result<> reserve(usize target_capacity) @@ -1034,9 +1074,14 @@ struct [[nodiscard]] InplaceVec return size_ == 0; } - constexpr T *data() const + constexpr T *data() + { + return reinterpret_cast(storage_); + } + + constexpr T const *data() const { - return (T *) storage_; + return reinterpret_cast(storage_); } constexpr usize size() const @@ -1044,6 +1089,11 @@ struct [[nodiscard]] InplaceVec return size_; } + constexpr usize size_bytes() const + { + return sizeof(T) * size_; + } + constexpr u32 size32() const { return (u32) size_; @@ -1054,32 +1104,82 @@ struct [[nodiscard]] InplaceVec return (u64) size_; } - constexpr usize capacity() const + static constexpr usize capacity() { return Capacity; } - constexpr T *begin() const + constexpr T *begin() { return data(); } - constexpr T *end() const + constexpr T const *begin() const + { + return data(); + } + + constexpr T *end() { return data() + size_; } - constexpr T &operator[](usize index) const + constexpr T const *end() const + { + return data() + size_; + } + + constexpr T &first() + { + return get(0); + } + + constexpr T const &first() const + { + return get(0); + } + + constexpr T &last() + { + return get(size_ - 1); + } + + constexpr T const &last() const + { + return get(size_ - 1); + } + + constexpr T &operator[](usize index) + { + return get(index); + } + + constexpr T const &operator[](usize index) const + { + return get(index); + } + + constexpr T &get(usize index) { return data()[index]; } - constexpr T &get(usize index) const + constexpr T const &get(usize index) const { return data()[index]; } - constexpr T *try_get(usize index) const + constexpr T *try_get(usize index) + { + if (index >= size_) [[unlikely]] + { + return nullptr; + } + + return data() + index; + } + + constexpr T const *try_get(usize index) const { if (index >= size_) [[unlikely]] { @@ -1090,7 +1190,7 @@ struct [[nodiscard]] InplaceVec } template - constexpr void set(usize index, Args &&...args) const + constexpr void set(usize index, Args &&...args) { data()[index] = T{((Args &&) args)...}; } @@ -1334,9 +1434,9 @@ struct [[nodiscard]] InplaceVec return Ok{}; } - constexpr void swap(usize a, usize b) const + constexpr void swap(usize a, usize b) { - ::ash::swap(data()[a], data()[b]); + ash::swap(data()[a], data()[b]); } constexpr Result<> resize_uninit(usize new_size)