Skip to content

File ShaderController.cpp

File List > controllers > ShaderController.cpp

Go to the documentation of this file

#include "ShaderController.h"
#include "events/ShaderEvents.h"
#include "events/MaterialEvents.h"

#include "Shaders.h"

#include <algorithm>
void UpdateMaterial(Shaders* shader, Material* mat)
{
    Shaders::ShaderUnit* active_unit = shader->GetShaderUnit(FRAGMENT_SHADER);
    if (!active_unit->sh_struct.has_value())
        return;

    ShaderStruct& sh_struct = active_unit->sh_struct.value();
    for (const auto& [ptype, pdata] : mat->mat_params) {
        const auto& [dtype, dfloat, dcol, dtex] = pdata;

        if (ptype == Material::MAT_NORMAL || ptype == Material::MAT_BUMP)
            continue;  // TODO: implement in the future

        auto loc_const = std::find_if(
            sh_struct.const_list.begin(),
            sh_struct.const_list.end(),
            [ptype](const S_const& con) ->bool {
                return std::get<1>(con) == "m_" + Material::mat_uniform_name[ptype];     // e.g. Material::MAT_ALBEDO -> m_albedo
            }
        );

        auto loc_uniform = std::find_if(
            sh_struct.uniform_list.begin(),
            sh_struct.uniform_list.end(),
            [ptype](const S_U& uni) ->bool {
                return std::get<0>(uni) == "U_" + Material::mat_uniform_name[ptype];     // e.g. Material::MAT_ALBEDO -> m_albedo
            }
        );

        switch (dtype)
        {
        case Material::MPARA_FLT:

            if (loc_uniform != sh_struct.uniform_list.end())
                std::get<1>(*loc_uniform) = FLOAT_PARA;
            else
                sh_struct.SetUni(FLOAT_PARA, 1, "U_" + Material::mat_uniform_name[ptype]);

            if (loc_const != sh_struct.const_list.end())
                *loc_const = ShaderLib::v_material[ptype];
            else
                sh_struct.const_list.emplace_back(ShaderLib::v_material[ptype]);

            break;
        case Material::MPARA_COL:

            if (loc_uniform != sh_struct.uniform_list.end())
                std::get<1>(*loc_uniform) = VEC3_PARA;
            else
                sh_struct.SetUni(VEC3_PARA, 1, "U_" + Material::mat_uniform_name[ptype]);

            if (loc_const != sh_struct.const_list.end())
                *loc_const = ShaderLib::v_material[ptype];
            else
                sh_struct.const_list.emplace_back(ShaderLib::v_material[ptype]);

            break;
        case Material::MPARA_TEX:

            if (loc_uniform != sh_struct.uniform_list.end())
                std::get<1>(*loc_uniform) = TEXTURE_PARA;
            else
                sh_struct.SetUni(TEXTURE_PARA, 1, "U_" + Material::mat_uniform_name[ptype]);

            if (loc_const != sh_struct.const_list.end())
                *loc_const = ShaderLib::t_material[ptype];
            else
                sh_struct.const_list.emplace_back(ShaderLib::t_material[ptype]);

            break;
        }
    }

    sh_struct.is_struct_changed = true;
    shader->is_shader_changed = true;

    shader->GenerateShader(FRAGMENT_SHADER);
    shader->RelinkShader(FRAGMENT_SHADER);
}

void ShaderController::bind(EventPool& pool)
{
    // Shader Edit

    pool.subscribe<ShaderCodeCompileEvent>([this, &pool](ShaderCodeCompileEvent e) {
        e.shader->ParseShaderCode(e.code, e.type);
        e.shader->RelinkShader(e.type);

        pool.emit<ShaderChangedEvent>({ e.shader, e.type });
        });

    pool.subscribe<ShaderStructCompileEvent>([this, &pool](ShaderStructCompileEvent e) {
        e.shader->GenerateShader(e.type);
        e.shader->RelinkShader(e.type);

        pool.emit<ShaderChangedEvent>({ e.shader, e.type });
        });

    pool.subscribe<ShaderStructAddArrayBufferEvent>([this](ShaderStructAddArrayBufferEvent e) {
        auto* unit = e.shader->GetShaderUnit(e.type);
        if (!unit || !unit->sh_struct.has_value()) return;
        const auto& [loc, name, type] = e.layout;
        unit->sh_struct->SetAB(loc, type, name);
        });

    pool.subscribe<ShaderStructAddPassEvent>([this](ShaderStructAddPassEvent e) {
        auto* unit = e.shader->GetShaderUnit(e.type);
        if (!unit || !unit->sh_struct.has_value()) return;
        const auto& [loc, name, type] = e.layout;
        unit->sh_struct->SetPass(loc, type, name);
        });

    pool.subscribe<ShaderStructAddInputEvent>([this](ShaderStructAddInputEvent e) {
        auto* unit = e.shader->GetShaderUnit(e.type);
        if (!unit || !unit->sh_struct.has_value()) return;
        const auto& [name, type, count] = e.input;
        unit->sh_struct->SetInp(type, count, name);
        });

    pool.subscribe<ShaderStructAddOutputEvent>([this](ShaderStructAddOutputEvent e) {
        auto* unit = e.shader->GetShaderUnit(e.type);
        if (!unit || !unit->sh_struct.has_value()) return;
        const auto& [name, type, count] = e.output;
        unit->sh_struct->SetOut(type, count, name);
        });

    pool.subscribe<ShaderStructAddUniformEvent>([this](ShaderStructAddUniformEvent e) {
        auto* unit = e.shader->GetShaderUnit(e.type);
        if (!unit || !unit->sh_struct.has_value()) return;
        const auto& [name, type, count] = e.uniform;
        unit->sh_struct->SetUni(type, count, name);
        });

    pool.subscribe<ShaderStructAddStructEvent>([this](ShaderStructAddStructEvent e) {
        auto* unit = e.shader->GetShaderUnit(e.type);
        if (!unit || !unit->sh_struct.has_value()) return;
        unit->sh_struct->DefStruct(e.name, e.args);
        });

    // Material Edit

    pool.subscribe<MaterialNameChangedEvent>([this](MaterialNameChangedEvent e) {
        if (!e.material)
            return;

        if (e.material->mat_name != e.name) {
            e.material->mat_name = e.name;
            e.material->is_mat_changed = true;
        }
        });

    pool.subscribe<MaterialFloatChangedEvent>([this](MaterialFloatChangedEvent e) {
        if (!e.material)
            return;
        if (e.data_type == Material::MPARA_FLT)
            e.material->SetMatParam(e.param_type, e.value);
        });

    pool.subscribe<MaterialColorChangedEvent>([this](MaterialColorChangedEvent e) {
        if (!e.material)
            return;
        if (e.data_type == Material::MPARA_COL)
            e.material->SetMatParam(e.param_type, e.color);
        });

    pool.subscribe<MaterialTextureNameChangedEvent>([this](MaterialTextureNameChangedEvent e) {
        if (!e.material)
            return;
        });

    pool.subscribe<MaterialTypeChangedEvent>([this, &pool](MaterialTypeChangedEvent e) {
        if (!e.material)
            return;
        e.material->SetMatParam(e.param_type, e.data_type);
        pool.emit<MaterialStructChangedEvent>({e.obj, e.material});
        });

    pool.subscribe<MaterialStructChangedEvent>([this, &pool ](MaterialStructChangedEvent e) {
        if (!e.material)
            return;
        UpdateMaterial((Shaders*)(e.obj->GetShader()), e.material);

        pool.emit<ShaderChangedEvent>({ (Shaders*)(e.obj->GetShader()), FRAGMENT_SHADER });
        });
}