/* -*-c++-*- */ /* osgEarth - Geospatial SDK for OpenSceneGraph * Copyright 2018 Pelican Mapping * http://osgearth.org * * osgEarth is free software; you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see */ #pragma once #include #include #include #include #include #include #include #include namespace osgEarth { using namespace osgEarth::Threading; using namespace osgEarth::Util; class ShaderGUI : public ImGuiPanel { private: struct UniformSpec { std::string _name; float _minval, _maxval, _value; osg::ref_ptr _u; }; std::vector _uniforms; struct DefineSpec { std::string _name; bool _checked; }; std::vector _defines; ProgramRepo::ProgramMap _db; public: ShaderGUI(osg::ArgumentParser* args = nullptr) : ImGuiPanel("Shaders") { if (args) { while (args->find("--uniform") >= 0) { UniformSpec spec; if (args->read("--uniform", spec._name, spec._minval, spec._maxval)) { spec._value = clamp(0.0f, spec._minval, spec._maxval); spec._u = new osg::Uniform(spec._name.c_str(), spec._value); _uniforms.emplace_back(spec); } } while (args->find("--define") >= 0) { DefineSpec spec; if (args->read("--define", spec._name)) { spec._checked = false; _defines.push_back(spec); } } } } void load(const Config& conf) override { } void save(Config& conf) override { } void draw(osg::RenderInfo& ri) override { if (!isVisible()) return; ImGui::Begin(name(), visible()); { if (!_uniforms.empty()) ImGui::Text("Uniforms:"); for (auto& def : _uniforms) { if (ImGui::SliderFloat(def._name.c_str(), &def._value, def._minval, def._maxval)) { def._u->set(def._value); ri.getCurrentCamera()->getOrCreateStateSet()->addUniform(def._u.get(), osg::StateAttribute::OVERRIDE); } } if (!_defines.empty()) ImGui::Text("Defines:"); for (auto& def : _defines) { if (ImGui::Checkbox(def._name.c_str(), &def._checked)) { if (def._checked) ri.getCurrentCamera()->getOrCreateStateSet()->setDefine(def._name, osg::StateAttribute::ON | osg::StateAttribute::OVERRIDE); else ri.getCurrentCamera()->getOrCreateStateSet()->setDefine(def._name, osg::StateAttribute::OFF | osg::StateAttribute::OVERRIDE); } } ImGui::Separator(); ImGui::TextColored(ImVec4(1, 1, 0, 1), "Active Programs:"); if (_db.empty() || ImGui::Button("Refresh")) { _db = Registry::programRepo().copy(); } static void* open_shader = nullptr; int count = 0; int frame = ri.getState()->getFrameStamp()->getFrameNumber(); for (auto& entry : _db) { if (entry.second->_users.size() > 0 && (frame - entry.second->_frameLastUsed < 60)) { auto program = entry.second->_program; auto name = program->getName(); if (name.empty()) name = "[no name]"; std::string tag = name + "##" + std::to_string(count++); if (ImGui::TreeNode(tag.c_str())) //name.c_str())) { auto num = program->getNumShaders(); for (unsigned i = 0; i < num; ++i) { auto shader = program->getShader(i); auto shader_name = shader->getName(); if (shader_name.empty()) shader_name = "[no name]"; ImGui::PushID(count++); std::string shader_tag = shader_name + "##" + std::to_string(count++); if (ImGui::Button(shader_tag.c_str())) { open_shader = shader; } if (open_shader == shader) { ImGui::SetNextWindowSize(ImVec2(800, 600), ImGuiCond_FirstUseEver); ImGui::Begin(shader_name.c_str()); if (ImGui::Button("Compile")) program->releaseGLObjects(nullptr); ImGui::SameLine(); if (ImGui::Button("Close")) open_shader = nullptr; auto text = shader->getShaderSource(); if (ImGuiEx::InputTextMultiline("##shader_source", &text, ImVec2(-1, -1))) { shader->setShaderSource(text); program->releaseGLObjects(nullptr); } ImGui::End(); } ImGui::PopID(); } ImGui::TreePop(); } } } } ImGui::End(); } }; }