I have a rendering architecture utilizing the following structure:
Model
: base level objectAssembly:
containsstd::vector<std::shared_ptr<Model>>
as well asstd::vector<std::shared_ptr<Assembly>>
(that is, it can contain models or subassemblies, which intern can contain subassemblies, etc.)Universe
: Top level; containsstd::vector<std::shared_ptr<Model>>
as well asstd::vector<std::shared_ptr<Assembly>>
. (Universe
is treated as separate from anAssembly
because it manages many other things as well)
I need to be able to loop over every model, which can be contained either in the Universe
directly, or in an Assembly
(possibly nested in several "sub" assemblies). What would be a convenient way of doing this? Inside of the Universe I need something like this:
for (auto& model : models) {
...
}
for (auto& assembly : assemblies) {
for (auto& model : assembly->models) {
...
}
// Recurse into potentially nested assemblies?
...
}
I need the Universe to be able to access the data in each model, preferably without copying it. I was thinking of implementing some method within the Assembly
class that can be called recursively, but I’m not sure how to then propagate that up to the Universe
such that it can do what is required (which is things like obtaining the geometry data stored in the Model to build ray tracing acceleration structure, to rasterize, etc.)
How might I do this? Or how could I restructure things to get the behavior that is desired?
>Solution :
Use a recursive function. Take another function as a parameter, and call it for every model.
I’ve simplified your class structure for the demo a bit, but the idea should be the same.
#include <functional>
#include <iostream>
struct Model
{
std::string model_name;
};
struct Assembly
{
std::vector<Model> models;
std::vector<Assembly> assemblies;
void ForEachModel(const std::function<void(Model &model)> &func)
{
for (Model &model : models)
func(model);
for (Assembly &assembly : assemblies)
assembly.ForEachModel(func);
}
};
int main()
{
Assembly a{
.models = {{"a"}, {"b"}},
.assemblies = {
{.models = {{"c"}, {"d"}}},
{
.models = {{"e"}, {"f"}},
.assemblies = {
{.models = {{"g"}, {"h"}}},
{.models = {{"i"}, {"j"}}},
},
},
},
};
a.ForEachModel([](Model &m){std::cout << m.model_name << '\n';});
}