Loading [MathJax]/extensions/tex2jax.js
Radium Engine  1.5.28
All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
renderparameters.cpp
1#include <catch2/catch_test_macros.hpp>
2
3#include <Core/Containers/DynamicVisitor.hpp>
4#include <Core/Containers/VariableSetEnumManagement.hpp>
5#include <Core/Types.hpp>
6#include <Core/Utils/Color.hpp>
7#include <Core/Utils/TypesUtils.hpp>
8#include <Engine/Data/RenderParameters.hpp>
9#include <Engine/Data/Texture.hpp>
10#include <Engine/RadiumEngine.hpp>
11#include <sstream>
12
13using namespace Ra::Core;
14using namespace Ra::Core::Utils;
15using namespace Ra::Engine::Data;
16
17class PrintThemAllVisitor : public DynamicVisitor
18{
19 public:
20 template <typename T>
21 void operator()( const std::string& name, const T& value ) {
22 output << "\tPrintThemAllVisitor: ( " << demangleType<T>() << " ) " << name << " --> "
23 << value << "\n";
24 }
25
26 template <typename T>
27 void allowVisit() {
28 addOperator<T>( *this );
29 }
30
31 std::stringstream output;
32};
33
34class StaticPrintVisitor
35{
36 public:
37 using customTypes = TypeList<std::string>;
38 // append custom types to the list of default BindableTypes
39 using types = RenderParameters::BindableTypes::Append<customTypes>;
40
41 StaticPrintVisitor() {
42 std::cout << "StaticPrintVisitor will iterate on " << RenderParameters::BindableTypes::Size
43 << "+" << customTypes::Size << " types.\n";
44 }
45
46 template <typename T, typename std::enable_if<!std::is_class<T>::value, bool>::type = true>
47 void operator()( const std::string& name, const T& _in, const std::string& prefix = "" ) {
48 if ( !prefix.empty() ) { output << "\t" << prefix << ": "; }
49 else { output << "\tStaticPrintVisitor: "; }
50 output << "( " << simplifiedDemangledType<T>() << " ) " << name << " --> " << _in << "\n";
51 }
52
53 template <typename T, typename std::enable_if<std::is_class<T>::value, bool>::type = true>
54 void operator()( const std::string& name,
55 [[maybe_unused]] const T& _in,
56 const std::string& prefix = "" ) {
57 if ( !prefix.empty() ) { output << "\t" << prefix << ": "; }
58 else { output << "\tStaticPrintVisitor: "; }
60 output << "( " << simplifiedDemangledType<T>() << " ) " << name << " --> " << _in
61 << "\n";
62 }
63 else { output << "( " << simplifiedDemangledType<T>() << " ) " << name << "\n"; }
64 }
65
66 void operator()( const std::string& name,
67 const RenderParameters& p,
68 const std::string& prefix = "" ) {
69 std::string localPrefix;
70 if ( prefix.empty() ) { localPrefix = "StaticPrintVisitor: "; }
71 else { localPrefix = prefix; }
72
73 output << "\t" << localPrefix << "( " << simplifiedDemangledType( p ) << " ) " << name
74 << " --> visiting recursively\n";
75 // visit the sub-parameters
76 p.visit( *this, std::string { "\t" } + localPrefix );
77
78 output << "\t" << localPrefix << "( " << simplifiedDemangledType( p ) << " ) " << name
79 << " --> end recursive visit\n";
80 }
81
82 std::stringstream output;
83};
84
85TEST_CASE( "Engine/Data/RenderParameters", "[unittests][Engine][Engine/Data][RenderParameters]" ) {
86 using RP = RenderParameters;
87 using namespace VariableSetEnumManagement;
88
89 SECTION( "Parameter storage" ) {
90 RP p1;
91 REQUIRE( !( p1.existsVariableType<int>().has_value() ) );
92 REQUIRE( !( p1.existsVariableType<bool>().has_value() ) );
93 REQUIRE( !( p1.existsVariableType<uint>().has_value() ) );
94 REQUIRE( !( p1.existsVariableType<Scalar>().has_value() ) );
95 REQUIRE( !( p1.existsVariableType<std::vector<int>>().has_value() ) );
96 REQUIRE( !( p1.existsVariableType<std::vector<uint>>().has_value() ) );
97 REQUIRE( !( p1.existsVariableType<std::vector<Scalar>>().has_value() ) );
98 REQUIRE( !( p1.existsVariableType<Vector2>().has_value() ) );
99 REQUIRE( !( p1.existsVariableType<Vector3>().has_value() ) );
100 REQUIRE( !( p1.existsVariableType<Vector4>().has_value() ) );
101 REQUIRE( !( p1.existsVariableType<Color>().has_value() ) );
102 REQUIRE( !( p1.existsVariableType<Matrix2>().has_value() ) );
103 REQUIRE( !( p1.existsVariableType<Matrix3>().has_value() ) );
104 REQUIRE( !( p1.existsVariableType<Matrix4>().has_value() ) );
105 REQUIRE( !( p1.existsVariableType<RP::TextureInfo>().has_value() ) );
106 int i = 1;
107 uint ui = 1u;
108 Scalar s = 1_ra;
109 bool b = true;
110 std::vector is { 0, 1, 2, 3, 4 };
111 std::vector uis { 0u, 1u, 2u, 3u, 4u };
112 std::vector ss { 0_ra, 1_ra, 2_ra, 3_ra, 4_ra };
113 Vector2 vec2 { 0_ra, 1_ra };
114 Vector3 vec3 { 0_ra, 1_ra, 2_ra };
115 Vector4 vec4 { 0_ra, 1_ra, 2_ra, 4_ra };
116 Matrix2 mat2 = Matrix2::Identity();
117 Matrix3 mat3 = Matrix3::Identity();
118 Matrix4 mat4 = Matrix4::Identity();
119 Color color = Color::White();
120 Texture tex1 { { "texture1" } };
121
122 p1.setTexture( "TextureParameter", &tex1, 1 );
123 p1.setVariable( "IntParameter", i );
124 p1.setVariable( "BoolParameter", b );
125 p1.setVariable( "UIntParameter", ui );
126 p1.setVariable( "ScalarParameter", s );
127 p1.setVariable( "IntsParameter", is );
128 p1.setVariable( "UIntsParameter", uis );
129 p1.setVariable( "ScalarsParameter", ss );
130 p1.setVariable( "Vec2Parameter", vec2 );
131 p1.setVariable( "Vec3Parameter", vec3 );
132 p1.setVariable( "Vec4Parameter", vec4 );
133 p1.setVariable( "ColorParameter", color );
134 p1.setVariable( "Mat2Parameter", mat2 );
135 p1.setVariable( "Mat3Parameter", mat3 );
136 p1.setVariable( "Mat4Parameter", mat4 );
137
138 REQUIRE( p1.getAllVariables<int>().size() == 1 );
139 REQUIRE( p1.getAllVariables<bool>().size() == 1 );
140 REQUIRE( p1.getAllVariables<uint>().size() == 1 );
141 REQUIRE( p1.getAllVariables<Scalar>().size() == 1 );
142 REQUIRE( p1.getAllVariables<std::vector<int>>().size() == 1 );
143 REQUIRE( p1.getAllVariables<std::vector<uint>>().size() == 1 );
144 REQUIRE( p1.getAllVariables<std::vector<Scalar>>().size() == 1 );
145 REQUIRE( p1.getAllVariables<Vector2>().size() == 1 );
146 REQUIRE( p1.getAllVariables<Vector3>().size() == 1 );
147 REQUIRE( p1.getAllVariables<Vector4>().size() == 1 );
148 REQUIRE( p1.getAllVariables<Color>().size() == 1 );
149 REQUIRE( p1.getAllVariables<Matrix2>().size() == 1 );
150 REQUIRE( p1.getAllVariables<Matrix3>().size() == 1 );
151 REQUIRE( p1.getAllVariables<Matrix4>().size() == 1 );
152 REQUIRE( p1.getAllVariables<RP::TextureInfo>().size() == 1 );
153
154 REQUIRE( p1.getAllVariables<int>().at( "IntParameter" ) == i );
155 REQUIRE( p1.getAllVariables<bool>().at( "BoolParameter" ) == b );
156 REQUIRE( p1.getAllVariables<uint>().at( "UIntParameter" ) == ui );
157 REQUIRE( p1.getAllVariables<Scalar>().at( "ScalarParameter" ) == s );
158 REQUIRE( p1.getAllVariables<std::vector<int>>().at( "IntsParameter" ) == is );
159 REQUIRE( p1.getAllVariables<std::vector<uint>>().at( "UIntsParameter" ) == uis );
160 REQUIRE( p1.getAllVariables<std::vector<Scalar>>().at( "ScalarsParameter" ) == ss );
161 REQUIRE( p1.getAllVariables<Vector2>().at( "Vec2Parameter" ) == vec2 );
162 REQUIRE( p1.getAllVariables<Vector3>().at( "Vec3Parameter" ) == vec3 );
163 REQUIRE( p1.getAllVariables<Vector4>().at( "Vec4Parameter" ) == vec4 );
164 REQUIRE( p1.getAllVariables<Color>().at( "ColorParameter" ) == color );
165 REQUIRE( p1.getAllVariables<Matrix2>().at( "Mat2Parameter" ) == mat2 );
166 REQUIRE( p1.getAllVariables<Matrix3>().at( "Mat3Parameter" ) == mat3 );
167 REQUIRE( p1.getAllVariables<Matrix4>().at( "Mat4Parameter" ) == mat4 );
168 REQUIRE( p1.getAllVariables<RP::TextureInfo>().at( "TextureParameter" ).first == &tex1 );
169 REQUIRE( p1.getAllVariables<RP::TextureInfo>().at( "TextureParameter" ).second == 1 );
170
171 StaticPrintVisitor vstr;
172 p1.visit( vstr, "p1 parameter set" );
173
174 std::cout << vstr.output.str();
175
176 RP p2;
177 p2.setVariable( "IntParameter", i + 1 );
178 p2.setVariable( "BoolParameter", !b );
179 p2.setVariable( "UIntParameter", ui + 1 );
180 p2.setVariable( "ScalarParameter", s + 1_ra );
181 is.push_back( 0 );
182 p2.setVariable( "IntsParameter", is );
183 uis.push_back( 0u );
184 p2.setVariable( "UIntsParameter", uis );
185 ss.push_back( 0_ra );
186 p2.setVariable( "ScalarsParameter", ss );
187 p2.setVariable( "Vec2Parameter", Vector2 { vec2 + Vector2 { 1_ra, 1_ra } } );
188 p2.setVariable( "Vec3Parameter", Vector3 { vec3 + Vector3 { 1_ra, 1_ra, 1_ra } } );
189 p2.setVariable( "Vec4Parameter", Vector4 { vec4 + Vector4 { 1_ra, 1_ra, 1_ra, 1_ra } } );
190 p2.setVariable( "ColorParameter", Color::Red() );
191 Texture tex2 { { "texture2" } };
192 p2.setTexture( "TextureParameter", &tex2, 2 );
193 p2.setVariable( "Foo", 42 );
194
195 // add a int parameter to p1
196 p1.setVariable( "Bar", 43 );
197
198 RP kept = p1;
199 kept.mergeKeepVariables( p2 );
200
201 // existings parameters are note changes (p1's values)
202 REQUIRE( kept.getAllVariables<int>().at( "IntParameter" ) ==
203 p1.getAllVariables<int>().at( "IntParameter" ) );
204 REQUIRE( kept.getAllVariables<bool>().at( "BoolParameter" ) ==
205 p1.getAllVariables<bool>().at( "BoolParameter" ) );
206 REQUIRE( kept.getAllVariables<uint>().at( "UIntParameter" ) ==
207 p1.getAllVariables<uint>().at( "UIntParameter" ) );
208 REQUIRE( kept.getAllVariables<Scalar>().at( "ScalarParameter" ) ==
209 p1.getAllVariables<Scalar>().at( "ScalarParameter" ) );
210 REQUIRE( kept.getAllVariables<std::vector<int>>().at( "IntsParameter" ) ==
211 p1.getAllVariables<std::vector<int>>().at( "IntsParameter" ) );
212 REQUIRE( kept.getAllVariables<std::vector<uint>>().at( "UIntsParameter" ) ==
213 p1.getAllVariables<std::vector<uint>>().at( "UIntsParameter" ) );
214 REQUIRE( kept.getAllVariables<std::vector<Scalar>>().at( "ScalarsParameter" ) ==
215 p1.getAllVariables<std::vector<Scalar>>().at( "ScalarsParameter" ) );
216 REQUIRE( kept.getAllVariables<Vector2>().at( "Vec2Parameter" ) ==
217 p1.getAllVariables<Vector2>().at( "Vec2Parameter" ) );
218 REQUIRE( kept.getAllVariables<Vector3>().at( "Vec3Parameter" ) ==
219 p1.getAllVariables<Vector3>().at( "Vec3Parameter" ) );
220 REQUIRE( kept.getAllVariables<Vector4>().at( "Vec4Parameter" ) ==
221 p1.getAllVariables<Vector4>().at( "Vec4Parameter" ) );
222 REQUIRE( kept.getAllVariables<Color>().at( "ColorParameter" ) ==
223 p1.getAllVariables<Color>().at( "ColorParameter" ) );
224 REQUIRE( kept.getAllVariables<RP::TextureInfo>().at( "TextureParameter" ) ==
225 p1.getAllVariables<RP::TextureInfo>().at( "TextureParameter" ) );
226 // Foo is p2's value
227 REQUIRE( kept.getAllVariables<int>().at( "Foo" ) == p2.getAllVariables<int>().at( "Foo" ) );
228
229 // Bar is on p1 side only, still here
230 REQUIRE( kept.getAllVariables<int>().at( "Bar" ) == p1.getAllVariables<int>().at( "Bar" ) );
231
232 RP replaced = p1;
233 replaced.mergeReplaceVariables( p2 );
234 // Existings in p1 and p2, as well as new parameters are set to p2's values
235 REQUIRE( replaced.getAllVariables<int>().at( "IntParameter" ) ==
236 p2.getAllVariables<int>().at( "IntParameter" ) );
237 REQUIRE( replaced.getAllVariables<bool>().at( "BoolParameter" ) ==
238 p2.getAllVariables<bool>().at( "BoolParameter" ) );
239 REQUIRE( replaced.getAllVariables<uint>().at( "UIntParameter" ) ==
240 p2.getAllVariables<uint>().at( "UIntParameter" ) );
241 REQUIRE( replaced.getAllVariables<Scalar>().at( "ScalarParameter" ) ==
242 p2.getAllVariables<Scalar>().at( "ScalarParameter" ) );
243 REQUIRE( replaced.getAllVariables<std::vector<int>>().at( "IntsParameter" ) ==
244 p2.getAllVariables<std::vector<int>>().at( "IntsParameter" ) );
245 REQUIRE( replaced.getAllVariables<std::vector<uint>>().at( "UIntsParameter" ) ==
246 p2.getAllVariables<std::vector<uint>>().at( "UIntsParameter" ) );
247 REQUIRE( replaced.getAllVariables<std::vector<Scalar>>().at( "ScalarsParameter" ) ==
248 p2.getAllVariables<std::vector<Scalar>>().at( "ScalarsParameter" ) );
249 REQUIRE( replaced.getAllVariables<Vector2>().at( "Vec2Parameter" ) ==
250 p2.getAllVariables<Vector2>().at( "Vec2Parameter" ) );
251 REQUIRE( replaced.getAllVariables<Vector3>().at( "Vec3Parameter" ) ==
252 p2.getAllVariables<Vector3>().at( "Vec3Parameter" ) );
253 REQUIRE( replaced.getAllVariables<Vector4>().at( "Vec4Parameter" ) ==
254 p2.getAllVariables<Vector4>().at( "Vec4Parameter" ) );
255 REQUIRE( replaced.getAllVariables<Color>().at( "ColorParameter" ) ==
256 p2.getAllVariables<Color>().at( "ColorParameter" ) );
257 REQUIRE( replaced.getAllVariables<int>().at( "Foo" ) ==
258 p2.getAllVariables<int>().at( "Foo" ) );
259 REQUIRE( replaced.getAllVariables<RP::TextureInfo>().at( "TextureParameter" ) ==
260 p2.getAllVariables<RP::TextureInfo>().at( "TextureParameter" ) );
261 // Bar is on p1 side only and not changed
262 REQUIRE( replaced.getAllVariables<int>().at( "Bar" ) ==
263 p1.getAllVariables<int>().at( "Bar" ) );
264
265 auto removed = replaced.deleteVariable<int>( "Bar" );
266 REQUIRE( removed == true );
267 auto found = replaced.existsVariable<int>( "Bar" );
268 REQUIRE( found.has_value() == false );
269 }
270
271 SECTION( "Enum parameter" ) {
272 RP params;
273
274 enum Values : unsigned int { VALUE_0 = 10, VALUE_1 = 20, VALUE_2 = 30 };
275 using ValuesType = typename std::underlying_type_t<Values>;
276
277 enum Unregistered : int { LOW = -1, MIDDDLE = 0, HIGH = 1 };
278 using UnregisteredType = typename std::underlying_type_t<Unregistered>;
279
280 auto valuesEnumConverter = std::make_shared<EnumConverter<ValuesType>>(
282 { Values::VALUE_0, "VALUE_0" },
283 { Values::VALUE_1, "VALUE_1" },
284 { Values::VALUE_2, "VALUE_2" } } );
285
286 // Enum converter must be added and fetched using the enum underlying type
287 REQUIRE( !getEnumConverter<ValuesType>( params, "enum.semantic" ) );
288 addEnumConverter( params, "enum.semantic", valuesEnumConverter );
289 REQUIRE( getEnumConverter<ValuesType>( params, "enum.semantic" ) );
290 REQUIRE( !getEnumConverter<ValuesType>( params, "enum.unknown" ) );
291 REQUIRE( !getEnumConverter<UnregisteredType>( params, "enum.unknown" ) );
292
293 // The string value of an enum value (with the enumeration type) can be fetched from
294 // the parameters and is empty if the enum is not registered
295 REQUIRE( getEnumString( params, "enum.semantic", Values::VALUE_0 ) == "VALUE_0" );
296 REQUIRE( getEnumString( params, "enum.unknown", Unregistered::LOW ) == "" );
297
298 // Adding the enum in the parameter set using its value
299 setEnumVariable( params, "enum.semantic", Values::VALUE_0 );
300
301 // checking its seen with its type (enum)
302 auto& v = getEnumVariable<Values>( params, "enum.semantic" );
303
304 REQUIRE( v == Values::VALUE_0 );
305
306 // The string value of an enum value (with the enumeration's underlying type) can also be
307 // fetched from the parameters
308 REQUIRE( getEnumString( params, "enum.semantic", v ) == "VALUE_0" );
309
310 // changing the value trough setParameter and string representation
311 setEnumVariable( params, "enum.semantic", "VALUE_2" );
312 REQUIRE( v == Values::VALUE_2 );
313
314 // variable managed with enum method could also be access directly thru underlying type
315 auto& vv = params.getVariable<ValuesType>( "enum.semantic" );
316 REQUIRE( vv == v );
317 REQUIRE( vv == Values::VALUE_2 );
318 params.setVariable( "enum.semantic", ValuesType { Values::VALUE_0 } );
319 REQUIRE( vv == v );
320 REQUIRE( vv == Values::VALUE_0 );
321
322 // unregistered enum could be added only using their value
323 setEnumVariable( params, "enum.unknown", Unregistered::LOW );
324 auto u = getEnumVariable<Unregistered>( params, "enum.unknown" );
325 REQUIRE( u == Unregistered::LOW );
326 REQUIRE( getEnumString( params, "enum.unknown", u ) == "" );
327
328 // Trying to add unregistered enums values trough string does not change the stored value
329 setEnumVariable( params, "enum.unknown", "Unregistered::HIGH" );
330 u = getEnumVariable<Unregistered>( params, "enum.unknown" );
331
332 // same with management thru underlying type
333 auto uu = params.getVariable<UnregisteredType>( "enum.unknown" );
334 REQUIRE( uu == Unregistered::LOW );
335 }
336
337 SECTION( "Parameter visit" ) {
338 RP paramsToVisit;
339 enum Values : unsigned int { VALUE_0 = 10, VALUE_1 = 20, VALUE_2 = 30 };
340 using ValuesType = typename std::underlying_type<Values>::type;
341
342 auto vnc = new EnumConverter<ValuesType>( { { Values::VALUE_0, "VALUE_0" },
343 { Values::VALUE_1, "VALUE_1" },
344 { Values::VALUE_2, "VALUE_2" } } );
345 auto valuesEnumConverter = std::shared_ptr<EnumConverter<ValuesType>>( vnc );
346 addEnumConverter( paramsToVisit, "enum.semantic", valuesEnumConverter );
347 setEnumVariable( paramsToVisit, "enum.semantic", "VALUE_0" );
348 paramsToVisit.setVariable( "int.simple", int( 1 ) );
349
350 PrintThemAllVisitor ptm;
351 ptm.allowVisit<ValuesType>();
352 ptm.allowVisit<int>();
353 std::cout << "Visiting with custom dynamic visitor:\n";
354 paramsToVisit.visit( ptm );
355 // visiting order is system dependent, compares output ignoring output order.
356 {
358 for ( std::string line; std::getline( ptm.output, line, '\n' ); )
359 outputSet.insert( line );
361 expected.insert( "\tPrintThemAllVisitor: ( int ) int.simple --> 1" );
362 expected.insert( "\tPrintThemAllVisitor: ( unsigned int ) enum.semantic --> 10" );
363 REQUIRE( outputSet == expected );
364 }
365 StaticPrintVisitor vstr;
366 std::cout << "Visiting with custom static visitor:\n";
367 paramsToVisit.visit( vstr );
368
369 std::stringstream().swap( vstr.output ); // clear output
370
371 std::cout << "Visiting with custom static visitor and hierarchical parameters:\n";
372 RP subParams;
373 subParams.setVariable( "sub.int", 3 );
374 subParams.setVariable( "sub.string", std::string { "SubString" } );
375 addEnumConverter( subParams, "enum.semantic", valuesEnumConverter );
376 setEnumVariable( subParams, "enum.semantic", "VALUE_1" );
377 paramsToVisit.setVariable( "SubParameter", subParams );
378 paramsToVisit.visit( vstr, "Visiting with subparameters" );
379
380 {
382 for ( std::string line; std::getline( vstr.output, line, '\n' ); )
383 outputSet.insert( line );
385
386 expected.insert(
387 "\t\tVisiting with subparameters: ( basic_string<char, char_traits<char>, "
388 "allocator<char>> ) sub.string --> SubString" );
389 expected.insert( "\t\tVisiting with subparameters: ( int ) sub.int --> 3" );
390 expected.insert(
391 "\t\tVisiting with subparameters: ( unsigned int ) enum.semantic --> 20" );
392 expected.insert( "\tVisiting with subparameters( Ra::Engine::Data::RenderParameters ) "
393 "SubParameter --> end recursive visit" );
394 expected.insert( "\tVisiting with subparameters( Ra::Engine::Data::RenderParameters ) "
395 "SubParameter --> visiting recursively" );
396 expected.insert( "\tVisiting with subparameters: ( int ) int.simple --> 1" );
397 expected.insert(
398 "\tVisiting with subparameters: ( unsigned int ) enum.semantic --> 10" );
399
400 std::cerr << "------------------\n";
401 for ( const auto& s : outputSet )
402 std::cerr << s << "\n";
403 std::cerr << "------------------\n";
404 for ( const auto& s : expected )
405 std::cerr << s << "\n";
406 std::cerr << "------------------\n";
407
408 REQUIRE( outputSet == expected );
409 }
410 }
411}
T at(T... args)
Base class for visitors with configurable per-type callbacks. Visiting will be prepared at running ti...
bool addOperator(F &&f)
Add a visiting operator.
This class manage the bijective association between string and integral representation of an enumerat...
void visit(F &&visitor) const
Visit the container using a user defined visitor.
Management of shader parameters with automatic binding of a named parameter to the corresponding glsl...
Represent a Texture of the engine.
Definition Texture.hpp:120
T getline(T... args)
T insert(T... args)
T make_shared(T... args)
This namespace contains everything "low level", related to data, datastuctures, and computation.
Definition Cage.cpp:5
(GPU) Data representation, along with manager
T size(T... args)
T str(T... args)
T swap(T... args)