| /* |
| * Copyright 2025 Rive |
| */ |
| |
| // Provides GLSL-specific #defines and declarations that enable our shaders to |
| // be compiled as C++ and unit tested. |
| |
| #ifdef _MSC_VER |
| #error glsl cross-compiling requires the clang/gcc vector extension |
| #else |
| |
| #include "rive/math/simd.hpp" |
| #include "rive/math/math_types.hpp" |
| #include <array> |
| |
| using namespace rive; |
| #define INLINE inline |
| #define OUT(T) T& |
| #define make_float4(x, y, z, w) \ |
| float4 { x, y, z, w } |
| #define make_float2(x, y) \ |
| float2 { x, y } |
| |
| using math::PI; |
| using simd::abs; |
| using simd::any; |
| using simd::clamp; |
| using simd::dot; |
| using simd::max; |
| using simd::min; |
| using simd::sqrt; |
| using std::sqrt; |
| using float3 = vec<3>; |
| using float2x2 = std::array<float2, 2>; |
| using half4 = float4; |
| using half3 = float3; |
| using half2 = float2; |
| using half = float; |
| using uint = uint32_t; |
| using ushort = uint16_t; |
| |
| inline half4 make_half4(half x, half y, half z, half w) { return {x, y, z, w}; } |
| inline half4 make_half4(half3 xyz, half w) { return {xyz.x, xyz.y, xyz.z, w}; } |
| inline half4 make_half4(half x) { return {x, x, x, x}; } |
| inline half3 make_half3(half x, half y, half z) { return {x, y, z}; } |
| inline half3 make_half3(half x) { return {x, x, x}; } |
| inline half2 make_half2(half x, half y) { return {x, y}; } |
| inline half2 make_half2(half x) { return {x, x}; } |
| |
| using half2x3 = std::array<half3, 2>; |
| inline half2x3 make_half2x3(half3 c0, half3 c1) { return {c0, c1}; } |
| inline half3 MUL(half2x3 m, half2 v) |
| { |
| half3 ret; |
| for (int i = 0; i < 3; ++i) |
| { |
| ret[i] = m[0][i] * v[0] + m[1][i] * v[1]; |
| } |
| return ret; |
| } |
| |
| using half3x3 = std::array<half3, 3>; |
| inline half3x3 make_half3x3(half3 c0, half3 c1, half3 c2) |
| { |
| return {c0, c1, c2}; |
| } |
| inline half3 MUL(half3x3 m, half3 v) |
| { |
| half3 ret; |
| for (int i = 0; i < 3; ++i) |
| { |
| ret[i] = m[0][i] * v[0] + m[1][i] * v[1] + m[2][i] * v[2]; |
| } |
| return ret; |
| } |
| |
| inline float clamp(float x, float lo, float hi) |
| { |
| return std::clamp(x, lo, hi); |
| } |
| inline float min(float x, float y) { return std::min(x, y); } |
| inline float max(float x, float y) { return std::max(x, y); } |
| |
| template <typename T> T inversesqrt(T x) { return 1 / sqrt(x); } |
| template <int N> float length(vec<N> x) { return std::sqrt(dot(x, x)); } |
| template <int N> vec<N> normalize(vec<N> x) { return x / length(x); } |
| template <int N> vec<N> sign(vec<N> x) |
| { |
| return simd::if_then_else(x < 0, |
| vec<N>(-1), |
| simd::if_then_else(x > 0, vec<N>(1), vec<N>(0))); |
| } |
| template <int N> vec<N> mix(vec<N> a, vec<N> b, ivec<N> t) |
| { |
| return simd::if_then_else(t, b, a); |
| } |
| |
| template <int N> vec<N> mix(vec<N> a, vec<N> b, vec<N> t) |
| { |
| // Do the lerp using this form which is always correct at the endpoints |
| // (t == 0 or 1) |
| return a * (1 - t) + b * t; |
| } |
| |
| template <typename T, int N> |
| ivec<N> equal(simd::gvec<T, N> x, simd::gvec<T, N> y) |
| { |
| return x == y; |
| } |
| |
| template <typename T, int N> |
| ivec<N> notEqual(simd::gvec<T, N> x, simd::gvec<T, N> y) |
| { |
| return x != y; |
| } |
| |
| template <typename T, int N> |
| ivec<N> lessThanEqual(simd::gvec<T, N> x, simd::gvec<T, N> y) |
| { |
| return x <= y; |
| } |
| |
| template <typename T, int N> |
| ivec<N> lessThan(simd::gvec<T, N> x, simd::gvec<T, N> y) |
| { |
| return x < y; |
| } |
| |
| template <typename T, int N> |
| ivec<N> greaterThanEqual(simd::gvec<T, N> x, simd::gvec<T, N> y) |
| { |
| return x >= y; |
| } |
| |
| template <typename T, int N> |
| ivec<N> greaterThan(simd::gvec<T, N> x, simd::gvec<T, N> y) |
| { |
| return x > y; |
| } |
| |
| #endif |