Editor.cpp 54.9 KB
Newer Older
1
2
3
4
5
6
7
8
#include "Editor.hpp"
#include <dino/editor/iconfont/IconsMaterialDesignIcons.h>
#include <dino/editor/tinyfiledialogs.h>
#include <fstream>
#include <imgui/imgui_internal.h>

namespace dino
{
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
constexpr const char* materialNames[] = {"No Texture",
                                         "Checker Board (procedural)",
                                         "Grid (procedural)",
                                         "Squares (procedural)",
                                         "Crosses (procedural)",
                                         "Flower Noise (procedural)",
                                         "Wood (procedural)",
                                         "Voronoi (procedural)",
                                         "Cube Map",
                                         "Hatch",
                                         "Stippling"};

constexpr const char* layerNames[] = {
        "RENDERLAYER_NONE  ", "Normals           ", "Trace Distance    ", "Object ID         ",
        "Step Count        ", "Min Distance      ", "Gradient (x)      ", "Gradient (y)      ",
        "Material Color    ", "Ambient Lighting  ", "Diffuse Lighting  ", "GGX Shading       ",
        "Ambient Occlusion ", "Shadow Mapping    ", "Soft Shadows      ", "Skybox            ",
        "Skybox Reflections", "Silhouette        ", "Tone Mapping      ", "FXAA              "};

int materialID = 0;
29

30
Editor::Editor(std::shared_ptr<Window> window, std::shared_ptr<dino::Renderer> renderer)
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
        : m_window(std::move(window))
        , m_renderer(std::move(renderer))
{
    m_editorWindow = std::make_unique<Window>(1280,
                                              720,
                                              "I have no idea how to name this window.",
                                              m_window,
                                              dino::Window::Hints{{GLFW_SAMPLES, 8},
                                                                  {GLFW_CONTEXT_VERSION_MINOR, 3},
                                                                  {GLFW_VISIBLE, 0}});
    glfwSetWindowCloseCallback(*m_editorWindow, [](GLFWwindow* window) {
        glfwSetWindowShouldClose(window, GL_FALSE);
        glfwHideWindow(window);
    });
    glfwMakeContextCurrent(*m_window);

47
48
49
50
51
52
53
54
55
56
57
58
    updateFromRenderer();

    int w, h;
    glfwGetFramebufferSize(*m_window, &w, &h);
    m_previewFramebuffer = std::make_unique<dino::FrameBuffer>();
    m_previewTexture = std::make_shared<dino::Texture>(GL_TEXTURE_2D, GL_RGBA8, glm::ivec2{w, h});
    m_previewFramebuffer->addColorAttachment(0, m_previewTexture);
    prepareTextures();
}

void Editor::updateFromRenderer()
{
59
60
61
62
    const auto oldFields = m_renderer->packFunctions();
    for(const auto& field : oldFields)
    {
        m_allFieldIds.push_back(field.first);
63
64
        m_blueprints.emplace_back(std::make_unique<dino::Blueprints>(*m_window))
                ->load(field.second);
65
    }
66

Darius Thies's avatar
Darius Thies committed
67
68
    for(const auto& p : m_renderer->getLights())
        m_allLightIds.push_back(p.first);
69

70
71
72
73
74
75
76
77
78
    int erased = 0;
    m_inactiveRenderLayers.resize(std::size(layerNames));
    std::iota(m_inactiveRenderLayers.begin(), m_inactiveRenderLayers.end(), 0u);
    for(int i = 0; i < m_renderer->getRenderLayers().size(); ++i)
    {
        const auto       id   = static_cast<uint32_t>(m_renderer->getRenderLayers()[i]->getType());
        ActiveLayerInfo& info = m_activeRenderLayers.emplace_back();
        info.indexInRenderer  = i;
        info.layerIndex       = id;
79
80
81
        m_inactiveRenderLayers.erase(
                std::remove(m_inactiveRenderLayers.begin(), m_inactiveRenderLayers.end(), id),
                m_inactiveRenderLayers.end());
82
83
        ++erased;
    }
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
}

void Editor::loadField(const std::filesystem::path path)
{
    std::ifstream  ifs(path);
    nlohmann::json j;
    try
    {
        ifs >> j;
        const auto                            bf  = dino::Function::deserialize(j);
        const std::shared_ptr<dino::Material> mat = std::make_shared<dino::Material>();
        mat->deserialize(j["material"]);
        if(const auto op = bf->as<dino::Operator>(); op)
        {
            m_renderer->add(op, mat);
            m_allFieldIds.push_back(m_renderer->getFunctionId(op));
            m_blueprints.emplace_back(std::make_unique<dino::Blueprints>(*m_window))->load(op);
        }
        else if(const auto pr = bf->as<dino::Primitive>(); pr)
        {
            m_renderer->add(pr, mat);
            m_allFieldIds.push_back(m_renderer->getFunctionId(op));
            m_blueprints.emplace_back(std::make_unique<dino::Blueprints>(*m_window))->load(pr);
        }
        m_blueprints.back()->setPath(path);
    }
    catch(const nlohmann::json::exception& e)
    {
        tinyfd_notifyPopup("Load Distance Field",
                           "Selected file cannot be parsed as a valid json object.",
                           "error");
    }
}

bool Editor::editorShown() const { return glfwGetWindowAttrib(*m_editorWindow, GLFW_VISIBLE); }

120
void Editor::prepareTextures()
121
{
122
    m_stipplingTexture = &m_textureResourceStippling.generate2DResource(
123
            dino::RESOURCES_PATH / "textures/stippling/stippling.png");
124
    m_hatchingTexture = &m_textureResourceHatching.generate3DResource(
125
            dino::RESOURCES_PATH / "textures/hatching", ".png");
126
    m_brickTexture = &m_textureResourceBrick.generateCubeResource(
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
            dino::RESOURCES_PATH / "textures/png", ".png");

    auto stipplingTextureMat = std::make_shared<dino::Material>(
            glm::vec3(1.0f), 1.0f, 0.0f, 1.0f, dino::TextureType::STIPPLING_TEXTURE);
    stipplingTextureMat->setTextureHandle(m_stipplingTexture->handle());

    auto hatchingTextureMat = std::make_shared<dino::Material>(
            glm::vec3(1.0f), 1.0f, 0.0f, 1.0f, dino::TextureType::HATCH_TEXTURE);
    hatchingTextureMat->setTextureHandle(m_hatchingTexture->handle());

    auto brickTextureMat = std::make_shared<dino::Material>(
            glm::vec3(1.0f), 1.0f, 0.0f, 1.0f, dino::TextureType::BOX_TEXTURE);
    brickTextureMat->setTextureHandle(m_brickTexture->handle());
}

142
143
void Editor::deleteField(uint32_t index)
{
144
145
    if(m_allFieldIds.empty())
        return;
146
147
148
149
150
151
152
153
154
155
156
157
158
159
    const auto id = m_allFieldIds[index];
    if(id)
        m_renderer->remove(m_renderer->getFunctionByID(*id));
    m_blueprints.erase(m_blueprints.begin() + index);
    m_allFieldIds.erase(m_allFieldIds.begin() + index);
}

void Editor::saveField(uint32_t index, std::filesystem::path path)
{
    const auto id = m_allFieldIds[index];

    if(!id)
        return;

160
    auto           mat  = m_renderer->getMaterials().at(*id);
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
    nlohmann::json json = m_renderer->getFunctionByID(*id)->serialize();
    json["material"]    = mat->serialize();
    {
        while(path.extension() != ".json")
            path = path.string() + ".json";
        std::ofstream output(path);
        output << std::setw(4) << json;
        std::cout << "SDF { id=" << *id << " } saved successfully.\n";
    }
}

void Editor::drawFieldsTab()
{
    ImGui::PushStyleColor(ImGuiCol_Button, ImVec4(0, 0, 0, 0));
    ImGui::BeginHorizontal("Koffein", ImVec2(ImGui::GetContentRegionAvailWidth(), 0));
    if(ImGui::Button(ICON_MDI_PLUS " Add"))
    {
        m_selectedFieldIndices.clear();
        m_selectedFieldIndices.emplace(m_allFieldIds.size());
        m_activeFieldIndex = m_allFieldIds.size();
        m_allFieldIds.push_back(std::nullopt);
        m_blueprints.emplace_back(std::make_unique<dino::Blueprints>(*m_window));
        glfwShowWindow(*m_editorWindow);
    }
    if(ImGui::Button(ICON_MDI_UPLOAD " Load"))
    {
        const char* fileEnding = "*.json";
        const char* filePath =
                tinyfd_openFileDialog("Load", nullptr, 1, &fileEnding, "JSON-Files", false);
        if(filePath)
        {
            loadField(filePath);
            m_selectedFieldIndices.clear();
            m_selectedFieldIndices.emplace(m_allFieldIds.size() - 1);
        }
    }
    ImGui::Spring();
    ImGui::EndHorizontal();
    ImGui::BeginChild("##content", ImVec2(0, 150));
    ImGui::BeginVertical("##ButtonBar");

    for(int field_index = 0; field_index < static_cast<int>(m_allFieldIds.size()); ++field_index)
    {
        const std::optional<uint32_t> field_id = m_allFieldIds[field_index];
        const auto                    it       = std::find_if(m_selectedFieldIndices.begin(),
                                     m_selectedFieldIndices.end(),
                                     [&](uint32_t index) { return index == field_index; });
        bool                          sel      = it != m_selectedFieldIndices.end();
        ImGui::PushID((std::string("Field") + std::to_string(field_index)).c_str());
        if(ImGui::Button(ICON_MDI_DELETE))
        {
212
            deleteField(0);
213
214
215
            m_selectedFieldIndices.clear();
            m_activeFieldIndex = std::nullopt;
            --field_index;
216
217
            glfwHideWindow(*m_editorWindow);
            ;
218
219
220
221
222
223
224
225
        }
        ImGui::SameLine();
        const bool is_new_field = !field_id;
        if(is_new_field)
        {
            ImGui::PushItemFlag(ImGuiItemFlags_Disabled, true);
            ImGui::PushStyleVar(ImGuiStyleVar_Alpha, 0.2f);
        }
226
        if(ImGui::Button(ICON_MDI_CONTENT_SAVE))
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
        {
            const char* fileEnding = "*.json";
            const char* filePath =
                    tinyfd_saveFileDialog("Save", nullptr, 1, &fileEnding, "JSON-Files");
            if(filePath)
            {
                saveField(*field_id, filePath);
                m_blueprints[*field_id]->setPath(filePath);
            }
        }
        if(is_new_field)
        {
            ImGui::PopStyleVar();
            ImGui::PopItemFlag();
        }
        ImGui::SameLine();
        bool temp_sel = sel;
        if(ImGui::Selectable(field_id ? (std::string(" Distance Field [ID: ") +
                                         std::to_string(*field_id) + "]")
                                                .c_str()
                                      : (std::string(" Distance Field, [New*]##") +
                                         std::to_string(field_index))
                                                .c_str(),
                             &temp_sel))
        {
            if(glfwGetKey(*m_window, GLFW_KEY_LEFT_SHIFT) == GLFW_PRESS)
            {
                if(sel)
                {
                    m_selectedFieldIndices.erase(it);
                }
                else
                {
                    m_selectedFieldIndices.emplace(field_index);
                    m_activeFieldIndex = field_index;
                }
            }
            else
            {
                m_selectedFieldIndices.clear();
                m_selectedFieldIndices.emplace(field_index);
                m_activeFieldIndex = field_index;
            }

            if(field_id)
            {
                m_renderer->setActivePixelObjectId(*field_id);
            }
        }
        ImGui::PopID();
    }

    ImGui::PopStyleColor();
    ImGui::EndVertical();
    ImGui::EndChild();
    ImGui::Separator();

    ImGui::BeginChild("##settings");
    if(!m_selectedFieldIndices.empty())
    {
        if(m_selectedFieldIndices.size() == 1)
        {
            const auto opt_id = m_allFieldIds[*m_selectedFieldIndices.begin()];
            if(!opt_id)
            {
                ImGui::BeginHorizontal("FieldInfo", ImVec2(ImGui::GetContentRegionAvailWidth(), 0));
                ImGui::PushStyleColor(ImGuiCol_Button, ImVec4(0, 0, 0, 0));
                ImGui::Text(" Distance Field [New*]");
                ImGui::Spring();
                if(ImGui::Button(ICON_MDI_SETTINGS " Edit"))
                {
                    glfwShowWindow(*m_editorWindow);
                }
                ImGui::PopStyleColor();
                ImGui::EndHorizontal();
            }
            else
            {
                ImGui::BeginHorizontal("FieldInfo", ImVec2(ImGui::GetContentRegionAvailWidth(), 0));
                ImGui::PushStyleColor(ImGuiCol_Button, ImVec4(0, 0, 0, 0));
                ImGui::Text((" Distance Field [ID: " + std::to_string(*opt_id) + "]").c_str());
                ImGui::Spring();
                if(ImGui::Button(ICON_MDI_SETTINGS " Edit"))
                {
                    glfwShowWindow(*m_editorWindow);
                }
                ImGui::PopStyleColor();
                ImGui::EndHorizontal();
315

316
                auto mat = m_renderer->getMaterials().at(*m_allFieldIds[*m_activeFieldIndex]);
317
318
                if(ImGui::BeginCombo(" ", materialNames[mat->getTextureType()]))
                {
319
                    for(int i = 0; i < std::size(materialNames); i++)
320
321
322
323
                    {
                        if(ImGui::Selectable(materialNames[i], materialID == i))
                        {
                            materialID = i;
324
325
326
327
328
329
330
331
332
333
334
335
336
                            switch(materialID)
                            {
                            case 8:
                                mat->setTextureHandle(m_brickTexture->handle());
                                break;
                            case 9:
                                mat->setTextureHandle(m_hatchingTexture->handle());
                                break;
                            case 10:
                                mat->setTextureHandle(m_stipplingTexture->handle());
                                break;
                            }
                            mat->setTextureType(static_cast<dino::TextureType>(materialID));
337
338
339
340
341
342
343
344
345
346
347
348
349
350
                        }
                        if(materialID == i)
                            ImGui::SetItemDefaultFocus();
                    }
                    ImGui::EndCombo();
                }
                glm::vec3          col = mat->getColor();
                std::vector<float> colv{col.x, col.y, col.z};
                if(ImGui::ColorEdit3("Mat-Color ", &colv[0]))
                {
                    mat->setColor(glm::vec3(colv[0], colv[1], colv[2]));
                }
                float roughness = mat->getRoughness();
                if(ImGui::DragFloat(
351
352
                           (std::string("Roughness ") + std::to_string(*m_activeFieldIndex))
                                   .c_str(),
353
354
355
356
357
                           &roughness,
                           0.01f))
                    mat->setRoughness(roughness);
                float metalness = mat->getMetalness();
                if(ImGui::DragFloat(
358
359
                           (std::string("Metalness ") + std::to_string(*m_activeFieldIndex))
                                   .c_str(),
360
361
362
363
364
365
                           &metalness,
                           0.01f))
                    mat->setMetalness(metalness);
                float ior = mat->getIOR();
                if(ImGui::DragFloat(
                           (std::string("IOR ") + std::to_string(*m_activeFieldIndex)).c_str(),
366
367
                           &ior,
                           0.01f))
368
                    mat->setIOR(ior);
369
370
371
372
            }
        }
    }
    ImGui::EndChild();
373
}
374

375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
void Editor::drawLightsTab()
{
    ImGui::PushStyleColor(ImGuiCol_Button, ImVec4(0, 0, 0, 0));
    ImGui::BeginHorizontal("Koffein", ImVec2(ImGui::GetContentRegionAvailWidth(), 0));
    if(ImGui::Button(ICON_MDI_PLUS " Add"))
    {
        ImGui::OpenPopup("Add Light");
    }
    if(ImGui::BeginPopup("Add Light"))
    {
        const auto newNodePosition = ImGui::GetMousePosOnOpeningCurrentPopup();
        if(ImGui::BeginMenu("Simple Light"))
        {
            if(ImGui::MenuItem("Point Light"))
            {
Darius Thies's avatar
Darius Thies committed
390
391
392
393
394
                m_allLightIds.push_back(m_renderer->addLight(
                        std::make_shared<dino::Light>(dino::LightType::POINT_LIGHT,
                                                      glm::vec3(1.0f, 10.0f, 1.0f),
                                                      glm::vec3(1.0f, 1.0f, 1.0f),
                                                      10.0f)));
395
396
397
            }
            if(ImGui::MenuItem("Spot Light"))
            {
Darius Thies's avatar
Darius Thies committed
398
399
400
401
402
403
404
                m_allLightIds.push_back(m_renderer->addLight(
                        std::make_shared<dino::Light>(dino::LightType::SPOT_LIGHT,
                                                      glm::vec3(1.0f, 10.0f, 1.0f),
                                                      glm::vec3(1.0f, 1.0f, 1.0f),
                                                      10.0f,
                                                      glm::vec3(0.0f, -1.0f, 0.0f),
                                                      0.5f)));
405
406
407
            }
            if(ImGui::MenuItem("Directional Light"))
            {
Darius Thies's avatar
Darius Thies committed
408
409
410
411
412
413
                m_allLightIds.push_back(m_renderer->addLight(
                        std::make_shared<dino::Light>(dino::LightType::DIR_LIGHT,
                                                      glm::vec3(1.0f, 10.0f, 1.0f),
                                                      glm::vec3(1.0f, 1.0f, 1.0f),
                                                      1.0f,
                                                      glm::vec3(-1.0f))));
414
415
416
417
418
419
420
            }
            ImGui::EndMenu();
        };
        if(ImGui::BeginMenu("Shadowmap Lights"))
        {
            if(ImGui::MenuItem("Point Light"))
            {
Darius Thies's avatar
Darius Thies committed
421
                m_allLightIds.push_back(m_renderer->addLight(
422
423
424
                        std::make_shared<dino::ShadowMapLight>(dino::LightType::POINT_LIGHT,
                                                               glm::vec3(1.0f, 10.0f, 1.0f),
                                                               glm::vec3(1.0f, 1.0f, 1.0f),
425
                                                               10.0f)));
426
427
428
            }
            if(ImGui::MenuItem("Spot Light"))
            {
Darius Thies's avatar
Darius Thies committed
429
                m_allLightIds.push_back(m_renderer->addLight(
430
431
432
433
434
                        std::make_shared<dino::ShadowMapLight>(dino::LightType::SPOT_LIGHT,
                                                               glm::vec3(1.0f, 10.0f, 1.0f),
                                                               glm::vec3(1.0f, 1.0f, 1.0f),
                                                               10.0f,
                                                               glm::vec3(0.0f, -1.0f, 0.0f),
435
                                                               0.5f)));
436
437
438
            }
            if(ImGui::MenuItem("Directional Light"))
            {
Darius Thies's avatar
Darius Thies committed
439
                m_allLightIds.push_back(m_renderer->addLight(
440
441
442
443
                        std::make_shared<dino::ShadowMapLight>(dino::LightType::DIR_LIGHT,
                                                               glm::vec3(1.0f, 10.0f, 1.0f),
                                                               glm::vec3(1.0f, 1.0f, 1.0f),
                                                               1.0f,
444
                                                               glm::vec3(-1.0f))));
445
446
447
448
449
450
451
            }
            ImGui::EndMenu();
        };
        if(ImGui::BeginMenu("Traced Lights"))
        {
            if(ImGui::MenuItem("Point Light"))
            {
Darius Thies's avatar
Darius Thies committed
452
                m_allLightIds.push_back(m_renderer->addLight(
453
454
455
                        std::make_shared<dino::TracedLight>(dino::LightType::POINT_LIGHT,
                                                            glm::vec3(1.0f, 10.0f, 1.0f),
                                                            glm::vec3(1.0f, 1.0f, 1.0f),
456
                                                            10.0f)));
457
458
459
            }
            if(ImGui::MenuItem("Spot Light"))
            {
Darius Thies's avatar
Darius Thies committed
460
                m_allLightIds.push_back(m_renderer->addLight(
461
462
463
464
465
                        std::make_shared<dino::TracedLight>(dino::LightType::SPOT_LIGHT,
                                                            glm::vec3(1.0f, 10.0f, 1.0f),
                                                            glm::vec3(1.0f, 1.0f, 1.0f),
                                                            10.0f,
                                                            glm::vec3(0.0f, -1.0f, 0.0f),
466
                                                            0.5f)));
467
468
469
            }
            if(ImGui::MenuItem("Directional Light"))
            {
Darius Thies's avatar
Darius Thies committed
470
                m_allLightIds.push_back(m_renderer->addLight(
471
472
473
474
                        std::make_shared<dino::TracedLight>(dino::LightType::DIR_LIGHT,
                                                            glm::vec3(1.0f, 10.0f, 1.0f),
                                                            glm::vec3(1.0f, 1.0f, 1.0f),
                                                            1.0f,
475
                                                            glm::vec3(-1.0f))));
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
            }
            ImGui::EndMenu();
        };
        ImGui::EndPopup();
    }
    if(ImGui::Button(ICON_MDI_ARROW_EXPAND_HORIZONTAL " All"))
    {
        ImGui::OpenPopup("Convert All");
    }
    if(ImGui::IsItemHovered())
    {
        ImGui::BeginTooltip();
        ImGui::PushTextWrapPos(ImGui::GetFontSize() * 35.0f);
        ImGui::TextUnformatted("Convert all to ..");
        ImGui::PopTextWrapPos();
        ImGui::EndTooltip();
    }
    if(ImGui::BeginPopup("Convert All"))
    {
        if(ImGui::MenuItem("ShadowMap Light"))
        {
            for(int i = 0; i < m_renderer->getLights().size(); i++)
            {
499
                m_renderer->convertLight(m_allLightIds[i], dino::ShadowType::SHADOWMAP_SHADOW);
500
501
502
503
504
505
            }
        }
        if(ImGui::MenuItem("Traced Light"))
        {
            for(int i = 0; i < m_renderer->getLights().size(); i++)
            {
506
                m_renderer->convertLight(m_allLightIds[i], dino::ShadowType::TRACED_SHADOW);
507
508
509
510
511
512
            }
        }
        if(ImGui::MenuItem("Simple Light"))
        {
            for(int i = 0; i < m_renderer->getLights().size(); i++)
            {
513
                m_renderer->convertLight(m_allLightIds[i], dino::ShadowType::NO_SHADOW);
514
515
516
517
518
519
520
521
            }
        }
        ImGui::EndPopup();
    }
    if(ImGui::Button(ICON_MDI_DELETE " All"))
    {
        m_selectedLightIndices.clear();
        m_activeLightIndex = std::nullopt;
522
        for(auto id : m_allLightIds)
523
        {
524
            m_renderer->removeLight(id);
525
        }
Darius Thies's avatar
Darius Thies committed
526
        m_allLightIds.clear();
527
528
529
530
531
532
533
534
    }
    ImGui::Spring();
    ImGui::EndHorizontal();
    ImGui::BeginChild("##content", ImVec2(0, 150));
    ImGui::BeginVertical("##ButtonBar");

    for(int light_index = 0; light_index < m_renderer->getLights().size(); ++light_index)
    {
Darius Thies's avatar
Darius Thies committed
535
536
        const auto light_id = m_allLightIds[light_index];
        const auto it       = std::find_if(m_selectedLightIndices.begin(),
537
538
                                     m_selectedLightIndices.end(),
                                     [&](uint32_t index) { return index == light_index; });
Darius Thies's avatar
Darius Thies committed
539
        bool       sel      = it != m_selectedLightIndices.end();
540
        ImGui::PushID((std::string("light") + std::to_string(light_id)).c_str());
541
542

        std::string lightName    = "";
543
        auto        currentLight = m_renderer->getLights().at(light_id);
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
        if(currentLight->shadowType() == ShadowType::NO_SHADOW)
            lightName += "Simple ";
        else if(currentLight->shadowType() == ShadowType::SHADOWMAP_SHADOW)
            lightName += "Shadowmap ";
        else if(currentLight->shadowType() == ShadowType::TRACED_SHADOW)
            lightName += "Traced ";

        if(currentLight->type() == LightType::POINT_LIGHT)
            lightName += "Point ";
        else if(currentLight->type() == LightType::DIR_LIGHT)
            lightName += "Directional ";
        else if(currentLight->type() == LightType::SPOT_LIGHT)
            lightName += "Spot ";

        if(ImGui::Button(ICON_MDI_DELETE))
        {
560
            m_renderer->removeLight(light_id);
561
562
            m_selectedLightIndices.clear();
            m_activeLightIndex = std::nullopt;
Darius Thies's avatar
Darius Thies committed
563
            m_allLightIds.erase(m_allLightIds.begin() + light_index);
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
            --light_index;
        }
        ImGui::SameLine();
        if(ImGui::Button(ICON_MDI_ARROW_EXPAND_HORIZONTAL))
        {
            ImGui::OpenPopup("Convert");
        }
        if(ImGui::IsItemHovered())
        {
            ImGui::BeginTooltip();
            ImGui::PushTextWrapPos(ImGui::GetFontSize() * 35.0f);
            ImGui::TextUnformatted("Convert to ..");
            ImGui::PopTextWrapPos();
            ImGui::EndTooltip();
        }
        if(ImGui::BeginPopup("Convert"))
        {
            if(ImGui::MenuItem("ShadowMap Light"))
            {
583
                m_renderer->convertLight(light_id, dino::ShadowType::SHADOWMAP_SHADOW);
584
585
586
            }
            if(ImGui::MenuItem("Traced Light"))
            {
587
                m_renderer->convertLight(light_id, dino::ShadowType::TRACED_SHADOW);
588
589
590
            }
            if(ImGui::MenuItem("Simple Light"))
            {
591
                m_renderer->convertLight(light_id, dino::ShadowType::NO_SHADOW);
592
593
594
595
596
597
598
599
            }
            ImGui::EndPopup();
        }

        ImGui::SameLine();

        bool temp_sel = sel;
        if(ImGui::Selectable(
600
                   (lightName + std::string(" Light [ID: ") + std::to_string(light_id) + "]")
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
                           .c_str(),
                   &temp_sel))
        {
            if(glfwGetKey(*m_window, GLFW_KEY_LEFT_SHIFT) == GLFW_PRESS)
            {
                if(sel)
                {
                    m_selectedLightIndices.erase(it);
                }
                else
                {
                    m_selectedLightIndices.emplace(light_index);
                }
            }
            else
            {
                m_selectedLightIndices.clear();
                m_selectedLightIndices.emplace(light_index);
                m_activeLightIndex = light_index;
            }
        }
        ImGui::PopID();
    }

    ImGui::PopStyleColor();
    ImGui::EndVertical();
    ImGui::EndChild();
    ImGui::Separator();

    ImGui::BeginChild("##settings");
    if(m_activeLightIndex)
    {
Darius Thies's avatar
Darius Thies committed
633
634
635
636
637
        ImGui::Text(
                (" Light Settings [ID: " + std::to_string(m_allLightIds[*m_activeLightIndex]) + "]")
                        .c_str());
        auto light                 = m_renderer->getLights().at(m_allLightIds[*m_activeLightIndex]);
        const dino::LightType type = light->type();
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707

        float     intensity = light->intensity();
        glm::vec3 col       = light->color();
        if(ImGui::ColorEdit3("Color ",
                             glm::value_ptr(col),
                             ImGuiColorEditFlags_Float | ImGuiColorEditFlags_HDR))
        {
            light->setColor(col);
        }
        if(ImGui::DragFloat("Intensity ", &intensity, 0.01f))
        {
            light->setIntensity(intensity);
        }
        if(type == dino::LightType::SPOT_LIGHT || type == dino::LightType::POINT_LIGHT)
        {
            glm::vec3 pos = light->position();
            if(ImGui::DragFloat3("Position", glm::value_ptr(pos), 0.01f))
                light->setPosition(pos);
        }

        if(type == dino::LightType::SPOT_LIGHT || type == dino::LightType::DIR_LIGHT)
        {
            glm::vec3 dir = light->direction();
            if(ImGui::DragFloat3("Direction", glm::value_ptr(dir), 0.01f))
                light->setDirection(dir);
        }

        if(type == dino::LightType::SPOT_LIGHT)
        {
            float cutoff = light->cutoff();
            if(ImGui::DragFloat("Cutoff", &cutoff, 0.01f))
                light->setCutoff(cutoff);
        }
    }
    // if(pixelObjectId != -1)
    //{
    //    if(!renderer->getFunctionByID(pixelObjectId))
    //    {
    // if(!m_selectedFieldIndices.empty())
    //{
    //    if(m_selectedFieldIndices.size() == 1)
    //    {
    //        const auto opt_id = m_allFieldIds[*m_selectedFieldIndices.begin()];
    //        if(!opt_id)
    //        {
    //            ImGui::BeginHorizontal("FieldInfo", ImVec2(ImGui::GetContentRegionAvailWidth(),
    //            0)); ImGui::PushStyleColor(ImGuiCol_Button, ImVec4(0, 0, 0, 0)); ImGui::Text("
    //            Distance Field [New*]"); ImGui::Spring(); if(ImGui::Button(ICON_MDI_SETTINGS "
    //            Edit"))
    //            {
    //                glfwShowWindow(*m_editorWindow);
    //            }
    //            ImGui::PopStyleColor();
    //            ImGui::EndHorizontal();
    //        }
    //        else
    //        {
    //            ImGui::BeginHorizontal("FieldInfo", ImVec2(ImGui::GetContentRegionAvailWidth(),
    //            0)); ImGui::PushStyleColor(ImGuiCol_Button, ImVec4(0, 0, 0, 0)); ImGui::Text(("
    //            Distance Field [ID: " + std::to_string(*opt_id) + "]").c_str()); ImGui::Spring();
    //            if(ImGui::Button(ICON_MDI_SETTINGS " Edit"))
    //            {
    //                glfwShowWindow(*m_editorWindow);
    //            }
    //            ImGui::PopStyleColor();
    //            ImGui::EndHorizontal();
    //        }
    //    }
    //}
    ImGui::EndChild();
708
}
709

Darius Thies's avatar
Darius Thies committed
710
711
void Editor::drawRenderingTab()
{
712
713
714
    ImGui::PushStyleColor(ImGuiCol_Button, ImVec4(0, 0, 0, 0));
    ImGui::BeginHorizontal("Koffein", ImVec2(ImGui::GetContentRegionAvailWidth(), 0));
    if(ImGui::Button(ICON_MDI_PLUS " Add"))
Darius Thies's avatar
Darius Thies committed
715
    {
716
        ImGui::OpenPopup("Add Layer");
Darius Thies's avatar
Darius Thies committed
717
    }
718
    if(ImGui::BeginPopup("Add Layer"))
Darius Thies's avatar
Darius Thies committed
719
    {
720
        for(auto it = m_inactiveRenderLayers.begin(); it != m_inactiveRenderLayers.end(); ++it)
Darius Thies's avatar
Darius Thies committed
721
        {
722
            if(ImGui::Selectable(layerNames[*it]))
Darius Thies's avatar
Darius Thies committed
723
            {
724
725
726
727
728
729
730
731
                m_activeRenderLayers.insert(
                        std::prev(m_activeRenderLayers.end()),
                        ActiveLayerInfo{*it,
                                        m_renderer->addRenderLayer(
                                                static_cast<dino::RenderLayer::Type>(*it))});
                it = m_inactiveRenderLayers.erase(it);
                ImGui::CloseCurrentPopup();
                break;
Darius Thies's avatar
Darius Thies committed
732
733
            }
        }
734
        ImGui::EndPopup();
Darius Thies's avatar
Darius Thies committed
735
    }
736
737
    ImGui::Spring();
    ImGui::EndHorizontal();
Darius Thies's avatar
Darius Thies committed
738
739

    // Render + dragging
740
    for(auto it = m_activeRenderLayers.begin(); it != m_activeRenderLayers.end();)
Darius Thies's avatar
Darius Thies committed
741
    {
742
743
744
745
        const ActiveLayerInfo& info        = *it;
        bool                   doIncrement = true;
        const bool             canDelete = static_cast<dino::RenderLayer::Type>(info.layerIndex) !=
                               dino::RenderLayer::SILHOUETTE;
746
747
        const bool canMoveBackward =
                info.indexInRenderer && it > m_activeRenderLayers.begin() && canDelete;
748
        const bool canMoveForward =
749
750
751
                info.indexInRenderer &&
                (m_activeRenderLayers.size() != 1 &&
                 it < std::prev(std::prev(m_activeRenderLayers.end())) && canDelete);
752
753

        if(!canDelete)
Darius Thies's avatar
Darius Thies committed
754
        {
755
756
757
758
759
760
761
            ImGui::PushItemFlag(ImGuiItemFlags_Disabled, true);
            ImGui::PushStyleVar(ImGuiStyleVar_Alpha, 0.2f);
        }
        if(ImGui::Button(
                   (std::string(ICON_MDI_DELETE "##") + std::to_string(info.layerIndex)).c_str()) &&
           canDelete)
        {
762
            m_renderer->clearAllSsShadowTextures();
763
764
            if(info.indexInRenderer)
                m_renderer->removeRenderLayer(*info.indexInRenderer);
765
766
            const auto id = it->indexInRenderer ? *it->indexInRenderer
                                                : std::numeric_limits<uint32_t>::max();
Felix Schröder's avatar
Felix Schröder committed
767
            m_inactiveRenderLayers.push_back(it->layerIndex);
768
769
770
771
            it = m_activeRenderLayers.erase(it);
            for(auto& rl : m_activeRenderLayers)
                if(rl.indexInRenderer && *rl.indexInRenderer > id)
                    --*rl.indexInRenderer;
772
773
774
775
776
777
            doIncrement = false;
        }
        if(!canDelete)
        {
            ImGui::PopItemFlag();
            ImGui::PopStyleVar();
Darius Thies's avatar
Darius Thies committed
778
        }
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
        ImGui::SameLine();
        if(!canMoveBackward)
        {
            ImGui::PushItemFlag(ImGuiItemFlags_Disabled, true);
            ImGui::PushStyleVar(ImGuiStyleVar_Alpha, 0.2f);
        }
        if(ImGui::Button(
                   (std::string(ICON_MDI_ARROW_UP_BOLD "##") + std::to_string(info.layerIndex))
                           .c_str()) &&
           canMoveBackward)
        {
            m_renderer->swapLayers(*info.indexInRenderer, *info.indexInRenderer - 1);
            std::swap(it->indexInRenderer, std::prev(it)->indexInRenderer);
            std::iter_swap(it, std::prev(it));
        }
        if(!canMoveBackward)
        {
            ImGui::PopItemFlag();
            ImGui::PopStyleVar();
        }
        ImGui::SameLine();
        if(!canMoveForward)
        {
            ImGui::PushItemFlag(ImGuiItemFlags_Disabled, true);
            ImGui::PushStyleVar(ImGuiStyleVar_Alpha, 0.2f);
        }
        if(ImGui::Button(
                   (std::string(ICON_MDI_ARROW_DOWN_BOLD "##") + std::to_string(info.layerIndex))
                           .c_str()) &&
           canMoveForward)
        {
            m_renderer->swapLayers(*info.indexInRenderer, *info.indexInRenderer + 1);
            std::swap(it->indexInRenderer, std::next(it)->indexInRenderer);
            std::iter_swap(it, std::next(it));
        }
        if(!canMoveForward)
        {
            ImGui::PopItemFlag();
            ImGui::PopStyleVar();
        }
819
820
        const float btnHeight = ImGui::GetItemsLineHeightWithSpacing();

821
822
823
        ImGui::SameLine();
        ImGui::Selectable(layerNames[info.layerIndex]);

824
825
826
827
828
829
830
831
832
833
834
835
836
        if((canMoveBackward || canMoveForward) && ImGui::IsItemHovered() &&
           !m_layerDragState.dragging)
        {
            if(glfwGetMouseButton(*m_window, GLFW_MOUSE_BUTTON_LEFT) == GLFW_PRESS)
            {
                m_layerDragState.dragging      = true;
                m_layerDragState.draggedLayer  = std::distance(m_activeRenderLayers.begin(), it);
                m_layerDragState.lastItemDelta = 0;
                m_layerDragState.dragStart     = ImGui::GetMousePos();
                m_layerDragState.itemHeight    = btnHeight;
                m_layerDragState.ydelta = m_layerDragState.dragStart.y - ImGui::GetItemRectMin().y;
            }
        }
837
838
839

        if(doIncrement)
            ++it;
Darius Thies's avatar
Darius Thies committed
840
    }
841

842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
    if(m_layerDragState.dragging)
    {
        const float delta = ImGui::GetMousePos().y - m_layerDragState.dragStart.y;
        const int   deltaItem =
                std::clamp<int>(m_layerDragState.draggedLayer +
                                        static_cast<int>(delta / m_layerDragState.itemHeight),
                                0,
                                m_renderer->getRenderLayers().size() - 2) -
                m_layerDragState.draggedLayer;

        std::cout << deltaItem << '\n';
        if(m_layerDragState.lastItemDelta != deltaItem)
        {
            auto startItRot = m_activeRenderLayers.begin() +
                              (m_layerDragState.draggedLayer + m_layerDragState.lastItemDelta);
            auto endItRot =
                    m_activeRenderLayers.begin() + (m_layerDragState.draggedLayer + deltaItem);
            while(startItRot != endItRot)
            {
                if(startItRot > endItRot)
                {
                    std::iter_swap(startItRot, std::prev(startItRot));
                    startItRot = std::prev(startItRot);
                }
                else
                {
                    std::iter_swap(startItRot, std::next(startItRot));
                    startItRot = std::next(startItRot);
                }
            }
            m_layerDragState.lastItemDelta = deltaItem;
        }

        if(glfwGetMouseButton(*m_window, GLFW_MOUSE_BUTTON_LEFT) == GLFW_RELEASE)
        {
            auto startIt = m_activeRenderLayers.begin() + m_layerDragState.draggedLayer;
            auto endIt = m_activeRenderLayers.begin() + (m_layerDragState.draggedLayer + deltaItem);
            // Fix position;
            int offset = 0;
            while(startIt != endIt)
            {
                if(startIt > endIt)
                {
                    std::swap(endIt->indexInRenderer, std::next(endIt)->indexInRenderer);
                    m_renderer->swapLayers(m_layerDragState.draggedLayer - offset,
                                           m_layerDragState.draggedLayer - offset - 1);
                    endIt = std::next(endIt);
                }
                else
                {
                    std::swap(endIt->indexInRenderer, std::prev(endIt)->indexInRenderer);
                    m_renderer->swapLayers(m_layerDragState.draggedLayer + offset,
                                           m_layerDragState.draggedLayer + offset + 1);
                    endIt = std::prev(endIt);
                }
                ++offset;
            }

            m_layerDragState.dragging     = false;
            m_layerDragState.draggedLayer = 0;
            m_layerDragState.dragStart    = ImVec2(0, 0);
            m_layerDragState.itemHeight   = 0;
        }
    }
906
    ImGui::PopStyleColor();
Darius Thies's avatar
Darius Thies committed
907
}
908

909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
void Editor::drawPreview()
{
    int w, h;
    glfwGetFramebufferSize(*m_window, &w, &h);
    w = glm::max(1, w);
    h = glm::max(1, h);

    if(m_previewTexture->size().x != w || m_previewTexture->size().y != h)
    {
        m_windowAspect = float(h) / float(w);
        m_previewFramebuffer->resize({w, h});
        m_previewTexture->resize(GL_TEXTURE_2D, GL_RGBA8, {w, h});
        m_previewFramebuffer->addColorAttachment(0, m_previewTexture);
    }

    ImGui::SetNextWindowSize({m_previewScale, m_previewScale * m_windowAspect});
    ImGui::PushStyleVar(ImGuiStyleVar_WindowPadding, {0, 0});
    ImGui::PushStyleVar(ImGuiStyleVar_WindowRounding, 0);
    ImGui::Begin("Preview", nullptr, ImGuiWindowFlags_NoScrollbar | ImGuiWindowFlags_NoTitleBar);

    m_previewTexture->generateMipmaps();
    m_previewScale = ImGui::GetWindowSize().x;
    ImGui::Image(reinterpret_cast<ImTextureID*>(size_t(m_previewTexture->id())),
                 {m_previewScale, m_previewScale * m_windowAspect},
                 {0, 1},
                 {1, 0});
    ImGui::End();
    ImGui::PopStyleVar(2);
}

939
940
void Editor::drawSettings()
{
Darius Thies's avatar
Darius Thies committed
941
    drawMenuBar();
942
943
944
945
    int w, h;
    glfwGetFramebufferSize(*m_window, &w, &h);
    glBlitNamedFramebuffer(
            0, m_previewFramebuffer->id(), 0, 0, w, h, 0, 0, w, h, GL_COLOR_BUFFER_BIT, GL_NEAREST);
946
947
948

    ImGui::SetNextWindowSize(ImVec2(250, h - m_menuBarHeight));
    ImGui::SetNextWindowPos(ImVec2(0, m_menuBarHeight));
949

Johannes Braun's avatar
Johannes Braun committed
950
951
    ImGui::PushStyleVar(ImGuiStyleVar_WindowPadding, ImVec2(0, 0));
    ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(0, 0));
952
953
954
    ImGui::Begin("Scene");
    {
        enum class Tab
955
        {
956
957
958
959
960
            FIELDS,
            LIGHTS,
            RENDERING
        };
        static int current_tab = 0;
Johannes Braun's avatar
Johannes Braun committed
961
        const auto w           = ImGui::GetWindowWidth() / 3.f;
962
        const auto tab_item    = [w](const char* name, int item, int& current) {
Johannes Braun's avatar
Johannes Braun committed
963
            bool selected = current == item;
Darius Thies's avatar
Darius Thies committed
964
965
            if(selected)
                ImGui::PushStyleColor(ImGuiCol_Button, ImVec4(0, 0, 0, 0));
Johannes Braun's avatar
Johannes Braun committed
966
            if(ImGui::Button(name, ImVec2(w, 0)))
967
                current = item;
Darius Thies's avatar
Darius Thies committed
968
969
            if(selected)
                ImGui::PopStyleColor();
970
971
972
973
974
975
976
977
        };
        tab_item("Fields", 0, current_tab);
        ImGui::SameLine();
        tab_item("Lights", 1, current_tab);
        ImGui::SameLine();
        tab_item("Rendering", 2, current_tab);
        ImGui::PopStyleVar(2);

Darius Thies's avatar
Darius Thies committed
978
        ImGui::BeginChild("CONTENT", ImVec2{}, false, ImGuiWindowFlags_AlwaysUseWindowPadding);
979
980
981
982
        switch(Tab(current_tab))
        {
        case Tab::FIELDS:
            drawFieldsTab();
Darius Thies's avatar
Darius Thies committed
983
            processInputsFields();
984
985
986
            break;
        case Tab::LIGHTS:
            drawLightsTab();
Darius Thies's avatar
Darius Thies committed
987
            processInputsLights();
988
989
990
991
992
            break;
        case Tab::RENDERING:
            drawRenderingTab();
            break;
        }
Darius Thies's avatar
Darius Thies committed
993
        ImGui::EndChild();
994
995
    }
    ImGui::End();
996
    processInputsMain();
997
998
}

Johannes Braun's avatar
Johannes Braun committed
999
1000
void Editor::selectByIndex(uint32_t index)
{
For faster browsing, not all history is shown. View entire blame