File ShaderEditor.cpp
File List > layer > ShaderEditor.cpp
Go to the documentation of this file
#include "ShaderEditor.h"
#include "Shaders.h"
#include "Input.h"
#include "operator.h"
#include "events/KeyMouseEvents.h"
#include "events/EditorEvents.h"
#include "events/ShaderEvents.h"
const std::string edit_mode[3] = { "Code", "Structure", "Nodes" };
ShaderEditor::ShaderEditor()
:ShaderEditor("Shader Editor")
{}
ShaderEditor::ShaderEditor(const std::string& name)
{
uly_name = name;
se_code_editor.Init();
se_node_editor = NodeEditor(SHADER_NODE_EDITOR);
}
ShaderEditor::~ShaderEditor()
{
}
static Args prop_args;
static S_U add_prop;
static S_func add_args;
static char prop_name[CHAR_MAX] = {};
static char prop_content[CHAR_MAX] = {};
/* Rendering Utils */
bool RenderPanel(ShaderEditor::MiniPropPanel& panel, const ImVec2& pos, S_U* out, const char* c_name, const char* c_sld_name)
{
if (!panel.is_open) {
panel.panel_pos = pos;
panel.is_open = true;
}
ImGui::SetNextWindowPos(ImGui::GetWindowPos() + panel.panel_pos - ImVec2(100, 0));
ImGui::SetNextWindowSize(ImVec2(300, 80));
bool a = false, b = false;
if (ImGui::Begin("ADD", nullptr, ImGuiWindowFlags_NoDocking | ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoScrollbar)) {
a = ImGui::IsWindowFocused();
ImGui::SetNextItemWidth(100);
if (ImGui::BeginCombo(" ", ShaderStruct::type_table[panel.datatype].c_str())) {
b = true;
LOOP(ShaderStruct::type_table.size())
if (ImGui::Selectable(ShaderStruct::type_table[i].c_str(), &a))
panel.datatype = i;
ImGui::EndCombo();
}ImGui::SameLine();
if ((!a) && (!b))
{
ImGui::End();
panel.is_open = false;
return false;
}
ImGui::InputTextMultiline(c_name, prop_name, CHAR_MAX, ImVec2(ImGui::GetContentRegionAvail().x, 20));
ImGui::InputInt(c_sld_name, &panel.prop_count);
if (ImGui::Button("OK", ImGui::GetContentRegionAvail())) {
panel.is_open = false;
ImGui::End();
if (prop_name[0] == '\0')
return false;
*out = { std::string(prop_name), ParaType(panel.datatype), panel.prop_count };
prop_name[0] = '\0';
return true;
}
ImGui::End();
}
return false;
}
void RenderArguPanel(bool* b)
{
int index = 0;
for (auto& arg : prop_args) {
char name[CHAR_MAX];
std::string b_name = std::get<1>(arg);
b_name.copy(name, b_name.size());
*(name + b_name.size()) = '\0';
int type = std::get<0>(arg);
bool a;
ImGui::SetNextItemWidth(100);
if (ImGui::BeginCombo(("member" + std::to_string(index)).c_str(), ShaderStruct::type_table[type].c_str())) {
*b = true;
LOOP(ShaderStruct::type_table.size())
if (ImGui::Selectable(ShaderStruct::type_table[i].c_str(), &a))
type = i;
ImGui::EndCombo();
}ImGui::SameLine();
ImGui::InputTextMultiline(("m_name" + std::to_string(index)).c_str(), name, CHAR_MAX, ImVec2(ImGui::GetContentRegionAvail().x, 20));
arg = { (ParaType)type, std::string(name) };
index++;
}
if (ImGui::Button("+", ImVec2(ImGui::GetContentRegionAvail().x, 40)))
prop_args.emplace_back(NONE_PARA, "Empty");
}
bool RenderDefPanel(ShaderEditor::MiniPropPanel& panel, bool type, const ImVec2& pos, S_func* _struct)
{
if (!panel.is_open) {
panel.panel_pos = pos;
panel.is_open = true;
}
ImGui::SetNextWindowPos(ImGui::GetWindowPos() + panel.panel_pos - ImVec2(100, 0));
ImGui::SetNextWindowSize(ImVec2(400, 300));
bool a, b = false;
if (ImGui::Begin("Add Def", nullptr, ImGuiWindowFlags_NoDocking | ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoNav)) {
if (type) {
ImGui::SetNextItemWidth(100);
if (ImGui::BeginCombo(" ", ShaderStruct::type_table[panel.datatype].c_str())) {
LOOP(ShaderStruct::type_table.size())
if (ImGui::Selectable(ShaderStruct::type_table[i].c_str(), &a))
panel.datatype = i;
ImGui::EndCombo();
}ImGui::SameLine();
}
ImGui::InputTextMultiline("name", prop_name, CHAR_MAX, ImVec2(ImGui::GetContentRegionAvail().x, 20));
RenderArguPanel(&b);
if ((!ImGui::IsWindowFocused()) && (!b)) {
panel.is_open = false;
ImGui::End();
return false;
}
if (type) {
ImGui::InputTextMultiline("content", prop_content, CHAR_MAX, ImVec2(ImGui::GetContentRegionAvail().x, 40));
}
if (ImGui::Button("OK", ImVec2(ImGui::GetContentRegionAvail().x, 50))) {
panel.is_open = false;
ImGui::End();
if (panel.datatype == 0 || prop_name[0] == '\0')
return false;
return true;
}
ImGui::End();
}
return false;
}
void RenderLayout(int* _loc, std::string* _name, ParaType* _type, char* add_name, bool* sel)
{
ImGui::SetNextItemWidth(80);
ImGui::InputInt(_name->c_str(), _loc, 1, 100, ImGuiInputTextFlags_NoName); ImGui::SameLine(); ImGui::SetNextItemWidth(60);
if (ImGui::BeginCombo(std::to_string(*_type).c_str(), ShaderStruct::ParseType((ParaType)*_type).c_str(), ImGuiComboFlags_NoName)) {
LOOP(ShaderStruct::type_table.size())
if (ImGui::Selectable(ShaderStruct::type_table[i].c_str(), sel))
*_type = (ParaType)i;
ImGui::EndCombo();
}ImGui::SameLine();
_name->copy(add_name, CHAR_MAX, 0);
*(add_name + _name->size()) = '\0'; ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x);
ImGui::InputText((*_name + "name").c_str(), add_name, CHAR_MAX, ImGuiInputTextFlags_NoName | ImGuiInputTextFlags_ReadOnly);
*_name = std::string(add_name);
}
void RenderSSBO(int* _loc, std::string* _name, ParaType* _type, Args* _args, char* add_name, bool* sel)
{
RenderLayout(_loc, _name, _type, add_name, sel);
}
void RenderArg(Arg& _arg, int _index, bool _is_editable, bool* sel)
{
char name[CHAR_MAX];
std::string b_name = _arg.second;
b_name.copy(name, b_name.size());
*(name + b_name.size()) = '\0';
ImGui::SetNextItemWidth(100);
if (ImGui::BeginCombo(std::to_string(_index).c_str(), ShaderStruct::ParseType(_arg.first).c_str(), ImGuiComboFlags_NoName)) {
LOOP(ShaderStruct::type_table.size())
if (ImGui::Selectable(ShaderStruct::type_table[i].c_str(), sel))
_arg.first = (ParaType)i;
ImGui::EndCombo();
}
ImGui::SameLine();
ImGui::InputTextMultiline(("m" + std::to_string(_index)).c_str(), name, CHAR_MAX, ImVec2(ImGui::GetContentRegionAvail().x, 20), ImGuiInputTextFlags_NoName | (!_is_editable * ImGuiInputTextFlags_ReadOnly));
_arg.second = std::string(name);
}
void RenderArg(ParaType& _type, std::string& _name, int _index, bool _is_editable, bool* sel)
{
char name[CHAR_MAX];
_name.copy(name, _name.size());
*(name + _name.size()) = '\0';
ImGui::SetNextItemWidth(100);
if (ImGui::BeginCombo(std::to_string(_index).c_str(), ShaderStruct::ParseType(_type).c_str(), ImGuiComboFlags_NoName)) {
LOOP(ShaderStruct::type_table.size())
if (ImGui::Selectable(ShaderStruct::type_table[i].c_str(), sel))
_type = (ParaType)i;
ImGui::EndCombo();
}
ImGui::SameLine();
ImGui::InputTextMultiline(("m" + std::to_string(_index)).c_str(), name, CHAR_MAX, ImVec2(ImGui::GetContentRegionAvail().x, 20), ImGuiInputTextFlags_NoName | (!_is_editable * ImGuiInputTextFlags_ReadOnly));
_name = std::string(name);
}
void RenderArgs(Args& args, int _type, bool* sel)
{
int index = 0;
for (auto& arg : args)
RenderArg(arg, index++, _type != -1, sel);
}
bool ShaderEditor::AddParam(const char* c_name /*= ""*/, const char* c_sld_name /*= ""*/)
{
if (ImGui::Button("+", ImVec2(ImGui::GetContentRegionAvail().x - 15, 20)) || se_panel.is_open) {
const ImVec2 mouse_pos = ImVec2(Input::GetMousePosX(), Input::GetMousePosY());
if (RenderPanel(se_panel, mouse_pos, &add_prop, c_name, c_sld_name)) {
return true;
}
}
return false;
}
bool ShaderEditor::AddStruct(bool def_type /*= false*/)
{
if (ImGui::Button("+", ImVec2(ImGui::GetContentRegionAvail().x - 15, 20)) || se_panel.is_open)
{
const ImVec2 mouse_pos = ImVec2(Input::GetMousePosX(), Input::GetMousePosY());
if (RenderDefPanel(se_panel, def_type, mouse_pos, &add_args)) {
return true;
}
}
return false;
}
void ShaderEditor::UpdateKeyword()
{
auto& table = ShaderStruct::type_table;
LOOP(table.size() - CUSTOM_PARA)
if (!se_code_editor.CheckKeyword(table[i + CUSTOM_PARA]))
se_code_editor.InsertKeyword(table[i + CUSTOM_PARA]);
}
static Shaders* GetActiveShaderPtr(ObjectID* active_obj)
{
if (active_obj == nullptr)
return nullptr;
return (Shaders*)(active_obj->GetShader());
}
static Shaders::ShaderUnit* GetShaderUnitPtr(Shaders* shader, ShaderType tar)
{
if (shader == nullptr) return nullptr;
return shader->GetShaderUnit(tar);
}
void ShaderEditor::RegisterEvents(EventPool& evt)
{
evt.subscribe<SelectionChangedEvent>([this](SelectionChangedEvent e) {
this->UpdateCoderEditor(e.obj);
});
evt.subscribe<ShaderChangedEvent>([this](ShaderChangedEvent e) {
Shaders::ShaderUnit* active_unit = GetShaderUnitPtr(e.shader, e.type);
if (active_unit == nullptr) return;
if (current_edit == ShaderEditor::CODE_EDITOR && current_shad_type == e.type) {
se_code_editor.SetText(active_unit->sh_code);
}
});
}
void ShaderEditor::RenderName(const std::string& _label, std::string* _name, float _width, bool read_only) const
{
RenderName((_label + *_name).c_str(), _name, _width, read_only);
}
void ShaderEditor::RenderName(const char* _label, std::string* _name, float _width, bool read_only /*= true*/) const
{
char name[CHAR_MAX];
std::string temp = *_name;
//DEBUG(_name->size())
temp.copy(name, temp.size());
*(name + temp.size()) = '\0';
ImGui::InputTextMultiline(_label, name, CHAR_MAX, ImVec2(_width == 0.0f ? ImGui::GetContentRegionAvail().x : _width, 20), ImGuiInputTextFlags_NoName | (read_only ? ImGuiInputTextFlags_ReadOnly : 0));
if (!read_only)
*_name = std::string(name);
}
void ShaderEditor::RenderShaderStruct(ObjectID* active_obj, EventPool& evt)
{
Shaders* shader = GetActiveShaderPtr(active_obj);
Shaders::ShaderUnit* active_unit = GetShaderUnitPtr(shader, (ShaderType)current_shad_type);
if (active_unit == nullptr) return;
if (!active_unit->sh_struct.has_value()) return;
int type_id = 0, vari_id = 0;
// [BASE INFO]
ImGui::PushID(type_id++);
if (ImGui::TreeNode("Base Information")) {
ImGui::Text("========================");
ImGui::Text("GLSL version : %i", active_unit->sh_struct->version);
ImGui::Text("Shader Type : %s", Shaders::shader_type[current_shad_type].c_str());
ImGui::Text("Shader ID : %i", active_unit->sh_ID);
ImGui::Text(active_unit->sh_struct->is_struct_changed ? "Status : Changed" : "Status : Compiled");
ImGui::Text("========================");
ImGui::TreePop();
}
ImGui::PopID();
// [AB]
if (active_unit->sh_struct->AB_list.size()) {
ImGui::PushID(type_id++);
if (ImGui::TreeNode("Array Buffer")) {
for (auto& l_in : active_unit->sh_struct->AB_list) {
ImGui::PushID(vari_id);
if (ImGui::TreeNode(std::get<1>(l_in).c_str())) {
RenderLayout(&std::get<0>(l_in), &std::get<1>(l_in), &std::get<2>(l_in), add_name, &sel);
ImGui::TreePop();
}ImGui::PopID();
}
if (AddParam("Array Buffer", "layout")) {
const S_AB layout{ std::get<2>(add_prop), std::get<0>(add_prop), std::get<1>(add_prop) };
evt.emit<ShaderStructAddArrayBufferEvent>({ shader, ShaderType(current_shad_type), layout });
}ImGui::TreePop();
}ImGui::PopID(); vari_id = 0;
}
// [PASS]
if (active_unit->sh_struct->pass_list.size()) {
ImGui::PushID(type_id++);
if (ImGui::TreeNode("Rendering Pass")) {
for (auto& i : active_unit->sh_struct->pass_list) {
ImGui::PushID(vari_id);
if (ImGui::TreeNode(std::get<1>(i).c_str())) {
ImGui::TreePop();
}ImGui::PopID();
}
if (AddParam("Render Pass", "layout")) {
const S_REND layout{ std::get<2>(add_prop), std::get<0>(add_prop), std::get<1>(add_prop) };
evt.emit<ShaderStructAddPassEvent>({ shader, ShaderType(current_shad_type), layout });
}ImGui::TreePop();
}ImGui::PopID(); vari_id = 0;
}
//[IN]
if (active_unit->sh_struct->input_list.size()) {
ImGui::PushID(type_id++);
if (ImGui::TreeNode("Input")) {
for (auto& i : active_unit->sh_struct->input_list) {
ImGui::PushID(vari_id);
if (ImGui::TreeNode(std::get<0>(i).c_str())) {
ImGui::TreePop();
}ImGui::PopID();
}
if (AddParam("Input", "number")) {
evt.emit<ShaderStructAddInputEvent>({ shader, ShaderType(current_shad_type), add_prop });
}ImGui::TreePop();
}ImGui::PopID(); vari_id = 0;
}
//[OUT]
if (active_unit->sh_struct->output_list.size()) {
ImGui::PushID(type_id++);
if (ImGui::TreeNode("Output")) {
for (auto& i : active_unit->sh_struct->output_list) {
ImGui::PushID(vari_id);
if (ImGui::TreeNode(std::get<0>(i).c_str())) {
ImGui::TreePop();
}ImGui::PopID();
}
if (AddParam("Output", "number")) {
evt.emit<ShaderStructAddOutputEvent>({ shader, ShaderType(current_shad_type), add_prop });
}ImGui::TreePop();
}ImGui::PopID(); vari_id = 0;
}
//[UNIFORM]
if (active_unit->sh_struct->uniform_list.size()) {
ImGui::PushID(type_id++);
if (ImGui::TreeNode("Uniform")) {
int index = 0;
for (auto& i : active_unit->sh_struct->uniform_list) {
ImGui::PushID(vari_id);
if (ImGui::TreeNode(std::get<0>(i).c_str())) {
RenderArg(std::get<1>(i), std::get<0>(i), index++, false, &sel);
ImGui::TreePop();
}ImGui::PopID();
}
//ImGui::PushFont(ImguiTheme::th_data.font_data[0]);
if (AddParam("Uniforms", "number")) {
evt.emit<ShaderStructAddUniformEvent>({ shader, ShaderType(current_shad_type), add_prop });
}ImGui::TreePop();
//ImGui::PopFont();
}ImGui::PopID(); vari_id = 0;
}
//[STRUCT]
if (active_unit->sh_struct->struct_def_list.size()) {
ImGui::PushID(type_id++);
if (ImGui::TreeNode("Struct")) {
for (auto& i : active_unit->sh_struct->struct_def_list) {
ImGui::PushID(vari_id);
if (ImGui::TreeNode(std::get<1>(i).c_str())) {
RenderName("struct name", &std::get<1>(i));
RenderArgs(std::get<2>(i), 0, &sel);
ImGui::TreePop();
}ImGui::PopID();
}
if (AddStruct()) {
evt.emit<ShaderStructAddStructEvent>({ shader, ShaderType(current_shad_type), std::get<1>(add_args), std::get<3>(add_args) });
}ImGui::TreePop();
}ImGui::PopID(); vari_id = 0;
}
//[Globs]
if (active_unit->sh_struct->glob_list.size()) {
ImGui::PushID(type_id++);
if (ImGui::TreeNode("Globs")) {
for (auto& i : active_unit->sh_struct->glob_list) {
ImGui::PushID(vari_id);
if (ImGui::TreeNode(std::get<0>(i).c_str())) {
ImGui::TreePop();
}ImGui::PopID();
}
if (ImGui::Button("+", ImVec2(ImGui::GetContentRegionAvail().x - 15, 20)))
{
// TODO
}ImGui::TreePop();
}ImGui::PopID(); vari_id = 0;
}
//[Const]
if (active_unit->sh_struct->const_list.size()) {
ImGui::PushID(type_id++);
if (ImGui::TreeNode("Consts")) {
for (auto& i : active_unit->sh_struct->const_list) {
ImGui::PushID(vari_id);
if (ImGui::TreeNode(std::get<1>(i).c_str())) {
RenderName(("name_" + std::get<1>(i)).c_str(), &std::get<1>(i), 100);
ImGui::SameLine();
RenderName(("content" + std::get<1>(i)).c_str(), &std::get<2>(i), 200, false);
ImGui::TreePop();
}ImGui::PopID();
}
if (ImGui::Button("+", ImVec2(ImGui::GetContentRegionAvail().x - 15, 20)))
{
// TODO
}ImGui::TreePop();
}ImGui::PopID(); vari_id = 0;
}
//[Funcs]
if (active_unit->sh_struct->func_list.size()) {
ImGui::PushID(type_id++);
if (ImGui::TreeNode("Functions")) {
for (auto& i : active_unit->sh_struct->func_list) {
bool op_ev = false, st_ev = false;
ImGui::PushID(vari_id++);
bool is_op = ImGui::TreeNodeB(
std::get<1>(i).c_str(),
&active_unit->sh_struct->func_list_state[vari_id - 1],
&op_ev,
&st_ev,
0,
(active_func != vari_id)
);
if (op_ev) {
se_code_editor.SetText(std::get<2>(i));
active_func = vari_id;
}
if (active_func == vari_id && is_op) {
RenderName("func name", &std::get<1>(i));
if (ImGui::TreeNode("arguments list")) {
RenderArgs(std::get<3>(i), -1, &sel);
ImGui::TreePop();
}
if (ImGui::Button("Apply", ImVec2(ImGui::GetContentRegionAvail().x, 20))) {
std::get<2>(i) = se_code_editor.GetText();
}
se_code_editor.Render(std::get<1>(i).c_str(), ImVec2(ImGui::GetContentRegionAvail().x, 100), true);
}ImGui::PopID();
if (is_op)ImGui::TreePop();
if (st_ev) {
if (se_code_editor.IsTextChanged())
std::get<2>(i) = se_code_editor.GetText();
active_unit->sh_struct->is_struct_changed = true;
// TODO: emit event to update shader code
}
}
if (ImGui::Button("+", ImVec2(ImGui::GetContentRegionAvail().x - 15, 20)))
{
// TODO
}ImGui::TreePop();
}ImGui::PopID(); vari_id = 0;
}
if (ImGui::Button("+", ImVec2(ImGui::GetContentRegionAvail().x - 5, 20)))
{
// TODO
}
}
void ShaderEditor::UpdateCoderEditor(ObjectID* obj) {
Shaders* shader = GetActiveShaderPtr(obj);
Shaders::ShaderUnit* active_unit = GetShaderUnitPtr(shader, (ShaderType)current_shad_type);
if (active_unit == nullptr) return;
if (current_edit == ShaderEditor::CODE_EDITOR) {
se_code_editor.SetText(active_unit->sh_code);
}
UpdateKeyword();
}
void ShaderEditor::RenderLayer(const Context& ctx, EventPool& evt)
{
ObjectID* active_obj = ctx.editor.selections.GetSelectedObjects();
Shaders* active_shader = GetActiveShaderPtr(active_obj);
Shaders::ShaderUnit* active_unit = GetShaderUnitPtr(active_shader, (ShaderType)current_shad_type);
if (active_shader == nullptr) {
ImGui::Text("No active shader");
return;
}
bool is_mode_changed = false, is_shad_type_changed = false;
if (ImGui::BeginCombo("Edit Mode", edit_mode[current_edit].c_str())) {
LOOP(3)
if (ImGui::Selectable(edit_mode[i].c_str(), &sel)) {
is_mode_changed |= current_edit != i;
current_edit = ShaderEditMode(i);
}
ImGui::EndCombo();
}
if (ImGui::BeginCombo("Shader Type", Shaders::shader_type[current_shad_type].c_str())) {
const std::vector<ShaderType> all_types = active_shader->GetAllShaderTypes();
LOOP(all_types.size()) {
const ShaderType type = all_types[i];
if (ImGui::Selectable(Shaders::shader_type[type].c_str(), &sel)) {
is_shad_type_changed |= current_shad_type != type;
current_shad_type = type;
}
}
ImGui::EndCombo();
}
if (ImGui::Button("Compile", ImVec2(ImGui::GetContentRegionAvail().x / 2, 25))) {
if (current_edit == CODE_EDITOR && se_code_editor.GetText() != active_unit->sh_code) {
evt.emit <ShaderCodeCompileEvent> ({ active_shader, ShaderType(current_shad_type), se_code_editor.GetText() });
}else if (current_edit == STRUCT_EDITOR && active_unit->sh_struct->is_struct_changed) {
evt.emit<ShaderStructCompileEvent>({ active_shader, ShaderType(current_shad_type) });
}
}ImGui::SameLine();
if (ImGui::Button("Save", ImVec2(ImGui::GetContentRegionAvail().x, 25))) {
evt.emit<ShaderSaveEvent>({ active_shader, ShaderType(current_shad_type) });
}
//editor.SetLanguageDefinition(TextEditor::LanguageDefinition().GLSL());
switch (current_edit)
{
case CODE_EDITOR:
se_code_editor.Render("##Editor", ImGui::GetContentRegionAvail());
break;
case STRUCT_EDITOR:
RenderShaderStruct(active_obj, evt);
break;
case NODE_EDITOR:
se_node_editor.Render(ctx, "##Node");
break;
}
if (is_mouse_hovered && current_edit == NODE_EDITOR) {
if (Input::IsMousePressed(Input::MouseButtons::MMB)) { // MMB
if (Input::IsKeyPressed(Input::SHIFT) || Input::IsKeyPressed(Input::NONE))
se_node_editor.MoveView();
else if (Input::IsKeyPressed(Input::CTRL))
se_node_editor.PushView();
}
if (Input::IsMouseScrolled()) {
se_node_editor.ZoomView();
}
}
if (is_shad_type_changed || is_mode_changed) {
UpdateCoderEditor(active_obj);
}
}