@@ -220,151 +220,36 @@ class CFrontendIR final : public CNodePool
220220 };
221221
222222 // This node could also represent non directional emission, but we have another node for that
223- class CSpectralVariable final : public obj_pool_type::IVariableSize , public IExprNode
223+ class ISpectralVariableExpr : public CTrueIR ::ISpectralVariable , public IExprNode
224224 {
225225 public:
226- inline uint8_t getChildCount () const override final { return 0 ; }
227- inline const std::string_view getTypeName () const override {return TYPE_NAME_STR (CSpectralVariable);}
228226 // Variable length but has no children
227+ inline uint8_t getChildCount () const override final {return 0 ;}
229228
230229 //
231- inline IExprNode::Type getType () const override {return Type::SpectralVariable;}
230+ inline IExprNode::Type getType () const override final {return Type::SpectralVariable;}
232231
233- using semantics_e = CTrueIR::ISpectralVariable::ESemantics;
234232 //
235- template <uint8_t Count>
236- struct SCreationParams
237- {
238- // Knots are "data points" on the (wavelength,value) plot, from which we can interpolate the rest of the spectrum
239- CTrueIR::SParameterSet<Count> knots = {};
240-
241- // a little bit of abuse and padding reuse
242- template <bool Enable=true > requires (Enable==(Count>1 ))
243- semantics_e& getSemantics() {return reinterpret_cast <semantics_e&>(knots.params [1 ].padding [0 ]); }
244- template <bool Enable=true > requires (Enable==(Count>1 ))
245- const semantics_e& getSemantics() const {return const_cast <const semantics_e&>(const_cast <SCreationParams<Count>*>(this )->getSemantics ());}
246- };
247- //
248- template <uint8_t Count>
249- inline CSpectralVariable (SCreationParams<Count>&& params)
250- {
251- // back up the count
252- static_assert (sizeof (CTrueIR::SParameter::padding)>1 );
253- params.knots .params [0 ].padding [1 ] = Count;
254- // set it correctly for monochrome
255- if constexpr (Count==1 )
256- params.knots .params [1 ].padding [0 ] = static_cast <uint8_t >(semantics_e::NoneUndefined);
257- else
258- {
259- assert (params.getSemantics ()!=semantics_e::NoneUndefined);
260- }
261- std::construct_at (reinterpret_cast <SCreationParams<Count>*>(this +1 ),std::move (params));
262- }
263- inline CSpectralVariable (const CSpectralVariable& other)
264- {
265- const auto * const src = other.pWonky ();
266- auto * const dst = pWonky ();
267- std::uninitialized_copy_n (src,1 ,dst);
268- const size_t count = other.getKnotCount ();
269- std::uninitialized_copy_n (src->knots .params +1 ,count-1 ,dst->knots .params +1 );
270- }
271-
272- // encapsulation due to padding abuse
273- inline auto & uvTransform () {return pWonky ()->knots .uvTransform ;}
274- inline const auto & uvTransform () const {return pWonky ()->knots .uvTransform ;}
275-
276- inline uint8_t & uvSlot () {return pWonky ()->knots .uvSlot ();}
277- inline const uint8_t & uvSlot () const {return pWonky ()->knots .uvSlot ();}
278-
279- // these getters are immutable
280- inline uint8_t getKnotCount () const
281- {
282- static_assert (sizeof (CTrueIR::SParameter::padding)>1 );
283- return pWonky ()->knots .params [0 ].padding [1 ];
284- }
285- inline semantics_e getSemantics () const
286- {
287- if (getKnotCount ()<2 )
288- return semantics_e::NoneUndefined;
289- return static_cast <semantics_e>(pWonky ()->knots .params [1 ].padding [0 ]);
290- }
291-
292- //
293- inline CTrueIR::SParameter* getParam (const uint8_t i)
294- {
295- if (i<getKnotCount ())
296- return &pWonky ()->knots .params [i];
297- return nullptr ;
298- }
299- inline const CTrueIR::SParameter* getParam (const uint8_t i) const {return const_cast <const CTrueIR::SParameter*>(const_cast <CSpectralVariable*>(this )->getParam (i));}
300-
301- //
302- template <uint8_t Count>
303- static inline uint32_t calc_size (const SCreationParams<Count>&)
304- {
305- return sizeof (CSpectralVariable)+sizeof (SCreationParams<Count>);
306- }
307- // for copying
308- static inline uint32_t calc_size (const CSpectralVariable& other)
309- {
310- return sizeof (CSpectralVariable)+sizeof (SCreationParams<1 >)+(other.getKnotCount ()-1 )*sizeof (CTrueIR::SParameter);
311- }
312-
313- inline operator bool () const {return !invalid (SInvalidCheckArgs{.pool =nullptr ,.logger =nullptr });}
233+ inline operator bool () const {return valid (nullptr );}
314234
315235 protected:
316- inline ~CSpectralVariable ()
317- {
318- std::destroy_n (pWonky ()->knots .params ,getKnotCount ());
319- }
320236 inline _typed_pointer_type<IExprNode> copy (CFrontendIR* ir) const override final
321237 {
322- auto & pool = ir->getObjectPool ();
323- const uint8_t count = getKnotCount ();
324- return pool.emplace <CSpectralVariable>(*this );
238+ return static_cast <const CSpectralVariableExpr*>(this )->copy (ir->getObjectPool ());
325239 }
326240
327- inline bool invalid (const SInvalidCheckArgs& args) const override
328- {
329- const auto knotCount = getKnotCount ();
330- // non-monochrome spectral variable
331- if (const auto semantic=getSemantics (); knotCount>1 )
332- switch (semantic)
333- {
334- case semantics_e::Fixed3_SRGB: [[fallthrough]];
335- case semantics_e::Fixed3_DCI_P3: [[fallthrough]];
336- case semantics_e::Fixed3_BT2020: [[fallthrough]];
337- case semantics_e::Fixed3_AdobeRGB: [[fallthrough]];
338- case semantics_e::Fixed3_AcesCG:
339- if (knotCount!=3 )
340- {
341- args.logger .log (" Semantic %d is only usable with 3 knots, this has %d knots" ,system::ILogger::ELL_ERROR,static_cast <uint8_t >(semantic),knotCount);
342- return false ;
343- }
344- break ;
345- default :
346- args.logger .log (" Invalid Semantic %d" ,system::ILogger::ELL_ERROR,static_cast <uint8_t >(semantic));
347- return true ;
348- }
349- for (auto i=0u ; i<knotCount; i++)
350- if (!*getParam (i))
351- {
352- args.logger .log (" Knot %u parameters invalid" ,system::ILogger::ELL_ERROR,i);
353- return true ;
354- }
355- return false ;
356- }
241+ //
242+ inline bool invalid (const SInvalidCheckArgs& args) const override final {return !valid (args.logger );}
357243
358- NBL_API2 core::string getLabelSuffix () const override ;
359- NBL_API2 void printDot (std::ostringstream& sstr, const core::string& selfID) const override ;
360-
361- private:
362- SCreationParams<1 >* pWonky () {return reinterpret_cast <SCreationParams<1 >*>(this +1 );}
363- const SCreationParams<1 >* pWonky () const {return reinterpret_cast <const SCreationParams<1 >*>(this +1 );}
244+ //
245+ NBL_API2 core::string getLabelSuffix () const override final ;
246+ NBL_API2 void printDot (std::ostringstream& sstr, const core::string& selfID) const override final ;
364247
248+ //
365249 friend class CFrontendIR ;
366- NBL_API2 CTrueIR::typed_pointer_type<CTrueIR::ISpectralVariable > createIRNode (const CFrontendIR* ast, CTrueIR* ir) const ;
250+ NBL_API2 CTrueIR::typed_pointer_type<CTrueIR::CSpectralVariableFactor > createIRNode (const CFrontendIR* ast, CTrueIR* ir) const ;
367251 };
252+ using CSpectralVariableExpr = CTrueIR::CSpectralVariable<ISpectralVariableExpr>;
368253 //
369254 class IUnaryOp : public obj_pool_type ::INonTrivial, public IExprNode
370255 {
@@ -483,16 +368,16 @@ class CFrontendIR final : public CNodePool
483368
484369 // Effective transparency = exp2(log2(perpTransmittance)*thickness/dot(refract(V,X,eta),X)) = exp2(log2(perpTransmittance)*thickness*inversesqrt(1.f+(LdotX-1)*rcpEta))
485370 // Eta and `LdotX` is taken from the leaf BTDF node. With refractions from Dielectrics, we get just `1/LdotX`, for Delta Transmission we get `1/VdotN` since its the same
486- typed_pointer_type<CSpectralVariable > perpTransmittance = {};
487- typed_pointer_type<CSpectralVariable > thickness = {};
371+ typed_pointer_type<CSpectralVariableExpr > perpTransmittance = {};
372+ typed_pointer_type<CSpectralVariableExpr > thickness = {};
488373
489374 protected:
490375 COPY_DEFAULT_IMPL
491376
492377 inline typed_pointer_type<IExprNode> getChildHandle_impl (const uint8_t ix) const override {return ix ? perpTransmittance:thickness;}
493378 inline void setChild_impl (const uint8_t ix, _typed_pointer_type<IExprNode> newChild) override
494379 {
495- *(ix ? &perpTransmittance:&thickness) = block_allocator_type::_static_cast<CSpectralVariable >(newChild);
380+ *(ix ? &perpTransmittance:&thickness) = block_allocator_type::_static_cast<CSpectralVariableExpr >(newChild);
496381 }
497382
498383 inline std::string_view getChildName_impl (const uint8_t ix) const override {return " Perpendicular\\ nTransmittance" ;}
@@ -509,9 +394,9 @@ class CFrontendIR final : public CNodePool
509394 inline CFresnel () = default;
510395
511396 // Already pre-divided Index of Refraction, e.g. exterior/interior since VdotG>0 the ray always arrives from the exterior.
512- typed_pointer_type<CSpectralVariable > orientedRealEta = {};
397+ typed_pointer_type<CSpectralVariableExpr > orientedRealEta = {};
513398 // Specifying this turns your Fresnel into a conductor one, note that currently these are disallowed on BTDFs!
514- typed_pointer_type<CSpectralVariable > orientedImagEta = {};
399+ typed_pointer_type<CSpectralVariableExpr > orientedImagEta = {};
515400 // if you want to reuse the same parameter but want to flip the interfaces around
516401 uint8_t reciprocateEtas : 1 = false ;
517402
@@ -521,7 +406,7 @@ class CFrontendIR final : public CNodePool
521406 inline typed_pointer_type<IExprNode> getChildHandle_impl (const uint8_t ix) const override {return ix ? orientedImagEta:orientedRealEta;}
522407 inline void setChild_impl (const uint8_t ix, _typed_pointer_type<IExprNode> newChild) override
523408 {
524- *(ix ? &orientedImagEta:&orientedRealEta) = block_allocator_type::_static_cast<CSpectralVariable >(newChild);
409+ *(ix ? &orientedImagEta:&orientedRealEta) = block_allocator_type::_static_cast<CSpectralVariableExpr >(newChild);
525410 }
526411
527412 NBL_API2 bool invalid (const SInvalidCheckArgs& args) const override ;
@@ -672,13 +557,13 @@ class CFrontendIR final : public CNodePool
672557
673558 CTrueIR::SBasicNDFParams ndParams = {};
674559 // See the comments in CTrueIR about this on a matching class
675- typed_pointer_type<CSpectralVariable > orientedRealEta = {};
560+ typed_pointer_type<CSpectralVariableExpr > orientedRealEta = {};
676561
677562 protected:
678563 COPY_DEFAULT_IMPL
679564
680565 inline typed_pointer_type<IExprNode> getChildHandle_impl (const uint8_t ix) const override {return orientedRealEta;}
681- inline void setChild_impl (const uint8_t ix, _typed_pointer_type<IExprNode> newChild) override {orientedRealEta = block_allocator_type::_static_cast<CSpectralVariable >(newChild);}
566+ inline void setChild_impl (const uint8_t ix, _typed_pointer_type<IExprNode> newChild) override {orientedRealEta = block_allocator_type::_static_cast<CSpectralVariableExpr >(newChild);}
682567
683568 NBL_API2 bool invalid (const SInvalidCheckArgs& args) const override ;
684569
@@ -752,10 +637,14 @@ class CFrontendIR final : public CNodePool
752637 {
753638 auto & pool = getObjectPool ();
754639 const auto fresnelH = pool.emplace <CFresnel>();
755- CSpectralVariable::SCreationParams<1 > params = {};
756- params.knots .params [0 ].scale = orientedRealEta;
757640 if (auto * const fresnel=pool.deref (fresnelH); fresnel)
758- fresnel->orientedRealEta = pool.emplace <CSpectralVariable>(std::move (params));
641+ {
642+ fresnel->orientedRealEta = pool.emplace <CSpectralVariableExpr>(uint8_t (1 ));
643+ if (auto * const var=pool.deref <CSpectralVariableExpr>(fresnel->orientedRealEta ); var)
644+ var->setParameter (0 ,{.scale =orientedRealEta});
645+ else
646+ return {};
647+ }
759648 return fresnelH;
760649 }
761650
@@ -983,6 +872,8 @@ class CFrontendIR final : public CNodePool
983872 return retval;
984873 }
985874};
875+
876+ template class CTrueIR ::CSpectralVariable<CFrontendIR::ISpectralVariableExpr>;
986877}
987878
988879// specialize the `to_string
0 commit comments