GUIの追加

守矢諏訪子 <suwako@076.moe>、2026-06-25 02:14
コミット aaa1d9b70156a4949bf73e8318c28e6f884076aa ・親 2ae4f5b ・ファイルを見る

11個のファイル、+337 -3

@@ -169,6 +169,7 @@
169169 target_link_libraries(shaderplayground PRIVATE
170170 glad
171171 glfw
172+ imgui
172173 luajit
173174 sqlite3
174175 sol2
@@ -14,6 +14,9 @@
1414 "${CMAKE_CURRENT_SOURCE_DIR}/ImGuiColorTextEdit/TextEditor.cpp"
1515 )
1616
17-target_include_directories(imgui PUBLIC "${CMAKE_CURRENT_SOURCE_DIR}/imgui")
17+target_include_directories(imgui PUBLIC
18+ "${CMAKE_CURRENT_SOURCE_DIR}/imgui"
19+ "${CMAKE_CURRENT_SOURCE_DIR}/ImGuiColorTextEdit"
20+)
1821
1922 target_link_libraries(imgui PUBLIC glfw glad)
@@ -0,0 +1,34 @@
1+#pragma once
2+
3+#include <util/types.hh>
4+
5+#include <imgui.h>
6+#include <TextEditor.h>
7+
8+namespace gui {
9+ enum Languages {
10+ Glsl,
11+ Hlsl,
12+ Lua,
13+ };
14+
15+ class Editor {
16+ public:
17+ Editor(string title, string renderName, string code, Languages lang, ImFont *cjkFont, ImFont *monoFont);
18+ ~Editor();
19+
20+ TextEditor Get() const { return m_Editor; }
21+ void Render();
22+ void SetCode(string code);
23+ void RenderStatusBar(TextEditor editor);
24+
25+ private:
26+ TextEditor m_Editor;
27+ ImFont *m_CjkFont;
28+ ImFont *m_MonoFont;
29+ string m_Title;
30+ string m_RenderName;
31+ string m_Code;
32+ Languages m_Lang;
33+ }; // class Editor
34+} // namespace gui
@@ -0,0 +1,28 @@
1+#pragma once
2+
3+#include <util/types.hh>
4+
5+#include <imgui.h>
6+#include <backends/imgui_impl_glfw.h>
7+#include <backends/imgui_impl_opengl3.h>
8+
9+namespace glfwpp {
10+ class Window;
11+} // namespace glfwpp
12+
13+namespace gui {
14+ class GuiEngine {
15+ public:
16+ GuiEngine(glfwpp::Window *window);
17+ ~GuiEngine();
18+
19+ ImGuiIO &GetIO() const { return ImGui::GetIO(); }
20+ ImFont *GetCjkFont() const { return m_CjkFont; }
21+ ImFont *GetMonoFont() const { return m_MonoFont; }
22+
23+ private:
24+ glfwpp::Window *m_Window;
25+ ImFont *m_CjkFont;
26+ ImFont *m_MonoFont;
27+ }; // class GuiEngine
28+} // namespace gui
@@ -0,0 +1,7 @@
1+#pragma once
2+
3+#include <util/types.hh>
4+
5+namespace gui {
6+ void showTitleBar();
7+} // namespace gui
@@ -0,0 +1,6 @@
1+#pragma once
2+
3+#include <util/types.hh>
4+
5+namespace gui {
6+} // namespace gui
変更 main.cc
@@ -44,7 +44,14 @@
4444 #include <database/setup.hh>
4545 #include <database/shaderdata.hh>
4646 #include <lua/luaengine.hh>
47+#include <gui/guiengine.hh>
48+#include <gui/titlebar.hh>
49+#include <gui/editor.hh>
4750
51+#include <imgui.h>
52+#include <backends/imgui_impl_glfw.h>
53+#include <backends/imgui_impl_opengl3.h>
54+
4855 #include <sol.hpp>
4956
5057 constexpr int windowWidth = 1280;
@@ -63,16 +70,23 @@
6370
6471 // ウィンドウを作成
6572 string winName = sofname + " " + version::full;
66- glfwpp::Window window(windowWidth, windowHeight, winName);
73+ f32 mainScale = ImGui_ImplGlfw_GetContentScaleForMonitor(glfwGetPrimaryMonitor());
74+ glfwpp::Window window((windowWidth * mainScale), (windowHeight * mainScale), winName);
6775 window.MakeContextCurrent();
6876 glfw.SwapInterval(1);
6977
78+ bool showDemo = true;
79+
7080 // GLADを初期化
7181 if (!gladLoadGLLoader((GLADloadproc)glfwGetProcAddress)) {
7282 std::cout << "GLADの初期化に失敗しました" << std::endl;
7383 return -1;
7484 }
7585
86+ // ImGui設定
87+ gui::GuiEngine ge(&window);
88+
89+ // フレームバッファーサイズ
7690 window.SetFramebufferSizeCallback();
7791
7892 // データベースが未だ存在しなければ、初期設定
@@ -81,16 +95,27 @@
8195
8296 // データベースからシェーダーとLuaコードの受け取り
8397 vector<db::ShaderData> codeMap = db::GetAllShaders(db);
98+ string shaderName;
8499 string VERT = "";
85100 string FRAG = "";
86101 string LUA = "";
87102
88103 for (const auto &c : codeMap) {
104+ shaderName = c.name;
89105 VERT = c.vertexShader.code;
90106 FRAG = c.fragmentShader.code;
91107 LUA = c.luaCode.code;
92108 }
93109
110+ string title = shaderName + "(頂点シェーダー)";
111+ gui::Editor vertEditor(title, "VertexEditor", VERT, gui::Glsl, ge.GetCjkFont(), ge.GetMonoFont());
112+
113+ title = shaderName + "(フラグメントシェーダー)";
114+ gui::Editor fragEditor(title, "FragmentEditor", FRAG, gui::Glsl, ge.GetCjkFont(), ge.GetMonoFont());
115+
116+ title = shaderName + "(Luaエディター)";
117+ gui::Editor luaEditor(title, "LuaEditor", LUA, gui::Lua, ge.GetCjkFont(), ge.GetMonoFont());
118+
94119 // シェーダーをコンパイル
95120 Shader vertexShader(VERT, GL_VERTEX_SHADER);
96121 Shader fragmentShader(FRAG, GL_FRAGMENT_SHADER);
@@ -120,6 +145,51 @@
120145
121146 // メインレンダリングループ
122147 while (!window.ShouldClose()) {
148+ glfw.PollEvents();
149+ if (window.GetAttrib(glfwpp::Attributes::Iconified) != 0) {
150+ ImGui_ImplGlfw_Sleep(10);
151+ continue;
152+ }
153+
154+ gui::showTitleBar();
155+
156+ if (showDemo) ImGui::ShowDemoWindow(&showDemo);
157+
158+ vertEditor.Render();
159+ fragEditor.Render();
160+ luaEditor.Render();
161+
162+ {
163+ static float f = 0.0f;
164+ static int counter = 0;
165+
166+ ImGui::Begin("コントロール");
167+
168+ if (ImGui::Button("コンパイル(F5)")) {
169+ VERT = vertEditor.Get().GetText();
170+ FRAG = fragEditor.Get().GetText();
171+ //LUA = luaEditor.Get().GetText();
172+
173+ try {
174+ Shader newVert(VERT, GL_VERTEX_SHADER);
175+ Shader newFrag(FRAG, GL_FRAGMENT_SHADER);
176+ shaderProgram = Program(newVert, newFrag);
177+ } catch (const std::exception &e) {
178+ std::cerr << e.what() << std::endl;
179+ }
180+ }
181+
182+ ImGui::SameLine();
183+
184+ if (ImGui::Button("保存(CTRL + S)")) {
185+ }
186+
187+ ImGui::Text("現在フレームレート: %.3f ms/frame (%.1f FPS)", 1000.0f / ge.GetIO().Framerate, ge.GetIO().Framerate);
188+ ImGui::End();
189+ }
190+
191+ ImGui::Render();
192+
123193 // 画面をクリア
124194 shaderProgram.ClearColor(0.f, 0.f, 0.f, 1.f);
125195 shaderProgram.Clear();
@@ -160,8 +230,8 @@
160230 glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0);
161231
162232 // バッファをスワップし、イベントを処理
233+ ImGui_ImplOpenGL3_RenderDrawData(ImGui::GetDrawData());
163234 window.SwapBuffers();
164- glfw.PollEvents();
165235 }
166236
167237 return 0;
@@ -0,0 +1,108 @@
1+#include <gui/editor.hh>
2+
3+namespace gui {
4+ Editor::Editor(string title, string renderName, string code, Languages lang, ImFont *cjkFont, ImFont *monoFont) {
5+ m_CjkFont = cjkFont;
6+ m_MonoFont = monoFont;
7+ m_Title = title;
8+ m_RenderName = renderName;
9+ m_Code = code;
10+ m_Editor.SetText(code);
11+ m_Lang = lang;
12+
13+ if (lang == Glsl) {
14+ m_Editor.SetLanguage(TextEditor::Language::Glsl());
15+ } else if (lang == Hlsl) {
16+ // 現在未対応
17+ m_Editor.SetLanguage(TextEditor::Language::Hlsl());
18+ } else if (lang == Lua) {
19+ m_Editor.SetLanguage(TextEditor::Language::Lua());
20+ }
21+ }
22+
23+ Editor::~Editor() {}
24+
25+ void Editor::Render() {
26+ ImGui::PushFont(m_CjkFont);
27+ ImGui::Begin(m_Title.c_str());
28+ ImGui::PopFont();
29+ ImGui::PushFont(m_MonoFont);
30+ m_Editor.Render(m_RenderName.c_str());
31+ ImGui::PopFont();
32+ RenderStatusBar(m_Editor);
33+ ImGui::End();
34+ }
35+
36+ void Editor::RenderStatusBar(TextEditor editor) {
37+ static const char *languages[] = { "Lua", "GLSL", "HLSL" };
38+
39+ static const TextEditor::Language *definitions[] = {
40+ TextEditor::Language::Lua(),
41+ TextEditor::Language::Glsl(),
42+ TextEditor::Language::Hlsl(),
43+ };
44+
45+ std::string language = editor.GetLanguageName();
46+
47+ ImGui::PushStyleColor(ImGuiCol_ChildBg, ImVec4(0.15f, 0.15f, 0.15f, 1.0f));
48+ ImGui::BeginChild("StatusBar", ImVec2(0.0f, 0.0f), ImGuiChildFlags_Borders);
49+ ImGui::SetNextItemWidth(120.0f);
50+
51+ if (ImGui::BeginCombo("##LanguageSelector", language.c_str())) {
52+ for (int n = 0; n < IM_ARRAYSIZE(languages); n++) {
53+ bool selected = (language == languages[n]);
54+
55+ if (ImGui::Selectable(languages[n], selected)) {
56+ editor.SetLanguage(definitions[n]);
57+ //buildAutocompleteTrie();
58+ }
59+
60+ if (selected) {
61+ ImGui::SetItemDefaultFocus();
62+ }
63+ }
64+
65+ ImGui::EndCombo();
66+ }
67+
68+ ImGui::SameLine(0.0f, 0.0f);
69+ ImGui::AlignTextToFramePadding();
70+
71+ int line;
72+ int column;
73+ int tabSize = editor.GetTabSize();
74+ float glyphWidth = ImGui::CalcTextSize("#").x;
75+ editor.GetCurrentCursor(line, column);
76+
77+ // determine status message
78+ char status[256];
79+
80+ auto statusSize = std::snprintf(
81+ status,
82+ sizeof(status),
83+ "Ln %d, Col %d Tab Size: %d File: %s",
84+ line + 1,
85+ column + 1,
86+ tabSize,
87+ "default" // ファイル名
88+ );
89+
90+ auto size = glyphWidth * (statusSize + 3);
91+ auto width = ImGui::GetContentRegionAvail().x;
92+
93+ ImGui::SameLine(0.0f, width - size);
94+ ImGui::TextUnformatted(status);
95+
96+ ImGui::SameLine(0.0f, glyphWidth * 1.0f);
97+ auto drawlist = ImGui::GetWindowDrawList();
98+ auto pos = ImGui::GetCursorScreenPos();
99+ auto offset = ImGui::GetFrameHeight() * 0.5f;
100+ auto radius = offset * 0.6f;
101+ //auto color = isDirty() ? IM_COL32(164, 0, 0, 255) : IM_COL32(164, 164, 164, 255);
102+ auto color = IM_COL32(164, 0, 0, 255);
103+ drawlist->AddCircleFilled(ImVec2(pos.x + offset, pos.y + offset), radius, color);
104+
105+ ImGui::EndChild();
106+ ImGui::PopStyleColor();
107+ }
108+} // namespace gui
@@ -0,0 +1,27 @@
1+#include <gui/guiengine.hh>
2+#include <util/glfwpp.hh>
3+
4+namespace gui {
5+ GuiEngine::GuiEngine(glfwpp::Window *window) {
6+ m_Window = window;
7+ IMGUI_CHECKVERSION();
8+ ImGui::CreateContext();
9+ ImGuiIO &io = ImGui::GetIO();
10+ (void)io;
11+ m_CjkFont = io.Fonts->AddFontFromFileTTF("NotoSansCJKjp-Regular.otf", 16.f, nullptr, io.Fonts->GetGlyphRangesJapanese());
12+ m_MonoFont = io.Fonts->AddFontFromFileTTF("NotoMono-Regular.ttf", 16.f, nullptr, io.Fonts->GetGlyphRangesJapanese());
13+ io.ConfigFlags |= ImGuiConfigFlags_NavEnableKeyboard;
14+ io.ConfigFlags |= ImGuiConfigFlags_NavEnableGamepad;
15+
16+ ImGui::StyleColorsDark();
17+
18+ ImGui_ImplGlfw_InitForOpenGL(window->Get(), true);
19+ ImGui_ImplOpenGL3_Init("#version 460");
20+ }
21+
22+ GuiEngine::~GuiEngine() {
23+ ImGui_ImplOpenGL3_Shutdown();
24+ ImGui_ImplGlfw_Shutdown();
25+ ImGui::DestroyContext();
26+ }
27+} // namespace gui
@@ -0,0 +1,46 @@
1+#include <gui/titlebar.hh>
2+
3+#include <imgui.h>
4+#include <backends/imgui_impl_glfw.h>
5+#include <backends/imgui_impl_opengl3.h>
6+
7+namespace gui {
8+ void showTitleBar() {
9+ ImGui_ImplOpenGL3_NewFrame();
10+ ImGui_ImplGlfw_NewFrame();
11+ ImGui::NewFrame();
12+
13+ if (ImGui::BeginMainMenuBar()) {
14+ if (ImGui::BeginMenu("ファイル")) {
15+ if (ImGui::MenuItem("新しいファイル")) {}
16+ if (ImGui::MenuItem("開く", "Ctrl+O")) {}
17+ if (ImGui::BeginMenu("最近使った物")) {
18+ ImGui::MenuItem("fish_hat.c");
19+ ImGui::MenuItem("fish_hat.inl");
20+ ImGui::MenuItem("fish_hat.h");
21+ if (ImGui::BeginMenu("もっと見る...")) {
22+ ImGui::MenuItem("Hello");
23+ ImGui::MenuItem("Sailor");
24+ ImGui::EndMenu();
25+ }
26+ ImGui::EndMenu();
27+ }
28+ if (ImGui::MenuItem("保存", "Ctrl+S")) {}
29+
30+ ImGui::Separator();
31+ if (ImGui::MenuItem("終了", "CTRL+Q")) {}
32+ ImGui::EndMenu();
33+ }
34+ if (ImGui::BeginMenu("編集")) {
35+ if (ImGui::MenuItem("元に戻す", "Ctrl+Z")) {}
36+ if (ImGui::MenuItem("やり直し", "Ctrl+Y", false, false)) {}
37+ ImGui::Separator();
38+ if (ImGui::MenuItem("切り取り", "Ctrl+X")) {}
39+ if (ImGui::MenuItem("コピー", "Ctrl+C")) {}
40+ if (ImGui::MenuItem("貼り付け", "Ctrl+V")) {}
41+ ImGui::EndMenu();
42+ }
43+ ImGui::EndMainMenuBar();
44+ }
45+ }
46+} // namespace gui
@@ -0,0 +1,4 @@
1+#include <gui/view.hh>
2+
3+namespace gui {
4+} // namespace gui