Skip to content

File ShaderParser.cpp

File List > render > ShaderParser.cpp

Go to the documentation of this file

#include "shaders/RenderShader.h"
#include "ShaderLib.h"
#include "structs.h"
#include "macros.h"

void RenderShader::ParseShaderStream(std::istream& _stream, ShaderType _type)
{
    ShaderUnit* shader = GetShaderUnit(_type);

    std::string Line;
    std::string cache = "";
    Args args_cache;

    while (getline(_stream, Line)) {


        // PARSING
        //shaders[type] << Line << "\n";
        if (Line == "") {
        }
        else if (Line.find("#version") != std::string::npos) {
            // [Version]
            shader->sh_struct->version = std::atoi(Line.substr(9, 3).c_str());
        }
        else if (Line.find("layout") != std::string::npos) {
            // [layout]
            int layout = std::atoi(Line.substr(18, Line.find(")") - 18).c_str());
            if (Line.find("in ") != std::string::npos) {
                std::istringstream str(Line);
                std::string word;
                str >> word;
                str >> word;
                str >> word;
                str >> word;
                str >> word;
                ParaType paratype = ShaderStruct::ParseType(word);
                str >> word;

                std::erase(word, ';'); // var name
                shader->sh_struct->SetAB(layout, paratype, word);
            }
            else if (Line.find("out ") != std::string::npos) {
                std::istringstream str(Line);
                std::string word;
                str >> word;
                str >> word;
                str >> word;
                str >> word;
                str >> word;
                ParaType paratype = ShaderStruct::ParseType(word);
                str >> word;

                std::erase(word, ';'); // var name
                shader->sh_struct->SetPass(layout, paratype, word);
            }
            else if (Line.find("buffer ") != std::string::npos) {
                layout = std::atoi(Line.substr(25, 1).c_str());
                std::istringstream str(Line);
                std::string name;
                LOOP(6)
                    str >> name;

                while (Line != "};") {
                    getline(_stream, Line);

                    if (Line == "};") break;

                    std::istringstream str(Line);
                    std::string word;
                    str >> word;

                    ParaType paratype = ShaderStruct::ParseType(word);
                    str >> word;

                    std::erase(word, ';'); // var name
                    args_cache.emplace_back(paratype, word);
                };

                shader->sh_struct->SetSB(layout, name, args_cache);

                args_cache = {};
            }
            else if (Line.find("uniform ") != std::string::npos) {
                size_t start = Line.find("uniform ") + 8;
                std::string type_name = Line.substr(start, Line.find(" {") - start);
                while (Line.find("}") == std::string::npos) {
                    getline(_stream, Line);

                    if (Line.find("}") != std::string::npos) break;

                    std::istringstream str(Line);
                    std::string word;
                    str >> word;

                    ParaType paratype = ShaderStruct::ParseType(word);
                    str >> word;

                    std::erase(word, ';'); // var name
                    args_cache.emplace_back(paratype, word);
                }
                start = Line.find("} ") + 2;
                std::string var_name = Line.substr(start, Line.find(";") - start);

                shader->sh_struct->SetUB(type_name, var_name, args_cache);

                args_cache = {};
            }
        }
        else if (Line.find("in ") != std::string::npos) {
            // [in]
            // it is unnecessary to parese the input, 
            // inputs are linked from the output of the vertex shader.
        }
        else if (Line.find("out ") != std::string::npos) {
            // [out]
            std::istringstream str(Line);
            std::string name;
            std::string type;
            str >> name;
            str >> type;
            str >> name;
            assert(!_is_link_repeat(name));
            ParaType para_type = ShaderStruct::ParseType(type);

            std::erase(name, ';'); // var name
            shader->sh_struct->SetOut(para_type, 1, name);
            shader_data[1 - _type].sh_struct->SetInp(para_type, 1, name);

            _LINK_LOC[name] = int(_LINK_LOC.size());
        }
        else if (Line.find("uniform") != std::string::npos) {
            // [Uniform]
            std::istringstream str(Line);
            std::string word;
            str >> word;
            str >> word;
            ParaType paratype = ShaderStruct::ParseType(word);
            str >> word;

            std::erase(word, ';'); // var name
            int count = 1;
            if (word.find("[") != std::string::npos) {
                count = std::atoi(word.substr(word.find("[") + 1, word.find("]") - word.find("[") - 1).c_str());
                word = word.substr(0, word.find("["));
                //DEBUG(word)
            }
            shader->sh_struct->SetUni(paratype, count, word);
        }
        else if (Line.find("struct") != std::string::npos) {
            // [Sturct]
            std::string name = Line.substr(7, Line.size() - 8);
            ShaderStruct::ADD_TYPE(name);
            while (Line != "};") {
                getline(_stream, Line);

                if (Line == "};") break;

                if (Line.find("//") != std::string::npos || Line == "")
                    continue;

                std::istringstream str(Line);
                std::string word;
                str >> word;
                ParaType paratype = ShaderStruct::ParseType(word);
                str >> word;

                std::erase(word, ';'); // var name
                args_cache.emplace_back(paratype, word);
            }

            shader->sh_struct->DefStruct(name, args_cache);

            args_cache = {};
        }
        else if (Line.find("const") != std::string::npos) {
            // [Const]
            std::istringstream str(Line);
            std::string word;
            str >> word;
            str >> word;
            ParaType paratype = ShaderStruct::ParseType(word);
            str >> word;

            std::erase(word, ';'); // var name
            std::string content = Line.substr(Line.find(" = ") + 3, Line.size() - Line.find(" = ") - 4);
            shader->sh_struct->SetConst(paratype, word, content);
        }
        else if (Line.find("void main") != std::string::npos) {
            int blanc_count = (Line.find("{") != std::string::npos) ? 1 : 0;
            bool skip_first_brace = (blanc_count == 0);  // Need to skip standalone { on next line
            do {
                getline(_stream, Line);
                if (Line.find("{") != std::string::npos) blanc_count++;
                if (Line.find("}") != std::string::npos) blanc_count--;
                //shaders[type] << Line << "\n";
                // Skip the opening brace line if it's standalone
                if (skip_first_brace && Line.find("{") != std::string::npos && Line.find("}") == std::string::npos) {
                    skip_first_brace = false;
                    continue;
                }
                // Don't add the closing brace line to Main (GenerateShader will add it)
                if (blanc_count != 0) {
                    shader->sh_struct->Main += Line + "\n";
                }

            } while (blanc_count != 0);
        }
        else {
            std::istringstream str(Line);
            std::string word;
            str >> word;
            if (ShaderStruct::IsAvailType(word)) {
                if (Line.find("(") != std::string::npos) {
                    // [Functions]
                    size_t left_b = Line.find("(");
                    ParaType paratype = ShaderStruct::ParseType(word);
                    std::string name = Line.substr(word.size() + 1, left_b - word.size() - 1);
                    std::string args_list = Line.substr(left_b + 1, Line.find(")") - left_b - 1) + ", ";
                    //DEBUG(args_list)
                    size_t blanc_count = Line.find("{") != std::string::npos ? 1 : 0;
                    do {
                        getline(_stream, Line);
                        //shaders[type] << Line << "\n";
                        if (blanc_count != 0)
                            cache += Line + "\n";
                        if (Line.find("{") != std::string::npos) blanc_count++;
                        if (Line.find("}") != std::string::npos) blanc_count--;

                    } while (blanc_count != 0);

                    cache.erase(cache.size() - 1, 1);
                    if (cache.substr(cache.size() - 2, 2).find("}") != std::string::npos)
                        cache.erase(cache.size() - 2, 2);
                    //shader->sh_struct->Main.erase(shader->sh_struct->Main.size() - 3, 3);
                    shader->sh_struct->DefFunc(paratype, name, cache, ShaderStruct::ParseArgs(args_list));
                    cache = "";
                    args_cache = {};
                }
                else {
                    // [Glob]
                    int count = 1;
                    std::string type_name = word;
                    str >> word;
                    if (word.find("[") != std::string::npos) {
                        count = std::atoi(word.substr(word.find("[") + 1, word.find("]") - word.find("[") - 1).c_str());
                        word = word.substr(0, word.find("["));
                        //DEBUG(word)
                    }
                    else if (word.find(",") != std::string::npos) {
                        do {
                            shader->sh_struct->SetVar(type_name, word.erase(word.size() - 1, 1), count);
                        } while (str >> word);
                        shader->sh_struct->vari_list.pop_back();
                    }
                    else {
                        std::erase(word, ';'); // var name
                    }
                    shader->sh_struct->SetVar(type_name, word, count);
                }
            }
        }
    }

    shader->sh_struct->func_list_state.resize(shader->sh_struct->func_list.size());
}



std::string ShaderStruct::GenerateShader()
{
    std::string code_result;

    code_result = ""; // RESET
    code_result += "#version " + std::to_string(version) + " core\n\n";

    std::string code_block = "";
    if (AB_list.size()) {
        code_block += "// [ARRAY_BUFFER]\n";
        for (const auto& [loc, name, type] : AB_list)
            code_block += "layout(location = " + std::to_string(loc) + ") in " + ShaderStruct::ParseType(type)/* + " In_"*/ + " " + name + ";\n";
        code_block += "\n";
    }
    code_result += code_block;

    code_block = "";
    if (pass_list.size()) {
        code_block += "// [RENDER_BUFFER]\n";
        for (const auto& [loc, name, type] : pass_list)
            code_block += "layout(location = " + std::to_string(loc) + ") out " + ShaderStruct::ParseType(type)/* + " Ch_"*/ + " " + name + ";\n";
        code_block += "\n";
    }
    code_result += code_block;

    code_block = "";
    if (struct_def_list.size()) {
        code_block += "// [STRUCTURE_DEFINE]\n";
        for (const auto& [_, sname, args] : struct_def_list) {
            code_block += "struct " + sname + "{\n";
            for (const auto& [type, name] : args) {
                code_block += "\t" + ShaderStruct::ParseType(type) + " " + name + ";\n";
            }
            code_block += "};\n\n";
        }
    }
    code_result += code_block;

    code_block = "";
    if (SB_list.size()) {
        code_block += "// [STORAGE_BUFFER]\n";
        for (const auto& [loc, bname, args] : SB_list) {
            code_block += "layout(std430, binding = " + std::to_string(loc) + ") buffer " + bname + " {\n";
            for (const auto& [type, name] : args) {
                code_block += "\treadonly " + ShaderStruct::ParseType(type) + " " + name + ";\n";
            }
            code_block += "};\n";
        }
        code_block += "\n";
    }
    code_result += code_block;

    code_block = "";
    if (ubuffer_list.size()) {
        code_block += "// [UNIFORM BUFFER]\n";
        for (const auto& [_, uname, vname, args] : ubuffer_list) {
            code_block += "layout(std140) uniform " + uname + " {\n";
            for (const auto& [type, name] : args) {
                code_block += "\t" + ShaderStruct::ParseType(type) + " " + name + ";\n";
            }
            code_block += "} " + vname + ";\n";
        }
        code_block += "\n";
    }
    code_result += code_block;

    code_block = "";
    if (uniform_list.size()) {
        code_block += "// [UNIFORM]\n";
        for (const auto& [name, type, count] : uniform_list)
            code_block += "uniform " + ShaderStruct::ParseType(type) /*+ " U_" */ + " " + name + ShaderStruct::ParseCount(count) + ";\n";
        code_block += "\n";
    }
    code_result += code_block;

    code_block = "";
    if (input_list.size()) {
        code_block += "// [IN]\n";
        for (const auto& [name, type, count] : input_list)
            code_block += "in " + ShaderStruct::ParseType(type) /*+ " Out_" */ + " " + name + ShaderStruct::ParseCount(count) + ";\n";
        code_block += "\n";
    }
    code_result += code_block;

    code_block = "";
    if (output_list.size()) {
        code_block += "// [OUT]\n";
        for (const auto& [name, type, count] : output_list)
            code_block += "out " + ShaderStruct::ParseType(type) /*+ " Out_" */ + " " + name + ShaderStruct::ParseCount(count) + ";\n";
        code_block += "\n";
    }
    code_result += code_block;

    code_block = "";
    if (glob_list.size()) {
        code_block += "// [GLOBES]\n";
        for (const auto& [name, type, val] : glob_list)
            code_block += ShaderStruct::ParseType(type) /* + " Glob_"*/ + name + " = " + ShaderStruct::ParseType(type) + "(" + std::to_string(val) + ");\n";
        code_block += "\n";
    }
    code_result += code_block;

    code_block = "";
    if (const_list.size()) {
        code_block += "// [CONSTS]\n";
        for (const auto& [type, name, cont, _] : const_list)
            code_block += "const " + ShaderStruct::ParseType(type) + " " + name + " = " + cont + ";\n";
        code_block += "\n";
    }
    code_result += code_block;

    code_block = "";
    if (vari_list.size()) {
        code_block += "// [VARS]\n";
        for (const auto& [tname, name, count] : vari_list)
            code_block += tname + " " + name + ShaderStruct::ParseCount(count) + ";\n";
        code_block += "\n";
    }
    code_result += code_block;

    code_block = "";
    if (func_list.size()) {
        code_block += "// [FUNCTION_DEFINE]\n";
        for (const auto& [rtype, name, cont, args] : func_list) {
            code_block += ShaderStruct::ParseType(rtype) + " " + name + ShaderStruct::ParseArgs(args) + "{\n";
            code_block += cont;
            code_block += "\n}\n\n";
        }
    }
    code_result += code_block;

    code_result += "\nvoid main(){\n";
    code_result += Main;
    code_result += "\n}\n";

    return code_result;
}