1+ // Copyright (C) 2022-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+ #include " nbl/asset/material_compiler3/CFrontendIR.h"
5+
6+
7+ namespace nbl ::asset::material_compiler3
8+ {
9+
10+ constexpr auto ELL_ERROR = nbl::system::ILogger::E_LOG_LEVEL::ELL_ERROR;
11+ using namespace nbl ::system;
12+
13+ bool CFrontendIR::CEmitter::invalid (const SInvalidCheckArgs& args) const
14+ {
15+ // not checking validty of profile because invalid means no emission profile
16+ // check for NaN and non invertible matrix
17+ if (profile && !(hlsl::determinant (profileTransform)>hlsl::numeric_limits<hlsl::float32_t >::min))
18+ {
19+ args.logger .log (" Emission Profile's Transform is not an invertible matrix!" );
20+ return true ;
21+ }
22+ return false ;
23+ }
24+
25+ bool CFrontendIR::CBeer::invalid (const SInvalidCheckArgs& args) const
26+ {
27+ if (!args.pool ->deref (perpTransparency))
28+ {
29+ args.logger .log (" Perpendicular Transparency node of correct type must be attached, but is %u of type %s" ,ELL_ERROR,perpTransparency,args.pool ->getTypeName (perpTransparency).data ());
30+ return true ;
31+ }
32+ return false ;
33+ }
34+
35+ bool CFrontendIR::CFresnel::invalid (const SInvalidCheckArgs& args) const
36+ {
37+ if (!args.pool ->deref (orientedRealEta))
38+ {
39+ args.logger .log (" Oriented Real Eta node of correct type must be attached, but is %u of type %s" ,ELL_ERROR,orientedRealEta,args.pool ->getTypeName (orientedRealEta).data ());
40+ return true ;
41+ }
42+ if (!args.pool ->deref (orientedImagEta))
43+ {
44+ args.logger .log (" Oriented Imaginary Eta node of correct type must be attached, but is %u of type %s" ,ELL_ERROR,orientedImagEta,args.pool ->getTypeName (orientedImagEta).data ());
45+ return true ;
46+ }
47+ return false ;
48+ }
49+
50+ bool CFrontendIR::COrenNayar::invalid (const SInvalidCheckArgs& args) const
51+ {
52+ if (!ndParams)
53+ {
54+ args.logger .log (" Normal Distribution Parameters are invalid" ,ELL_ERROR);
55+ return true ;
56+ }
57+ return false ;
58+ }
59+
60+ bool CFrontendIR::CCookTorrance::invalid (const SInvalidCheckArgs& args) const
61+ {
62+ if (!ndParams)
63+ {
64+ args.logger .log (" Normal Distribution Parameters are invalid" ,ELL_ERROR);
65+ return true ;
66+ }
67+ if (args.isBTDF && !args.pool ->deref (orientedRealEta))
68+ {
69+ args.logger .log (" Cook Torrance BTDF requires the Index of Refraction to compute the refraction direction, but is %u of type %s" ,ELL_ERROR,orientedRealEta,args.pool ->getTypeName (orientedRealEta).data ());
70+ return true ;
71+ }
72+ return false ;
73+ }
74+
75+
76+ auto CFrontendIR::reciprocate (const TypedHandle<const IExprNode> other) -> TypedHandle<IExprNode>
77+ {
78+ assert (false ); // unimplemented
79+ return {};
80+ }
81+
82+ void CFrontendIR::printDotGraph (std::ostringstream& str) const
83+ {
84+ str << " digraph {\n " ;
85+
86+ // TODO: track layering depth and indent accordingly?
87+ // assign in reverse because we want materials to print in order
88+ core::vector<TypedHandle<const CLayer>> layerStack (m_rootNodes.rbegin (),m_rootNodes.rend ());
89+ core::stack<TypedHandle<const IExprNode>> exprStack;
90+ while (!layerStack.empty ())
91+ {
92+ const auto layerHandle = layerStack.back ();
93+ layerStack.pop_back ();
94+ const auto * layerNode = deref (layerHandle);
95+ //
96+ const auto layerID = getNodeID (layerHandle);
97+ str << " \n\t " << getLabelledNodeID (layerHandle);
98+ //
99+ if (layerNode->coated )
100+ {
101+ str << " \n\t " << layerID << " -> " << getNodeID (layerNode->coated ) << " [label=\" coats\" ]\n " ;
102+ layerStack.push_back (layerNode->coated );
103+ }
104+ auto pushExprRoot = [&](const TypedHandle<const IExprNode> root, const std::string_view edgeLabel)->void
105+ {
106+ if (!root)
107+ return ;
108+ str << " \n\t " << layerID << " -> " << getNodeID (root) << " [label=\" " << edgeLabel << " \" ]" ;
109+ exprStack.push (root);
110+ };
111+ pushExprRoot (layerNode->brdfTop ," Top BRDF" );
112+ pushExprRoot (layerNode->btdf ," BTDF" );
113+ pushExprRoot (layerNode->brdfBottom ," Bottom BRDF" );
114+ while (!exprStack.empty ())
115+ {
116+ const auto entry = exprStack.top ();
117+ exprStack.pop ();
118+ const auto nodeID = getNodeID (entry);
119+ str << " \n\t " << getLabelledNodeID (entry);
120+ const auto * node = deref (entry);
121+ const auto childCount = node->getChildCount ();
122+ if (childCount)
123+ {
124+ str << " \n\t " << nodeID << " -> {" ;
125+ for (auto childIx=0 ; childIx<childCount; childIx++)
126+ {
127+ const auto childHandle = node->getChildHandle (childIx);
128+ if (const auto child=deref (childHandle); child)
129+ {
130+ str << getNodeID (childHandle) << " " ;
131+ exprStack.push (childHandle);
132+ }
133+ }
134+ str << " }\n " ;
135+ }
136+ // special printing
137+ node->printDot (str,nodeID);
138+ }
139+ }
140+
141+ // TODO: print image views
142+
143+ str << " \n }\n " ;
144+ }
145+
146+ void CFrontendIR::SParameter::printDot (std::ostringstream& sstr, const core::string& selfID) const
147+ {
148+ sstr << " \n\t " << selfID << " [label=\" scale = " << std::to_string (scale);
149+ if (view)
150+ {
151+ sstr << " \\ nchannel = " << std::to_string (viewChannel);
152+ const auto & viewParams = view->getCreationParameters ();
153+ sstr << " \\ nWraps = {" << sampler.TextureWrapU ;
154+ if (viewParams.viewType !=ICPUImageView::ET_1D && viewParams.viewType !=ICPUImageView::ET_1D_ARRAY)
155+ sstr << " ," << sampler.TextureWrapV ;
156+ if (viewParams.viewType ==ICPUImageView::ET_3D)
157+ sstr << " ," << sampler.TextureWrapW ;
158+ sstr << " }\\ nBorder = " << sampler.BorderColor ;
159+ // don't bother printing the rest, we really don't care much about those
160+ }
161+ sstr << " \" ]" ;
162+ // TODO: do specialized printing for image views (they need to be gathered into a view set -> need a printing context struct)
163+ /*
164+ struct SDotPrintContext
165+ {
166+ std::ostringstream* sstr;
167+ core::unordered_map<ICPUImageView*,core::blake3_hash>* usedViews;
168+ uint16_t indentation = 0;
169+ };
170+ */
171+ if (view)
172+ sstr << " \n\t " << selfID << " -> _view_" << std::to_string (reinterpret_cast <const uint64_t &>(view));
173+ }
174+
175+ core::string CFrontendIR::CSpectralVariable::getLabelSuffix () const
176+ {
177+ if (getKnotCount ()<2 )
178+ return " " ;
179+ constexpr const char * SemanticNames[] =
180+ {
181+ " \\ nSemantics = Fixed3_SRGB" ,
182+ " \\ nSemantics = Fixed3_DCI_P3" ,
183+ " \\ nSemantics = Fixed3_BT2020" ,
184+ " \\ nSemantics = Fixed3_AdobeRGB" ,
185+ " \\ nSemantics = Fixed3_AcesCG"
186+ };
187+ auto pWonky = reinterpret_cast <const SCreationParams<2 >*>(this +1 );
188+ return SemanticNames[static_cast <uint8_t >(pWonky->getSemantics ())];
189+ }
190+ void CFrontendIR::CSpectralVariable::printDot (std::ostringstream& sstr, const core::string& selfID) const
191+ {
192+ auto pWonky = reinterpret_cast <const SCreationParams<1 >*>(this +1 );
193+ pWonky->knots .printDot (getKnotCount (),sstr,selfID);
194+ }
195+
196+ void CFrontendIR::CEmitter::printDot (std::ostringstream& sstr, const core::string& selfID) const
197+ {
198+ if (profile)
199+ profile.printDot (sstr,selfID);
200+ if (profile.view )
201+ {
202+ const auto transformNodeID = selfID+" _pTform" ;
203+ sstr << " \n\t " << transformNodeID << " [label=\" " ;
204+ printMatrix (sstr,profileTransform);
205+ sstr << " \" ]" ;
206+ // connect up
207+ sstr << " \n\t " << selfID << " -> " << transformNodeID << " [label=\" Profile Transform\" ]" ;
208+ }
209+ }
210+
211+ void CFrontendIR::CFresnel::printDot (std::ostringstream& sstr, const core::string& selfID) const
212+ {
213+ }
214+
215+ void CFrontendIR::IBxDF::SBasicNDFParams::printDot (std::ostringstream& sstr, const core::string& selfID) const
216+ {
217+ constexpr const char * paramSemantics[] = {
218+ " dh/du" ,
219+ " dh/dv" ,
220+ " alpha_u" ,
221+ " alpha_v"
222+ };
223+ SParameterSet<4 >::printDot (sstr,selfID,paramSemantics);
224+ if (hlsl::determinant (reference)>0 .f )
225+ {
226+ const auto referenceID = selfID+" _reference" ;
227+ sstr << " \n\t " << referenceID << " [label=\" " ;
228+ printMatrix (sstr,reference);
229+ sstr << " \" ]" ;
230+ sstr << " \n\t " << selfID << " -> " << referenceID << " [label=\" Stretch Reference\" ]" ;
231+ }
232+ }
233+
234+ void CFrontendIR::COrenNayar::printDot (std::ostringstream& sstr, const core::string& selfID) const
235+ {
236+ ndParams.printDot (sstr,selfID);
237+ }
238+
239+ void CFrontendIR::CCookTorrance::printDot (std::ostringstream& sstr, const core::string& selfID) const
240+ {
241+ ndParams.printDot (sstr,selfID);
242+ }
243+
244+ }
0 commit comments