Archived
1
Fork 0
This repository has been archived on 2025-04-12. You can view files and clone it, but cannot push or open issues or pull requests.
prism/tools/cutsceneeditor/src/cutsceneeditor.cpp

445 lines
16 KiB
C++
Raw Normal View History

2020-08-11 12:07:21 -04:00
#include "cutsceneeditor.hpp"
#include <imgui.h>
#include <imgui_stdlib.h>
#include <nlohmann/json.hpp>
#include "engine.hpp"
#include "imguipass.hpp"
#include "file.hpp"
#include "json_conversions.hpp"
#include "platform.hpp"
#include "cutscene.hpp"
Shot* currentShot = nullptr;
AnimationChannel* currentChannel = nullptr;
PositionKeyFrame* currentFrame = nullptr;
std::string currentPath;
2021-04-20 10:28:55 -04:00
void app_main(prism::engine* engine) {
2021-10-14 08:51:58 -04:00
auto editor = (CommonEditor*)engine->get_app();
2020-08-11 12:07:21 -04:00
platform::open_window("Cutscene Editor",
{editor->getDefaultX(),
editor->getDefaultY(),
static_cast<uint32_t>(editor->getDefaultWidth()),
static_cast<uint32_t>(editor->getDefaultHeight())}, WindowFlags::Resizable);
}
CutsceneEditor::CutsceneEditor() : CommonEditor("CutsceneEditor") {}
2021-07-18 19:00:36 -04:00
static bool has_been_docked = false;
void CutsceneEditor::renderEditor(GFXCommandBuffer* command_buffer) {
for(auto [id, render_target] : viewport_render_targets) {
engine->get_renderer()->render(command_buffer, render_target.scene, *render_target.target, nullptr);
}
}
2020-08-11 12:07:21 -04:00
void CutsceneEditor::drawUI() {
createDockArea();
2021-07-18 19:00:36 -04:00
2020-08-11 12:07:21 -04:00
const ImGuiID editor_dockspace = ImGui::GetID("dockspace");
ImGui::End();
2021-07-18 19:00:36 -04:00
if(!has_been_docked) {
2020-08-11 12:07:21 -04:00
const auto size = ImGui::GetMainViewport()->Size;
ImGui::DockBuilderRemoveNode(editor_dockspace);
ImGui::DockBuilderAddNode(editor_dockspace, ImGuiDockNodeFlags_DockSpace);
ImGui::DockBuilderSetNodeSize(editor_dockspace, size);
2021-07-18 19:00:36 -04:00
2020-08-11 12:07:21 -04:00
ImGuiID outline_parent, view;
ImGui::DockBuilderSplitNode(editor_dockspace, ImGuiDir_Left, 0.2f, &outline_parent, &view);
ImGuiID outline, playback;
ImGui::DockBuilderSplitNode(outline_parent, ImGuiDir_Down, 0.8f, &outline, &playback);
ImGui::DockBuilderDockWindow("Outliner", outline);
ImGui::DockBuilderDockWindow("Playback Settings", playback);
ImGuiID viewport_parent, properties;
ImGui::DockBuilderSplitNode(view, ImGuiDir_Left, 0.7f, &viewport_parent, &properties);
ImGui::DockBuilderDockWindow("Properties", properties);
ImGuiID lowerbar, viewport;
ImGui::DockBuilderSplitNode(viewport_parent, ImGuiDir_Down, 0.3f, &lowerbar, &viewport);
ImGui::DockBuilderDockWindow("Viewport", viewport);
ImGui::DockBuilderDockWindow("Timeline", lowerbar);
ImGui::DockBuilderDockWindow("Animation Editor", lowerbar);
ImGui::DockBuilderFinish(editor_dockspace);
2021-07-18 19:00:36 -04:00
has_been_docked =true;
2020-08-11 12:07:21 -04:00
}
if (ImGui::BeginMainMenuBar())
{
if (ImGui::BeginMenu("File"))
{
if(ImGui::MenuItem("New", "CTRL+N")) {
engine->cutscene = std::make_unique<Cutscene>();
2021-10-14 08:51:58 -04:00
platform::set_window_title(engine->get_main_window(), "Cutscene Editor");
2020-08-11 12:07:21 -04:00
}
if(ImGui::MenuItem("Open", "CTRL+O")) {
2021-10-14 08:51:58 -04:00
engine->get_imgui().open_dialog(true, [this](std::string path){
2020-08-11 12:07:21 -04:00
currentPath = path;
engine->load_cutscene(path);
2021-10-14 08:51:58 -04:00
platform::set_window_title(engine->get_main_window(), ("Cutscene Editor - " + path).c_str());
2020-08-11 12:07:21 -04:00
addOpenedFile(path);
});
}
const auto& recents = getOpenedFiles();
if (ImGui::BeginMenu("Open Recent...", !recents.empty())) {
for (auto& file : recents) {
if (ImGui::MenuItem(file.c_str())) {
currentPath = file;
engine->load_cutscene(file);
platform::set_window_title(0, ("Cutscene Editor - " + file).c_str());
}
}
ImGui::Separator();
if (ImGui::MenuItem("Clear")) {
clearOpenedFiles();
}
ImGui::EndMenu();
}
if(ImGui::MenuItem("Save", "CTRL+S")) {
if (currentPath.empty()) {
engine->get_imgui().save_dialog([](std::string path) {
2020-08-11 12:07:21 -04:00
currentPath = path;
engine->save_cutscene(path);
platform::set_window_title(0, ("Cutscene Editor - " + path).c_str());
});
}
else {
engine->save_cutscene(currentPath);
}
}
if (ImGui::MenuItem("Save as...", "CTRL+S")) {
engine->get_imgui().save_dialog([](std::string path) {
2020-08-11 12:07:21 -04:00
currentPath = path;
engine->save_cutscene(path);
platform::set_window_title(0, ("Cutscene Editor - " + path).c_str());
});
}
ImGui::Separator();
if(ImGui::MenuItem("Quit", "CTRL+Q"))
engine->quit();
ImGui::EndMenu();
}
if (ImGui::BeginMenu("Edit"))
{
if (ImGui::MenuItem("Undo", "CTRL+Z")) {}
if (ImGui::MenuItem("Redo", "CTRL+Y", false, false)) {} // Disabled item
ImGui::Separator();
if (ImGui::MenuItem("Cut", "CTRL+X")) {}
if (ImGui::MenuItem("Copy", "CTRL+C")) {}
if (ImGui::MenuItem("Paste", "CTRL+V")) {}
ImGui::EndMenu();
}
if(ImGui::BeginMenu("Add...")) {
if (ImGui::MenuItem("Empty")) {
auto new_obj = engine->get_scene()->add_object();
engine->get_scene()->get(new_obj).name = "new object";
}
if(ImGui::MenuItem("Prefab")) {
engine->get_imgui().open_dialog(false, [](std::string path) {
2020-08-11 12:07:21 -04:00
engine->add_prefab(*engine->get_scene(), path);
});
}
ImGui::EndMenu();
}
if (ImGui::BeginMenu("Help")) {
if (ImGui::MenuItem("About")) {
}
ImGui::EndMenu();
}
ImGui::EndMainMenuBar();
}
if(ImGui::Begin("Outliner")) {
drawOutline();
}
ImGui::End();
if(ImGui::Begin("Properties")) {
drawPropertyEditor();
}
ImGui::End();
if(ImGui::Begin("Timeline")) {
if(engine->cutscene != nullptr) {
if(ImGui::Button("Add Shot")) {
2021-10-14 08:51:58 -04:00
engine->cutscene->shots.emplace_back();
2020-08-11 12:07:21 -04:00
currentShot = &engine->cutscene->shots.back();
}
if(currentShot != nullptr) {
ImGui::SameLine();
if(ImGui::Button("Change scene")) {
open_asset<Scene>(AssetType::Scene, [](prism::path path) {
2021-07-19 07:16:55 -04:00
currentShot->scene = engine->load_scene(prism::app_domain / path);
2020-08-11 12:07:21 -04:00
});
}
ImGui::SameLine();
ImGui::SetNextItemWidth(25.0f);
ImGui::DragInt("Begin", &currentShot->begin, 1.0f, 0, 1000);
ImGui::SameLine();
ImGui::SetNextItemWidth(25.0f);
ImGui::DragInt("Length", &currentShot->length, 1.0f, 0, 1000);
ImGui::SameLine();
if(ImGui::Button("Remove")) {
utility::erase(engine->cutscene->shots, *currentShot);
currentShot = nullptr;
}
}
ImGui::Separator();
const auto& draw_list = ImGui::GetWindowDrawList();
const ImVec2 p = ImGui::GetCursorScreenPos();
int i = 0;
for(auto& shot : engine->cutscene->shots) {
auto a = ImVec2(p.x + (5 * shot.begin), p.y);
auto b = ImVec2(p.x + (5 * (shot.begin + shot.length)), p.y + 50);
if(&shot == currentShot) {
draw_list->AddRectFilled(a, b, IM_COL32(0, 0, 100, 100));
}
draw_list->AddRect(a, b, IM_COL32_WHITE);
std::string name = "Shot " + std::to_string(i);
draw_list->AddText(ImVec2(a.x + 2, a.y + 2), IM_COL32_WHITE, name.c_str());
if(ImGui::IsMouseClicked(0)) {
auto c = ImGui::GetMousePos();
if(c.x > a.x && c.x < b.x && c.y > a.y && c.y < b.y) {
if(currentShot == &shot) {
currentShot = nullptr;
} else {
currentShot = &shot;
}
}
}
i++;
}
draw_list->AddLine(ImVec2(p.x + (engine->current_cutscene_time * 5), p.y), ImVec2(p.x + (engine->current_cutscene_time * 5), p.y + 75), IM_COL32_WHITE);
} else {
ImGui::Text("No cutscene loaded.");
}
}
ImGui::End();
if(ImGui::Begin("Animation Editor")) {
if(currentShot != nullptr && currentShot->scene != nullptr) {
ImGui::BeginChild("animations", ImVec2(150, -1), true);
if(ImGui::Button("Add Channel")) {
2021-10-14 08:51:58 -04:00
currentShot->channels.emplace_back();
2020-08-11 12:07:21 -04:00
currentChannel = &currentShot->channels.back();
}
int i = 0;
for(auto& channel : currentShot->channels) {
std::string name = "Channel " + std::to_string(i);
if(ImGui::Selectable(name.c_str(), &channel == currentChannel))
currentChannel = &channel;
i++;
}
if(currentShot->channels.empty())
ImGui::TextDisabled("No channels in this shot.");
ImGui::EndChildFrame();
ImGui::SameLine();
ImGui::BeginChild("editanim", ImVec2(-1, -1), false);
if(currentChannel != nullptr) {
if(ImGui::Button("Add Position Frame")) {
2021-10-14 08:51:58 -04:00
currentChannel->positions.emplace_back();
2020-08-11 12:07:21 -04:00
currentFrame = &currentChannel->positions.back();
}
ImGui::SameLine();
ImGui::SetNextItemWidth(50.0f);
const char* preview_value = "None";
2022-02-18 09:56:48 -05:00
if(currentChannel->target != prism::NullObject && currentShot->scene->has<Data>(currentChannel->target))
2020-08-11 12:07:21 -04:00
preview_value = currentShot->scene->get(currentChannel->target).name.c_str();
if(ImGui::BeginCombo("Target", preview_value)) {
for(auto& object : currentShot->scene->get_objects()) {
if(ImGui::Selectable(currentShot->scene->get(object).name.c_str())) {
currentChannel->target = object;
currentChannel->bone = nullptr;
}
if(currentShot->scene->has<Renderable>(object) && !currentShot->scene->get<Renderable>(object).mesh->bones.empty()) {
ImGui::Indent();
for(auto& bone : currentShot->scene->get<Renderable>(object).mesh->bones) {
if(ImGui::Selectable(bone.name.c_str())) {
currentChannel->bone = &bone;
2022-02-18 09:56:48 -05:00
currentChannel->target = prism::NullObject;
2020-08-11 12:07:21 -04:00
}
}
ImGui::Unindent();
}
}
ImGui::EndCombo();
}
ImGui::SameLine();
if(ImGui::Button("Remove Channel")) {
utility::erase(currentShot->channels, *currentChannel);
currentChannel = nullptr;
}
if(currentFrame != nullptr) {
ImGui::SameLine();
ImGui::SetNextItemWidth(10.0f);
ImGui::DragFloat("FT", &currentFrame->time, 1.0f, 0.0f, 10000.0f);
ImGui::SameLine();
ImGui::SetNextItemWidth(50.0f);
ImGui::DragFloat3("FV", currentFrame->value.ptr());
ImGui::SameLine();
if(ImGui::Button("Remove Keyframe")) {
utility::erase(currentChannel->positions, *currentFrame);
currentFrame = nullptr;
}
}
if(currentChannel != nullptr) {
const auto& draw_list = ImGui::GetWindowDrawList();
const ImVec2 p = ImGui::GetCursorScreenPos();
for(auto& keyframe : currentChannel->positions) {
ImVec2 c = ImVec2(p.x + (keyframe.time * 5), p.y);
if(&keyframe == currentFrame)
draw_list->AddCircleFilled(c, 5.0f, IM_COL32(0, 0, 100, 255));
draw_list->AddCircle(c, 5.0f, IM_COL32_WHITE);
if(ImGui::IsMouseClicked(0)) {
ImVec2 a = ImVec2(p.x + (keyframe.time * 5) - 5, p.y - 5);
ImVec2 b = ImVec2(p.x + (keyframe.time * 5) + 5, p.y + 5);
2021-10-14 08:51:58 -04:00
auto mouse_pos = ImGui::GetMousePos();
if(mouse_pos.x > a.x && mouse_pos.x < b.x && mouse_pos.y > a.y && mouse_pos.y < b.y) {
2020-08-11 12:07:21 -04:00
if(currentFrame == &keyframe) {
currentFrame = nullptr;
} else {
currentFrame = &keyframe;
}
}
}
}
ImVec2 shot_start = ImVec2(p.x + (currentShot->begin * 5), p.y + 10.0f);
ImVec2 shot_end = ImVec2(p.x + (currentShot->length * 5), p.y + 10.0f);
draw_list->AddCircleFilled(shot_start, 2.5f, IM_COL32(255, 0, 0, 255));
draw_list->AddCircleFilled(shot_end, 2.5f, IM_COL32(255, 0, 0, 255));
draw_list->AddLine(ImVec2(p.x + ((engine->current_cutscene_time - currentShot->begin) * 5), p.y), ImVec2(p.x + ((engine->current_cutscene_time - currentShot->begin) * 5), p.y + 75), IM_COL32_WHITE);
}
} else {
ImGui::TextDisabled("No animation selected.");
}
ImGui::EndChild();
} else {
ImGui::TextDisabled("No shot selected.");
}
}
ImGui::End();
if(ImGui::Begin("Playback Settings")) {
if(ImGui::Button(engine->play_cutscene ? "Stop" : "Play")) {
engine->play_cutscene = !engine->play_cutscene;
}
ImGui::DragFloat("Time", &engine->current_cutscene_time, 1.0f, 0.0f, 1000.0f);
}
ImGui::End();
if(ImGui::Begin("Viewport")) {
2021-10-12 10:26:40 -04:00
if(currentShot != nullptr && currentShot->scene != nullptr)
drawViewport(currentShot->scene);
2020-08-11 12:07:21 -04:00
}
ImGui::End();
if(ImGui::IsKeyPressed(ImGui::GetKeyIndex(ImGuiKey_LeftArrow)))
engine->current_cutscene_time -= 1.0f;
if(ImGui::IsKeyPressed(ImGui::GetKeyIndex(ImGuiKey_RightArrow)))
engine->current_cutscene_time += 1.0f;
}