Untitled

mail@pastecode.io avatar
unknown
plain_text
a year ago
3.2 kB
2
Indexable
Never
// Factory.hpp
#include <string>
#include <memory>
#include <map>
#include <functional>
#include <dlfcn.h>

namespace RayTracer {
    class Factory {
        public:
            Factory();
            ~Factory();
            void loadAllPlugins();
            void loadPlugin(
                std::string const &name,
                std::string const &path
            );
            void unloadPlugin(std::string const &name);
            void unloadAllPlugins();
            template<typename T, typename... Args>
            std::unique_ptr<T> createPlugin(
                std::string const &name,
                Args... args
            );

        private:
            std::map<std::string, void*> pluginHandles;
            std::map<std::string, std::function<void*(Args...)>> pluginConstructors;
    };
}

// Factory.cpp
#include "Factory.hpp"

RayTracer::Factory::Factory()
{
    this->loadAllPlugins();
}

RayTracer::Factory::~Factory()
{
    unloadAllPlugins();
}

void RayTracer::Factory::loadAllPlugins()
{
    // Lights
    this->loadPlugin("DirectionalLight", "./lights/DirectionalLight.so");

    // Math
    this->loadPlugin("Vector3D", "./math/Vector3D.so");
    this->loadPlugin("Point3D", "./math/Point3D.so");

    // Primitives
    this->loadPlugin("Rectangle3D", "./primitives/Rectangle3D.so");
    this->loadPlugin("Sphere", "./primitives/Sphere.so");

    // Render
    this->loadPlugin("Color", "./render/Color.so");

    // View
    this->loadPlugin("Camera", "./view/Camera.so");
    this->loadPlugin("Ray", "./view/Ray.so");
}

void RayTracer::Factory::loadPlugin(
    std::string const &name,
    std::string const &path
)
{
    void *pluginHandle = dlopen(path.c_str(), RTLD_NOW);
    if (!pluginHandle) {
        throw std::runtime_error("Failed to load plugin: " + name + " at path: " + path);
    }
    
    void *constructorPtr = dlsym(pluginHandle, ("create_" + name).c_str());
    if (!constructorPtr) {
        dlclose(pluginHandle);
        throw std::runtime_error("Failed to find constructor for plugin: " + name);
    }

    pluginHandles[name] = pluginHandle;
    pluginConstructors[name] = reinterpret_cast<std::function<void*(Args...)>>(constructorPtr);
}

void RayTracer::Factory::unloadPlugin(std::string const &name)
{
    auto it = pluginHandles.find(name);
    if (it != pluginHandles.end()) {
        dlclose(it->second);
        pluginHandles.erase(it);
        pluginConstructors.erase(name);
    }
}

void RayTracer::Factory::unloadAllPlugins()
{
    for (auto &pair : pluginHandles) {
        dlclose(pair.second);
    }
    pluginHandles.clear();
    pluginConstructors.clear();
}

template<typename T, typename... Args>
std::unique_ptr<T> RayTracer::Factory::createPlugin(
    std::string const &name,
    Args... args
)
{
    auto it = pluginConstructors.find(name);
    if (it == pluginConstructors.end()) {
        throw std::runtime_error("Plugin not found: " + name);
    }

    auto constructorFunc = it->second;
    return std::unique_ptr<T>(reinterpret_cast<T*>(constructorFunc(args...)));
}