1+ // Copyright (C) 2018-2025 - DevSH Graphics Programming Sp. z O.O.
2+ // This file is part of the "Nabla Engine".
3+ // For conditions of distribution and use, see copyright notice in nabla.h
4+
5+ #ifndef _NBL_BUILTIN_HLSL_IES_SAMPLER_INCLUDED_
6+ #define _NBL_BUILTIN_HLSL_IES_SAMPLER_INCLUDED_
7+
8+ #include "nbl/builtin/hlsl/cpp_compat.hlsl"
9+ #include "nbl/builtin/hlsl/numbers.hlsl"
10+ #include "nbl/builtin/hlsl/concepts.hlsl"
11+ #include "nbl/builtin/hlsl/ies/profile.hlsl"
12+
13+ namespace nbl
14+ {
15+ namespace hlsl
16+ {
17+ namespace ies
18+ {
19+ namespace concepts
20+ {
21+ #define NBL_CONCEPT_NAME IESAccessor
22+ #define NBL_CONCEPT_TPLT_PRM_KINDS (typename)
23+ #define NBL_CONCEPT_TPLT_PRM_NAMES (accessor_t)
24+ NBL_CONCEPT_BEGIN (0 )
25+ #define req_key_t uint32_t
26+ #define req_key_t2 uint32_t2
27+ #define req_value_t float32_t
28+ NBL_CONCEPT_END (
29+ ((NBL_CONCEPT_REQ_TYPE)(accessor_t::key_t))
30+ ((NBL_CONCEPT_REQ_TYPE)(accessor_t::key_t2))
31+ ((NBL_CONCEPT_REQ_TYPE)(accessor_t::value_t))
32+ ((NBL_CONCEPT_REQ_EXPR_RET_TYPE)((req_key_t (0 )), is_same_v, typename accessor_t::key_t))
33+ ((NBL_CONCEPT_REQ_EXPR_RET_TYPE)((req_key_t2 (0 , 0 )), is_same_v, typename accessor_t::key_t2))
34+ ((NBL_CONCEPT_REQ_EXPR_RET_TYPE)((req_value_t (0 )), is_same_v, typename accessor_t::value_t))
35+
36+ ((NBL_CONCEPT_REQ_EXPR_RET_TYPE)((experimental::declval<accessor_t>().vAnglesCount ()), is_same_v, req_key_t))
37+ ((NBL_CONCEPT_REQ_EXPR_RET_TYPE)((experimental::declval<accessor_t>().hAnglesCount ()), is_same_v, req_key_t))
38+ ((NBL_CONCEPT_REQ_EXPR_RET_TYPE)((experimental::declval<accessor_t>().symmetry ()), is_same_v, ProfileProperties::LuminairePlanesSymmetry))
39+ ((NBL_CONCEPT_REQ_EXPR_RET_TYPE)((experimental::declval<accessor_t>().template vAngle<req_key_t>((req_key_t)0 )), is_same_v, req_value_t))
40+ ((NBL_CONCEPT_REQ_EXPR_RET_TYPE)((experimental::declval<accessor_t>().template hAngle<req_key_t>((req_key_t)0 )), is_same_v, req_value_t))
41+ ((NBL_CONCEPT_REQ_EXPR_RET_TYPE)((experimental::declval<accessor_t>().template value<req_key_t2>((req_key_t2)0 )), is_same_v, req_value_t))
42+ );
43+ #undef req_key_t
44+ #undef req_key_t2
45+ #undef req_value_t
46+ #include <nbl/builtin/hlsl/concepts/__end.hlsl>
47+
48+ template<typename accessor_t>
49+ NBL_BOOL_CONCEPT IsIESAccessor = IESAccessor<accessor_t>;
50+ }
51+
52+ template<typename Accessor NBL_FUNC_REQUIRES (concepts::IsIESAccessor<Accessor>)
53+ struct CandelaSampler
54+ {
55+ using accessor_t = Accessor;
56+ using value_t = typename accessor_t::value_t;
57+ using symmetry_t = ProfileProperties::LuminairePlanesSymmetry;
58+
59+ static value_t sample (NBL_CONST_REF_ARG (accessor_t) accessor, const float32_t2 polar)
60+ {
61+ const float32_t vAngle = degrees (polar.x);
62+ const float32_t hAngle = degrees (wrapPhi (polar.y, symmetry));
63+
64+ const float32_t vABack = accessor.vAngle (accessor.vAnglesCount () - 1u);
65+ if (vAngle > vABack)
66+ return 0.f ;
67+
68+ const symmetry_t symmetry = accessor.symmetry ();
69+ const uint32_t j0 = getVLB (accessor, vAngle);
70+ const uint32_t j1 = getVUB (accessor, vAngle);
71+ const uint32_t i0 = (symmetry == ISOTROPIC) ? 0u : getHLB (accessor, hAngle);
72+ const uint32_t i1 = (symmetry == ISOTROPIC) ? 0u : getHUB (accessor, hAngle);
73+
74+ const float32_t uReciprocal = ((i1 == i0) ? 1.f : 1.f / (accessor.hAngle (i1) - accessor.hAngle (i0)));
75+ const float32_t vReciprocal = ((j1 == j0) ? 1.f : 1.f / (accessor.vAngle (j1) - accessor.vAngle (j0)));
76+
77+ const float32_t u = ((hAngle - accessor.hAngle (i0)) * uReciprocal);
78+ const float32_t v = ((vAngle - accessor.vAngle (j0)) * vReciprocal);
79+
80+ const float32_t s0 = (accessor.value (uint32_t2 (i0, j0)) * (1.f - v) + accessor.value (uint32_t2 (i0, j1)) * v);
81+ const float32_t s1 = (accessor.value (uint32_t2 (i1, j0)) * (1.f - v) + accessor.value (uint32_t2 (i1, j1)) * v);
82+
83+ return s0 * (1.f - u) + s1 * u;
84+ }
85+
86+ static float32_t wrapPhi (const float32_t phi, const symmetry_t symmetry)
87+ {
88+ switch (symmetry)
89+ {
90+ case ISOTROPIC: //! axial symmetry
91+ return 0.0f ;
92+ case QUAD_SYMETRIC: //! phi MIRROR_REPEAT wrap onto [0, 90] degrees range
93+ {
94+ NBL_CONSTEXPR float32_t M_HALF_PI = numbers::pi<float32_t> *0.5f ;
95+ float32_t wrapPhi = abs (phi); //! first MIRROR
96+ if (wrapPhi > M_HALF_PI) //! then REPEAT
97+ wrapPhi = hlsl::clamp (M_HALF_PI - (wrapPhi - M_HALF_PI), 0.f , M_HALF_PI);
98+ return wrapPhi; //! eg. maps (in degrees) 91,269,271 -> 89 and 179,181,359 -> 1
99+ }
100+ case HALF_SYMETRIC: //! phi MIRROR wrap onto [0, 180] degrees range
101+ case OTHER_HALF_SYMMETRIC: //! eg. maps (in degress) 181 -> 179 or 359 -> 1
102+ return abs (phi);
103+ case NO_LATERAL_SYMMET: //! plot onto whole (in degress) [0, 360] range
104+ {
105+ NBL_CONSTEXPR float32_t M_TWICE_PI = numbers::pi<float32_t> *2.f ;
106+ return (phi < 0.f ) ? (phi + M_TWICE_PI) : phi;
107+ }
108+ }
109+ return 69.f ;
110+ }
111+
112+ struct impl_t
113+ {
114+ static uint32_t getVUB (NBL_CONST_REF_ARG (accessor_t) accessor, const float32_t angle)
115+ {
116+ for (uint32_t i = 0u; i < accessor.vAnglesCount (); ++i)
117+ if (accessor.vAngle (i) > angle)
118+ return i;
119+ return accessor.vAnglesCount ();
120+ }
121+
122+ static uint32_t getHUB (NBL_CONST_REF_ARG (accessor_t) accessor, const float32_t angle)
123+ {
124+ for (uint32_t i = 0u; i < accessor.hAnglesCount (); ++i)
125+ if (accessor.hAngle (i) > angle)
126+ return i;
127+ return accessor.hAnglesCount ();
128+ }
129+ };
130+
131+ static uint32_t getVLB (NBL_CONST_REF_ARG (accessor_t) accessor, const float32_t angle)
132+ {
133+ return (uint32_t)hlsl::max ((int64_t)impl_t::getVUB (accessor, angle) - 1ll, 0ll);
134+ }
135+
136+ static uint32_t getHLB (NBL_CONST_REF_ARG (accessor_t) accessor, const float32_t angle)
137+ {
138+ return (uint32_t)hlsl::max ((int64_t)impl_t::getHUB (accessor, angle) - 1ll, 0ll);
139+ }
140+
141+ static uint32_t getVUB (NBL_CONST_REF_ARG (accessor_t) accessor, const float32_t angle)
142+ {
143+ return (uint32_t)hlsl::min ((int64_t)impl_t::getVUB (accessor, angle), (int64_t)(accessor.vAnglesCount () - 1u));
144+ }
145+
146+ static uint32_t getHUB (NBL_CONST_REF_ARG (accessor_t) accessor, const float32_t angle)
147+ {
148+ return (uint32_t)hlsl::min ((int64_t)impl_t::getHUB (accessor, angle), (int64_t)(accessor.hAnglesCount () - 1u));
149+ }
150+ };
151+
152+ }
153+ }
154+ }
155+
156+ #endif // _NBL_BUILTIN_HLSL_IES_SAMPLER_INCLUDED_
0 commit comments