From 41b52e3532d4d746a0629a402064346ed4f92e57 Mon Sep 17 00:00:00 2001 From: Anthony Rabine Date: Sat, 23 Dec 2023 14:33:05 +0100 Subject: [PATCH] better event, better audio, add QOI to emulator, emulator is executed --- software/chip32/chip32_vm.h | 1 + .../library/{miniaudio.c => audio_player.cpp} | 94 ++++-- software/library/audio_player.h | 47 +++ .../src => software/library}/json.hpp | 0 .../src => software/library}/resource.h | 0 .../library}/resource_manager.h | 0 .../library}/story_project.cpp | 43 +-- .../src => software/library}/story_project.h | 49 +-- .../src => software/library}/thread_pool.hpp | 0 software/library/thread_safe_queue.h | 52 +++ {story-editor/src => software/library}/uuid.h | 0 story-editor/CMakeLists.txt | 22 +- .../libs/ImGuiColorTextEdit/TextEditor.cpp | 25 +- .../libs/ImGuiColorTextEdit/TextEditor.h | 14 +- story-editor/src/base_node.cpp | 4 +- story-editor/src/base_node.h | 6 +- story-editor/src/code_editor.cpp | 4 +- story-editor/src/code_editor.h | 5 + story-editor/src/emulator_window.cpp | 48 ++- story-editor/src/emulator_window.h | 11 +- story-editor/src/gui.cpp | 58 +++- .../{i_story_project.h => i_story_manager.h} | 15 +- story-editor/src/main_window.cpp | 302 ++++++++++++++++-- story-editor/src/main_window.h | 40 ++- story-editor/src/media_node.cpp | 22 +- story-editor/src/media_node.h | 6 +- story-editor/src/node_editor_window.cpp | 8 +- story-editor/src/node_editor_window.h | 12 +- story-editor/src/resources_window.cpp | 12 +- story-editor/src/resources_window.h | 6 +- 30 files changed, 690 insertions(+), 216 deletions(-) rename software/library/{miniaudio.c => audio_player.cpp} (58%) create mode 100644 software/library/audio_player.h rename {story-editor/src => software/library}/json.hpp (100%) rename {story-editor/src => software/library}/resource.h (100%) rename {story-editor/src => software/library}/resource_manager.h (100%) rename {story-editor/src => software/library}/story_project.cpp (91%) rename {story-editor/src => software/library}/story_project.h (80%) rename {story-editor/src => software/library}/thread_pool.hpp (100%) create mode 100644 software/library/thread_safe_queue.h rename {story-editor/src => software/library}/uuid.h (100%) rename story-editor/src/{i_story_project.h => i_story_manager.h} (79%) diff --git a/software/chip32/chip32_vm.h b/software/chip32/chip32_vm.h index ebd93eb..0dc9d65 100644 --- a/software/chip32/chip32_vm.h +++ b/software/chip32/chip32_vm.h @@ -130,6 +130,7 @@ typedef enum typedef enum { + VM_READY, // VM Ready to be started VM_FINISHED, // execution completed (i.e. got halt instruction) VM_SKIPED, // skipped instruction VM_WAIT_EVENT, // execution paused since we hit the maximum instructions diff --git a/software/library/miniaudio.c b/software/library/audio_player.cpp similarity index 58% rename from software/library/miniaudio.c rename to software/library/audio_player.cpp index 5091335..e60112d 100644 --- a/software/library/miniaudio.c +++ b/software/library/audio_player.cpp @@ -13,10 +13,14 @@ the simple_mixing example for how best to do this. #define MINIAUDIO_IMPLEMENTATION #include "miniaudio.h" +#include #include +#include "audio_player.h" -ma_event g_stopEvent; /* <-- Signaled by the audio thread, waited on by the main thread. */ +static ThreadSafeQueue g_audioQueue; +static ma_decoder decoder; +static ma_device device; void data_callback(ma_device* pDevice, void* pOutput, const void* pInput, ma_uint32 frameCount) { @@ -27,21 +31,24 @@ void data_callback(ma_device* pDevice, void* pOutput, const void* pInput, ma_uin ma_uint64 framesRead; ma_result result = ma_decoder_read_pcm_frames(pDecoder, pOutput, frameCount, &framesRead); - - if (framesRead < frameCount) { - // Reached the end. - ma_event_signal(&g_stopEvent); + + + if (result == MA_AT_END) { + g_audioQueue.push({"end", ""}); } + // if (framesRead < frameCount) { + // // Reached the end. + // ma_event_signal(&g_stopEvent); + // } (void)pInput; } -int miniaudio_play(const char* filename) + +static int miniaudio_play(const char* filename) { ma_result result; - ma_decoder decoder; ma_device_config deviceConfig; - ma_device device; result = ma_decoder_init_file(filename, NULL, &decoder); if (result != MA_SUCCESS) { @@ -61,8 +68,6 @@ int miniaudio_play(const char* filename) ma_decoder_uninit(&decoder); return -3; } - - ma_event_init(&g_stopEvent); if (ma_device_start(&device) != MA_SUCCESS) { printf("Failed to start playback device.\n"); @@ -71,14 +76,67 @@ int miniaudio_play(const char* filename) return -4; } - printf("Wait untile end...\n"); - // getchar(); - ma_event_wait(&g_stopEvent); - printf("End!\n"); - - ma_device_uninit(&device); - ma_decoder_uninit(&decoder); - return 0; } +AudioPlayer::AudioPlayer(IAudioEvent &event) + : m_event(event) +{ + m_audioThread = std::thread( std::bind(&AudioPlayer::AudioThread, this) ); +} + +void AudioPlayer::Play(const std::string &filename) +{ + g_audioQueue.push({"play", filename}); +} + +AudioPlayer::~AudioPlayer() +{ + // Quit audio thread + g_audioQueue.push({"quit", ""}); + if (m_audioThread.joinable()) + { + m_audioThread.join(); + } +} + +void AudioPlayer::CloseAudio() +{ + ma_device_uninit(&device); + ma_decoder_uninit(&decoder); +} + +#define AUDIO_STATE_WAIT_PLAY 1 +#define AUDIO_STATE_WAIT_END 2 + +void AudioPlayer::AudioThread() +{ + int state = AUDIO_STATE_WAIT_PLAY; + for (;;) + { + auto cmd = g_audioQueue.front(); + g_audioQueue.pop(); + + if (cmd.order == "quit") { + return; + } + else if (cmd.order == "play") + { + if (state == AUDIO_STATE_WAIT_PLAY) + { + state = AUDIO_STATE_WAIT_END; + miniaudio_play(cmd.filename.c_str()); + } + } + else if (cmd.order == "end") + { + if (state == AUDIO_STATE_WAIT_END) + { + state = AUDIO_STATE_WAIT_PLAY; + CloseAudio(); + m_event.EndOfAudio(); + } + } + } +} + diff --git a/software/library/audio_player.h b/software/library/audio_player.h new file mode 100644 index 0000000..72ec5a6 --- /dev/null +++ b/software/library/audio_player.h @@ -0,0 +1,47 @@ +#ifndef AUDIO_PLAYER_H +#define AUDIO_PLAYER_H + +#include "miniaudio.h" +#include +#include +#include +#include +#include +#include +#include "thread_safe_queue.h" + + +struct AudioCommand { + std::string order; + std::string filename; +}; + +class IAudioEvent +{ +public: + virtual ~IAudioEvent() {} + + virtual void EndOfAudio() = 0; +}; + + +class AudioPlayer +{ +public: + + AudioPlayer(IAudioEvent &event); + ~AudioPlayer(); + + void Play(const std::string &filename); + +private: + IAudioEvent &m_event; + + std::thread m_audioThread; + + void AudioThread(); + void CloseAudio(); +}; + + +#endif // AUDIO_PLAYER_H diff --git a/story-editor/src/json.hpp b/software/library/json.hpp similarity index 100% rename from story-editor/src/json.hpp rename to software/library/json.hpp diff --git a/story-editor/src/resource.h b/software/library/resource.h similarity index 100% rename from story-editor/src/resource.h rename to software/library/resource.h diff --git a/story-editor/src/resource_manager.h b/software/library/resource_manager.h similarity index 100% rename from story-editor/src/resource_manager.h rename to software/library/resource_manager.h diff --git a/story-editor/src/story_project.cpp b/software/library/story_project.cpp similarity index 91% rename from story-editor/src/story_project.cpp rename to software/library/story_project.cpp index eab9b18..bb8c548 100644 --- a/story-editor/src/story_project.cpp +++ b/software/library/story_project.cpp @@ -4,21 +4,16 @@ #include #include #include + #include "json.hpp" StoryProject::StoryProject() { - m_audioThread = std::thread( std::bind(&StoryProject::AudioThread, this) ); + } StoryProject::~StoryProject() { - // Quit audio thread - m_audioQueue.push({"quit", ""}); - if (m_audioThread.joinable()) - { - m_audioThread.join(); - } } @@ -100,7 +95,7 @@ void StoryProject::SaveStory(const std::vector &m_program) void StoryProject::Initialize(const std::string &file_path) { - m_project_file_path = file_path; + m_story_file_path = file_path; std::filesystem::path p(file_path); m_working_dir= p.parent_path().generic_string(); @@ -243,7 +238,7 @@ void StoryProject::Save(const nlohmann::json &model, ResourceManager &manager) { nlohmann::json resourcesData; - auto [b, e] = manager.filter(""); + auto [b, e] = manager.Items(); for (auto it = b; it != e; ++it) { nlohmann::json obj = {{"type", (*it)->type}, @@ -258,7 +253,7 @@ void StoryProject::Save(const nlohmann::json &model, ResourceManager &manager) j["nodegraph"] = model; - std::ofstream o(m_project_file_path); + std::ofstream o(m_story_file_path); o << std::setw(4) << j << std::endl; } @@ -364,32 +359,6 @@ std::string StoryProject::GetFileExtension(const std::string &fileName) return ""; } -extern "C" int miniaudio_play(const char* filename); - -void StoryProject::AudioThread() -{ - for (;;) - { - auto cmd = m_audioQueue.front(); - - if (cmd.order == "play") { - miniaudio_play(cmd.filename.c_str()); - // QMetaObject::invokeMethod(this, "sigAudioStopped", Qt::QueuedConnection); - m_audioQueue.pop(); - } else { - return; - } - } -} - -void StoryProject::PlaySoundFile(const std::string &fileName) -{ - m_audioQueue.push({"play", fileName}); -} - - - - void StoryProject::SetImageFormat(ImageFormat format) { m_imageFormat = format; @@ -408,7 +377,7 @@ void StoryProject::SetDisplayFormat(int w, int h) std::string StoryProject::GetProjectFilePath() const { - return m_project_file_path; + return m_story_file_path; } std::string StoryProject::GetWorkingDir() const diff --git a/story-editor/src/story_project.h b/software/library/story_project.h similarity index 80% rename from story-editor/src/story_project.h rename to software/library/story_project.h index 392b035..a353c24 100644 --- a/story-editor/src/story_project.h +++ b/software/library/story_project.h @@ -5,47 +5,13 @@ #include #include #include "json.hpp" -#include -#include + #include #include -#include -#include + #include "json.hpp" #include "resource_manager.h" - -template -class ThreadSafeQueue { - std::mutex mutex; - std::condition_variable cond_var; - std::queue queue; - -public: - void push(T&& item) { - { - std::lock_guard lock(mutex); - queue.push(item); - } - - cond_var.notify_one(); - } - - T& front() { - std::unique_lock lock(mutex); - cond_var.wait(lock, [&]{ return !queue.empty(); }); - return queue.front(); - } - - void pop() { - std::lock_guard lock(mutex); - queue.pop(); - } -}; - -struct AudioCommand { - std::string order; - std::string filename; -}; +#include "audio_player.h" @@ -141,9 +107,8 @@ public: static void EraseString(std::string &theString, const std::string &toErase); static std::string ToUpper(const std::string &input); - void SaveStory(const std::vector &m_program); - void PlaySoundFile(const std::string &fileName); + private: // Project properties and location std::string m_name; /// human readable name @@ -156,17 +121,13 @@ private: std::string m_titleSound; std::filesystem::path m_working_dir; /// Temporary folder based on the uuid, where the archive is unzipped - std::string m_project_file_path; /// JSON project file + std::string m_story_file_path; /// JSON project file int m_display_w{320}; int m_display_h{240}; - std::thread m_audioThread; - ThreadSafeQueue m_audioQueue; - ImageFormat m_imageFormat{IMG_FORMAT_BMP_4BITS}; SoundFormat m_soundFormat{SND_FORMAT_WAV}; - void AudioThread(); }; #endif // STORY_PROJECT_H diff --git a/story-editor/src/thread_pool.hpp b/software/library/thread_pool.hpp similarity index 100% rename from story-editor/src/thread_pool.hpp rename to software/library/thread_pool.hpp diff --git a/software/library/thread_safe_queue.h b/software/library/thread_safe_queue.h new file mode 100644 index 0000000..28cd42d --- /dev/null +++ b/software/library/thread_safe_queue.h @@ -0,0 +1,52 @@ +#ifndef THREAD_SAFE_QUEUE_H +#define THREAD_SAFE_QUEUE_H + +#include +#include +#include +#include + +template +class ThreadSafeQueue { + std::mutex mutex; + std::condition_variable cond_var; + std::queue queue; + +public: + void push(T&& item) { + { + std::lock_guard lock(mutex); + queue.push(item); + } + + cond_var.notify_one(); + } + + T& front() { + std::unique_lock lock(mutex); + cond_var.wait(lock, [&]{ return !queue.empty(); }); + return queue.front(); + } + + void pop() { + std::lock_guard lock(mutex); + queue.pop(); + } + + bool try_pop(T& popped_item) { + std::unique_lock lock(mutex); + + if (queue.empty()) { + return false; // La file d'attente est vide + } + + popped_item = std::move(queue.front()); + queue.pop(); + + return true; + } +}; + + + +#endif // THREAD_SAFE_QUEUE_H diff --git a/story-editor/src/uuid.h b/software/library/uuid.h similarity index 100% rename from story-editor/src/uuid.h rename to software/library/uuid.h diff --git a/story-editor/CMakeLists.txt b/story-editor/CMakeLists.txt index a42339d..749a9b0 100644 --- a/story-editor/CMakeLists.txt +++ b/story-editor/CMakeLists.txt @@ -131,10 +131,10 @@ set(SRCS src/connection.cpp src/connection.h - src/uuid.h - src/resource_manager.h - src/i_story_project.h - src/resource.h + src/media_converter.cpp + src/media_converter.h + + src/i_story_manager.h libs/ImGuiColorTextEdit/TextEditor.cpp libs/ImGuiColorTextEdit/TextEditor.h @@ -155,13 +155,15 @@ set(SRCS ../software/chip32/chip32_assembler.cpp ../software/chip32/chip32_vm.c - ../software/library/miniaudio.c + ../software/library/audio_player.cpp + ../software/library/audio_player.h ../software/library/miniaudio.h - - src/story_project.cpp - src/story_project.h - src/media_converter.cpp - src/media_converter.h + ../software/library/uuid.h + ../software/library/resource.h + ../software/library/resource_manager.h + ../software/library/story_project.cpp + ../software/library/story_project.h + ../software/library/thread_safe_queue.h ) if(WIN32) diff --git a/story-editor/libs/ImGuiColorTextEdit/TextEditor.cpp b/story-editor/libs/ImGuiColorTextEdit/TextEditor.cpp index d375392..5b07602 100644 --- a/story-editor/libs/ImGuiColorTextEdit/TextEditor.cpp +++ b/story-editor/libs/ImGuiColorTextEdit/TextEditor.cpp @@ -26,7 +26,8 @@ bool equals(InputIt1 first1, InputIt1 last1, TextEditor::TextEditor() : mLineSpacing(1.0f) - , mUndoIndex(0) + , mUndoIndex(0) + , mExternalUndoBuffer(nullptr) , mTabSize(4) , mOverwrite(false) , mReadOnly(false) @@ -41,15 +42,10 @@ TextEditor::TextEditor() , mColorRangeMin(0) , mColorRangeMax(0) , mSelectionMode(SelectionMode::Normal) - , mCheckComments(true) - , mLastClick(-1.0f) - , mHandleKeyboardInputs(true) - , mHandleMouseInputs(true) - , mIgnoreImGuiChild(false) - , mShowWhitespaces(true) - , mShowShortTabGlyphs(false) - , mStartTime(std::chrono::duration_cast(std::chrono::system_clock::now().time_since_epoch()).count()) - , mExternalUndoBuffer(nullptr) + , mShowShortTabGlyphs(false) + , mCheckComments(true) + , mStartTime(std::chrono::duration_cast(std::chrono::system_clock::now().time_since_epoch()).count()) + , mLastClick(-1.0f) { SetPalette(GetDarkPalette()); SetLanguageDefinition(LanguageDefinition::HLSL()); @@ -981,6 +977,15 @@ void TextEditor::Render() } } + + // Draw execution marker + if (mExecutionMarker == (lineNo + 1)) + { + auto end = ImVec2(lineStartScreenPos.x + contentSize.x + 2.0f * scrollX, lineStartScreenPos.y + mCharAdvance.y); + drawList->AddRectFilled(start, end, mPalette[(int)PaletteIndex::Selection]); + } + + // Draw line number (right aligned) snprintf(buf, 16, "%d ", lineNo + 1); diff --git a/story-editor/libs/ImGuiColorTextEdit/TextEditor.h b/story-editor/libs/ImGuiColorTextEdit/TextEditor.h index dd072d0..25eec72 100644 --- a/story-editor/libs/ImGuiColorTextEdit/TextEditor.h +++ b/story-editor/libs/ImGuiColorTextEdit/TextEditor.h @@ -247,6 +247,10 @@ public: void SetErrorMarkers(const ErrorMarkers& aMarkers) { mErrorMarkers = aMarkers; } void SetBreakpoints(const Breakpoints& aMarkers) { mBreakpoints = aMarkers; } + void SetExecutionMarker(int line) { + mExecutionMarker = line; + } + void Render(const char* aTitle, const ImVec2& aSize = ImVec2(), bool aBorder = false); void SetText(const std::string& aText); std::string GetText() const; @@ -386,10 +390,10 @@ private: bool mCursorPositionChanged; int mColorRangeMin, mColorRangeMax; SelectionMode mSelectionMode; - bool mHandleKeyboardInputs; - bool mHandleMouseInputs; - bool mIgnoreImGuiChild; - bool mShowWhitespaces; + bool mHandleKeyboardInputs{true}; + bool mHandleMouseInputs{true}; + bool mIgnoreImGuiChild{false}; + bool mShowWhitespaces{true}; bool mShowShortTabGlyphs; Palette mPaletteBase; @@ -404,6 +408,6 @@ private: Coordinates mInteractiveStart, mInteractiveEnd; std::string mLineBuffer; uint64_t mStartTime; - float mLastClick; + int mExecutionMarker{-1}; }; diff --git a/story-editor/src/base_node.cpp b/story-editor/src/base_node.cpp index b6817a0..a824c1a 100644 --- a/story-editor/src/base_node.cpp +++ b/story-editor/src/base_node.cpp @@ -5,8 +5,8 @@ unsigned long BaseNode::s_nextId = 1; -BaseNode::BaseNode(const std::string &title, IStoryProject &proj) - : m_project(proj) +BaseNode::BaseNode(const std::string &title, IStoryManager &proj) + : m_story(proj) { // m_id = UUID().String(); diff --git a/story-editor/src/base_node.h b/story-editor/src/base_node.h index 4565ab9..a989385 100644 --- a/story-editor/src/base_node.h +++ b/story-editor/src/base_node.h @@ -7,7 +7,7 @@ #include #include "json.hpp" -#include "i_story_project.h" +#include "i_story_manager.h" #include namespace ed = ax::NodeEditor; @@ -101,7 +101,7 @@ public: float y; }; - BaseNode(const std::string &title, IStoryProject &proj); + BaseNode(const std::string &title, IStoryManager &proj); virtual void Draw() = 0; @@ -223,7 +223,7 @@ public: void DeleteOutput(); private: - IStoryProject &m_project; + IStoryManager &m_story; std::unique_ptr m_node; diff --git a/story-editor/src/code_editor.cpp b/story-editor/src/code_editor.cpp index 37b07ce..d4abbf8 100644 --- a/story-editor/src/code_editor.cpp +++ b/story-editor/src/code_editor.cpp @@ -18,8 +18,8 @@ void CodeEditor::Initialize() // "breakpoint" markers - m_breakPoints.insert(42); - mEditor.SetBreakpoints(m_breakPoints); + // m_breakPoints.insert(42); + // mEditor.SetBreakpoints(m_breakPoints); } diff --git a/story-editor/src/code_editor.h b/story-editor/src/code_editor.h index 86b06e8..8bdcb0d 100644 --- a/story-editor/src/code_editor.h +++ b/story-editor/src/code_editor.h @@ -15,6 +15,11 @@ public: void SetScript(const std::string &txt); void ClearErrors(); void AddError(int line, const std::string &text); + + void HighlightLine(int line) + { + mEditor.SetExecutionMarker(line); + } private: TextEditor mEditor; TextEditor::Breakpoints m_breakPoints; diff --git a/story-editor/src/emulator_window.cpp b/story-editor/src/emulator_window.cpp index d4a5eb0..475116a 100644 --- a/story-editor/src/emulator_window.cpp +++ b/story-editor/src/emulator_window.cpp @@ -2,9 +2,9 @@ #include "gui.h" #include "IconsMaterialDesignIcons.h" -EmulatorWindow::EmulatorWindow(IStoryProject &proj) +EmulatorWindow::EmulatorWindow(IStoryManager &proj) : WindowBase("Emulator") - , m_project(proj) + , m_story(proj) { } @@ -31,8 +31,17 @@ void EmulatorWindow::Draw() // ImGui::Image((void*)(intptr_t)my_image_texture, ImVec2(313, 367)); // float sz = ImGui::GetTextLineHeight(); + ImVec2 p = ImGui::GetCursorScreenPos(); - ImGui::GetWindowDrawList()->AddRectFilled(p, ImVec2(p.x + 320, p.y + 240), ImGui::GetColorU32(ImVec4(1.0, 1.0, 1.0, 1.0))); + + if (m_image.Valid()) + { + ImGui::Image(m_image.texture, ImVec2(320, 240)); + } + else + { + ImGui::GetWindowDrawList()->AddRectFilled(p, ImVec2(p.x + 320, p.y + 240), ImGui::GetColorU32(ImVec4(1.0, 1.0, 1.0, 1.0))); + } ImGui::SetCursorScreenPos(ImVec2(p.x, p.y + 244)); @@ -42,13 +51,25 @@ void EmulatorWindow::Draw() ImGui::PushFont(ImGui::GetFont()); - ImGui::Button(ICON_MDI_PLAY_CIRCLE_OUTLINE, ImVec2(50, 50)); + if (ImGui::Button(ICON_MDI_PLAY_CIRCLE_OUTLINE, ImVec2(50, 50))) + { + m_story.Play(); + } ImGui::SameLine(); - ImGui::Button(ICON_MDI_STOP_CIRCLE_OUTLINE, ImVec2(50, 50)); + if (ImGui::Button(ICON_MDI_STOP_CIRCLE_OUTLINE, ImVec2(50, 50))) + { + m_story.Pause(); + } ImGui::SameLine(); - ImGui::Button(ICON_MDI_ARROW_LEFT_BOLD_CIRCLE_OUTLINE, ImVec2(50, 50)); + if (ImGui::Button(ICON_MDI_ARROW_LEFT_BOLD_CIRCLE_OUTLINE, ImVec2(50, 50))) + { + m_story.Previous(); + } ImGui::SameLine(); - ImGui::Button(ICON_MDI_ARROW_RIGHT_BOLD_CIRCLE_OUTLINE, ImVec2(50, 50)); + if (ImGui::Button(ICON_MDI_ARROW_RIGHT_BOLD_CIRCLE_OUTLINE, ImVec2(50, 50))) + { + m_story.Next(); + } ImGui::GetFont()->Scale = old_size; ImGui::PopFont(); @@ -57,9 +78,20 @@ void EmulatorWindow::Draw() if (ImGui::Button("Build")) { - m_project.Build(); + m_story.Build(); } ImGui::SameLine(); WindowBase::EndDraw(); } + +void EmulatorWindow::ClearImage() +{ + m_image.Clear(); +} + +void EmulatorWindow::SetImage(const std::string &image) +{ + m_image.name = image; + m_image.Load(m_story.BuildFullAssetsPath(image)); +} diff --git a/story-editor/src/emulator_window.h b/story-editor/src/emulator_window.h index d2c5594..c7f790e 100644 --- a/story-editor/src/emulator_window.h +++ b/story-editor/src/emulator_window.h @@ -1,17 +1,22 @@ #pragma once #include "window_base.h" -#include "i_story_project.h" +#include "i_story_manager.h" +#include "gui.h" class EmulatorWindow : public WindowBase { public: - EmulatorWindow(IStoryProject &proj); + EmulatorWindow(IStoryManager &proj); void Initialize(); virtual void Draw() override; + void ClearImage(); + void SetImage(const std::string &image); + private: - IStoryProject &m_project; + IStoryManager &m_story; + Gui::Image m_image; }; diff --git a/story-editor/src/gui.cpp b/story-editor/src/gui.cpp index 46a5c53..e454ad2 100644 --- a/story-editor/src/gui.cpp +++ b/story-editor/src/gui.cpp @@ -22,6 +22,7 @@ your use of the corresponding standard functions. #include "IconsMaterialDesignIcons.h" #include "IconsFontAwesome5_c.h" +#include "qoi.h" static void glfw_error_callback(int error, const char* description) { @@ -34,24 +35,59 @@ static SDL_Renderer* renderer{nullptr}; #include "stb_image.h" +static std::string GetFileExtension(const std::string &fileName) +{ + if(fileName.find_last_of(".") != std::string::npos) + return fileName.substr(fileName.find_last_of(".")+1); + return ""; +} + // Simple helper function to load an image into a OpenGL texture with common settings bool LoadTextureFromFile(const char* filename, Gui::Image &img) { - int channels; - unsigned char* data = stbi_load(filename, &img.w, &img.h, &channels, 0); - if (data == nullptr) { - fprintf(stderr, "Failed to load image: %s\n", stbi_failure_reason()); - return false; + + std::string ext = GetFileExtension(filename); + + SDL_Surface* surface = nullptr; + + if (ext == "qoi") + { + qoi_desc desc; + void *pixels = qoi_read(filename, &desc, 0); + unsigned int channels = desc.channels; + img.w = desc.width; + img.h = desc.height; + + surface = SDL_CreateRGBSurfaceFrom((void*)pixels, img.w, img.h, channels * 8, channels * img.w, + 0x000000ff, 0x0000ff00, 0x00ff0000, 0xff000000); + + if (pixels != NULL) + { + free(pixels); + } } + else + { + unsigned char* data = nullptr; + int channels; + data = stbi_load(filename, &img.w, &img.h, &channels, 0); - // SDL3 -// SDL_Surface* surface = SDL_CreateSurfaceFrom((void*)data, img.w, img.h, 4 * img.w, SDL_PIXELFORMAT_RGBA8888); + if (data == nullptr) { + fprintf(stderr, "Failed to load image: %s\n", stbi_failure_reason()); + return false; + } - // SDL2 - SDL_Surface* surface = SDL_CreateRGBSurfaceFrom((void*)data, img.w, img.h, channels * 8, channels * img.w, - 0x000000ff, 0x0000ff00, 0x00ff0000, 0xff000000); + + // SDL3 + // SDL_Surface* surface = SDL_CreateSurfaceFrom((void*)data, img.w, img.h, 4 * img.w, SDL_PIXELFORMAT_RGBA8888); + + // SDL2 + surface = SDL_CreateRGBSurfaceFrom((void*)data, img.w, img.h, channels * 8, channels * img.w, + 0x000000ff, 0x0000ff00, 0x00ff0000, 0xff000000); + stbi_image_free(data); + } if (surface == nullptr) { @@ -67,7 +103,7 @@ bool LoadTextureFromFile(const char* filename, Gui::Image &img) // SDL_DestroySurface(surface); // SDL3 SDL_FreeSurface(surface); // SDL2 - stbi_image_free(data); + return true; } diff --git a/story-editor/src/i_story_project.h b/story-editor/src/i_story_manager.h similarity index 79% rename from story-editor/src/i_story_project.h rename to story-editor/src/i_story_manager.h index f51ccf3..7584895 100644 --- a/story-editor/src/i_story_project.h +++ b/story-editor/src/i_story_manager.h @@ -1,5 +1,5 @@ -#ifndef I_STORY_PROJECT_H -#define I_STORY_PROJECT_H +#ifndef I_STORY_MANAGER_H +#define I_STORY_MANAGER_H #include @@ -10,10 +10,10 @@ #include "resource.h" #include "connection.h" -class IStoryProject +class IStoryManager { public: - virtual ~IStoryProject() {} + virtual ~IStoryManager() {} virtual void Log(const std::string &txt, bool critical = false) = 0; virtual void PlaySoundFile(const std::string &fileName) = 0; @@ -31,7 +31,12 @@ public: virtual void Build() = 0; virtual std::list> GetNodeConnections(unsigned long nodeId) = 0; virtual std::string GetNodeEntryLabel(unsigned long nodeId) = 0; + virtual void Play() = 0; + virtual void Pause() = 0; + virtual void Next() = 0; + virtual void Previous() = 0; + }; -#endif // I_STORY_PROJECT_H +#endif // I_STORY_MANAGER_H diff --git a/story-editor/src/main_window.cpp b/story-editor/src/main_window.cpp index b193011..6461746 100644 --- a/story-editor/src/main_window.cpp +++ b/story-editor/src/main_window.cpp @@ -4,6 +4,7 @@ #include "platform_folders.h" #include "uuid.h" +#include "media_converter.h" #ifdef USE_WINDOWS_OS #include @@ -22,9 +23,24 @@ MainWindow::MainWindow() : m_emulatorWindow(*this) , m_resourcesWindow(*this) , m_nodeEditorWindow(*this) - + , m_player(*this) { - m_project.Clear(); + + // VM Initialize + m_chip32_ctx.stack_size = 512; + + m_chip32_ctx.rom.mem = m_rom_data; + m_chip32_ctx.rom.addr = 0; + m_chip32_ctx.rom.size = sizeof(m_rom_data); + + m_chip32_ctx.ram.mem = m_ram_data; + m_chip32_ctx.ram.addr = sizeof(m_rom_data); + m_chip32_ctx.ram.size = sizeof(m_ram_data); + + Callback::func = std::bind(&MainWindow::Syscall, this, std::placeholders::_1, std::placeholders::_2); + m_chip32_ctx.syscall = static_cast(Callback::callback); + + m_story.Clear(); } MainWindow::~MainWindow() @@ -32,6 +48,194 @@ MainWindow::~MainWindow() } + +std::string MainWindow::GetFileNameFromMemory(uint32_t addr) +{ + char strBuf[100]; + bool isRam = addr & 0x80000000; + addr &= 0xFFFF; // mask the RAM/ROM bit, ensure 16-bit addressing + if (isRam) { + strcpy(&strBuf[0], (const char *)&m_chip32_ctx.ram.mem[addr]); + } else { + strcpy(&strBuf[0], (const char *)&m_chip32_ctx.rom.mem[addr]); + } + return strBuf; +} + +/* +void MainWindow::EventFinished(uint32_t replyEvent) +{ + if (m_dbg.run_result == VM_WAIT_EVENT) + { + // Result event is in R0 + m_chip32_ctx.registers[R0] = replyEvent; + m_dbg.run_result = VM_OK; + + if (m_dbg.free_run) + { + m_runTimer->start(100); + } + else + { + stepInstruction(); + } + } +}*/ + + +void MainWindow::Play() +{ + if (m_dbg.run_result == VM_FINISHED) + { + Build(); + + if (m_dbg.run_result == VM_READY) + { + m_dbg.free_run = true; + m_dbg.run_result = VM_OK; // actually starts the execution + } + } +} + +void MainWindow::Pause() +{ + +} + +void MainWindow::Next() +{ + +} + +void MainWindow::Previous() +{ + +} + +void MainWindow::EndOfAudio() +{ + Log("End of audio track"); + m_eventQueue.push({VmEventType::EvAudioFinished}); +} + +void MainWindow::StepInstruction() +{ + m_dbg.run_result = chip32_step(&m_chip32_ctx); + UpdateVmView(); +} + +void MainWindow::ProcessStory() +{ + if (m_dbg.run_result == VM_FINISHED) + return; + + if (m_dbg.run_result == VM_READY) + return; + + // 1. First, check events + if (m_dbg.run_result == VM_WAIT_EVENT) + { + VmEvent event; + if (m_eventQueue.try_pop(event)) + { + if (event.type == VmEventType::EvStep) + { + m_dbg.run_result = VM_OK; + } + else if (event.type == VmEventType::EvOkButton) + { + m_chip32_ctx.registers[R0] = 0x01; + m_dbg.run_result = VM_OK; + } + else if (event.type == VmEventType::EvLeftButton) + { + m_chip32_ctx.registers[R0] = 0x02; + m_dbg.run_result = VM_OK; + } + else if (event.type == VmEventType::EvRightButton) + { + m_chip32_ctx.registers[R0] = 0x04; + m_dbg.run_result = VM_OK; + } + else if (event.type == VmEventType::EvAudioFinished) + { + m_chip32_ctx.registers[R0] = 0x08; + m_dbg.run_result = VM_OK; + } + } + } + + if (m_dbg.run_result == VM_OK) + { + if (m_dbg.m_breakpoints.contains(m_dbg.line + 1)) + { + Log("Breakpoint on line: " + std::to_string(m_dbg.line + 1)); + m_dbg.free_run = false; + return; + } + StepInstruction(); + } + + if (m_dbg.run_result == VM_FINISHED) + { + m_dbg.free_run = false; + } + + // In this case, we wait for single step debugger + if ((m_dbg.run_result == VM_OK) && !m_dbg.free_run) + { + m_dbg.run_result = VM_WAIT_EVENT; + } +} + +uint8_t MainWindow::Syscall(chip32_ctx_t *ctx, uint8_t code) +{ + uint8_t retCode = SYSCALL_RET_OK; + Log("SYSCALL: " + std::to_string(code)); + + // Media + if (code == 1) // Execute media + { + if (m_chip32_ctx.registers[R0] != 0) + { + // image file name address is in R0 + std::string imageFile = m_story.BuildFullAssetsPath(GetFileNameFromMemory(m_chip32_ctx.registers[R0])); + Log("Image: " + imageFile); + m_emulatorWindow.SetImage(imageFile); + } + else + { + m_emulatorWindow.ClearImage(); + } + + if (m_chip32_ctx.registers[R1] != 0) + { + // sound file name address is in R1 + std::string soundFile = m_story.BuildFullAssetsPath(GetFileNameFromMemory(m_chip32_ctx.registers[R1])); + Log(", Sound: " + soundFile); + m_player.Play(soundFile); + } + retCode = SYSCALL_RET_WAIT_EV; // set the VM in pause + } + // WAIT EVENT bits: + // 0: block + // 1: OK button + // 2: home button + // 3: pause button + // 4: rotary left + // 5: rotary right + else if (code == 2) // Wait for event + { + // Event mask is located in R0 + // optional timeout is located in R1 + // if timeout is set to zero, wait for infinite and beyond + retCode = SYSCALL_RET_WAIT_EV; // set the VM in pause + } + + + return retCode; +} + void MainWindow::DrawStatusBar() { float statusWindowHeight = ImGui::GetFrameHeight() * 1.4f; @@ -221,11 +425,11 @@ void MainWindow::OpenProjectDialog() std::string filePath = ImGuiFileDialog::Instance()->GetCurrentPath(); - m_project.Initialize(filePathName); + m_story.Initialize(filePathName); nlohmann::json model; - if (m_project.Load(filePathName, model, m_resources)) + if (m_story.Load(filePathName, model, m_resources)) { Log("Open project success"); m_nodeEditorWindow.Load(model); @@ -247,7 +451,7 @@ void MainWindow::OpenProjectDialog() void MainWindow::EnableProject() { - auto proj = m_project.GetProjectFilePath(); + auto proj = m_story.GetProjectFilePath(); // Add to recent if not exists if (std::find(m_recentProjects.begin(), m_recentProjects.end(), proj) != m_recentProjects.end()) { @@ -426,21 +630,21 @@ void MainWindow::NewProjectPopup() if (valid) { - m_project.Initialize(std::filesystem::path(projdir) / "project.json"); + m_story.Initialize(std::filesystem::path(projdir) / "project.json"); if (display_item_current_idx == 0) { - m_project.SetDisplayFormat(320, 240); + m_story.SetDisplayFormat(320, 240); } else { - m_project.SetDisplayFormat(640, 480); + m_story.SetDisplayFormat(640, 480); } - m_project.SetImageFormat(GetImageFormat(image_item_current_idx)); - m_project.SetSoundFormat(GetSoundFormat(sound_item_current_idx)); - m_project.SetName(project_name); - m_project.SetUuid(UUID().String()); + m_story.SetImageFormat(GetImageFormat(image_item_current_idx)); + m_story.SetSoundFormat(GetSoundFormat(sound_item_current_idx)); + m_story.SetName(project_name); + m_story.SetUuid(UUID().String()); SaveProject(); EnableProject(); @@ -466,12 +670,12 @@ void MainWindow::SaveProject() { nlohmann::json model; m_nodeEditorWindow.Save(model); - m_project.Save(model, m_resources); + m_story.Save(model, m_resources); } void MainWindow::CloseProject() { - m_project.Clear(); + m_story.Clear(); m_nodeEditorWindow.Clear(); // m_model.Clear(); @@ -505,6 +709,10 @@ void MainWindow::Loop() DrawMainMenuBar(); // DrawStatusBar(); + + ProcessStory(); + + // ------------ Draw all windows m_consoleWindow.Draw(); m_emulatorWindow.Draw(); @@ -543,12 +751,12 @@ void MainWindow::Log(const std::string &txt, bool critical) void MainWindow::PlaySoundFile(const std::string &fileName) { Log("Play sound file: " + fileName); - m_project.PlaySoundFile(fileName); + m_player.Play(fileName); } std::string MainWindow::BuildFullAssetsPath(const std::string &fileName) const { - return m_project.BuildFullAssetsPath(fileName); + return m_story.BuildFullAssetsPath(fileName); } std::pair MainWindow::Images() @@ -647,9 +855,9 @@ void MainWindow::GenerateBinary() // FIXME // m_ramView->SetMemory(m_ram_data, sizeof(m_ram_data)); // m_romView->SetMemory(m_rom_data, m_program.size()); - m_project.SaveStory(m_program); + m_story.SaveStory(m_program); chip32_initialize(&m_chip32_ctx); - m_dbg.run_result = VM_OK; + m_dbg.run_result = VM_READY; UpdateVmView(); // DebugContext::DumpCodeAssembler(m_assembler); } @@ -672,14 +880,70 @@ void MainWindow::UpdateVmView() { // FIXME // m_vmDock->updateRegistersView(m_chip32_ctx); -// highlightNextLine(); + + + // Highlight next line in the test editor + uint32_t pcVal = m_chip32_ctx.registers[PC]; + + // On recherche quelle est la ligne qui possède une instruction à cette adresse + std::vector::const_iterator ptr = m_assembler.Begin(); + for (; ptr != m_assembler.End(); ++ptr) + { + if ((ptr->addr == pcVal) && ptr->isRomCode()) + { + break; + } + } + + if (ptr != m_assembler.End()) + { + m_dbg.line = (ptr->line - 1); + m_editor.HighlightLine(m_dbg.line); + } + else + { + // Not found + Log("Reached end or instruction not found line: " + std::to_string(m_dbg.line)); + } + + // Refresh RAM content // m_ramView->SetMemory(m_ram_data, m_chip32_ctx.ram.size); } void MainWindow::ConvertResources() { + auto [b, e] = m_resources.Items(); + for (auto it = b; it != e; ++it) + { + std::string inputfile = m_story.BuildFullAssetsPath((*it)->file.c_str()); + std::string outputfile = std::filesystem::path(m_story.AssetsPath() / StoryProject::RemoveFileExtension((*it)->file)).string(); + int retCode = 0; + if ((*it)->format == "PNG") + { + outputfile += ".qoi"; // FIXME: prendre la congif en cours désirée + retCode = MediaConverter::ImageToQoi(inputfile, outputfile); + } + else if ((*it)->format == "MP3") + { + outputfile += ".wav"; // FIXME: prendre la congif en cours désirée + retCode = MediaConverter::Mp3ToWav(inputfile, outputfile); + } + else + { + Log("Skipped: " + inputfile + ", unknown format" + outputfile, true); + } + + if (retCode < 0) + { + Log("Failed to convert media file " + inputfile + ", error code: " + std::to_string(retCode) + " to: " + outputfile, true); + } + else if (retCode == 0) + { + Log("Convertered file: " + inputfile); + } + } } void MainWindow::SaveParams() diff --git a/story-editor/src/main_window.h b/story-editor/src/main_window.h index 5e3e773..34f61ab 100644 --- a/story-editor/src/main_window.h +++ b/story-editor/src/main_window.h @@ -1,6 +1,9 @@ #ifndef MAINWINDOW_H #define MAINWINDOW_H + +#include + #include "gui.h" #include "console_window.h" #include "code_editor.h" @@ -13,7 +16,8 @@ #include "chip32_assembler.h" #include "chip32_vm.h" #include "story_project.h" -#include "i_story_project.h" +#include "i_story_manager.h" +#include "thread_safe_queue.h" struct DebugContext { @@ -25,6 +29,10 @@ struct DebugContext std::set m_breakpoints; + void Stop() { + run_result = VM_FINISHED; + } + static void DumpCodeAssembler(Chip32::Assembler & assembler) { for (std::vector::const_iterator iter = assembler.Begin(); @@ -51,7 +59,7 @@ struct DebugContext } }; -#include + template struct Callback; @@ -70,7 +78,7 @@ std::function Callback::func; -class MainWindow : public IStoryProject +class MainWindow : public IStoryManager, public IAudioEvent { public: MainWindow(); @@ -80,8 +88,9 @@ public: void Loop(); private: + enum VmEventType { EvNoEvent, EvStep, EvOkButton, EvLeftButton, EvRightButton, EvAudioFinished}; - StoryProject m_project; + StoryProject m_story; // VM uint8_t m_rom_data[16*1024]; @@ -95,6 +104,7 @@ private: DebugContext m_dbg; std::string m_currentCode; + std::vector m_recentProjects; ResourceManager m_resources; @@ -110,8 +120,17 @@ private: PropertiesWindow m_PropertiesWindow; + AudioPlayer m_player; - // From IStoryProject (proxy to StoryProject class) + struct VmEvent + { + VmEventType type; + }; + + ThreadSafeQueue m_eventQueue; + + + // From IStoryManager (proxy to StoryProject class) virtual void Log(const std::string &txt, bool critical = false) override; virtual void PlaySoundFile(const std::string &fileName) override;; virtual std::string BuildFullAssetsPath(const std::string &fileName) const override; @@ -125,6 +144,13 @@ private: virtual void Build() override; virtual std::list> GetNodeConnections(unsigned long nodeId) override; virtual std::string GetNodeEntryLabel(unsigned long nodeId) override; + virtual void Play() override; + virtual void Pause() override; + virtual void Next() override; + virtual void Previous() override; + + // From IAudioEvent + virtual void EndOfAudio() override; void SaveParams(); void LoadParams(); @@ -143,6 +169,10 @@ private: void ConvertResources(); void GenerateBinary(); void UpdateVmView(); + uint8_t Syscall(chip32_ctx_t *ctx, uint8_t code); + std::string GetFileNameFromMemory(uint32_t addr); + void ProcessStory(); + void StepInstruction(); }; #endif // MAINWINDOW_H diff --git a/story-editor/src/media_node.cpp b/story-editor/src/media_node.cpp index 48db78c..d510181 100644 --- a/story-editor/src/media_node.cpp +++ b/story-editor/src/media_node.cpp @@ -4,9 +4,9 @@ namespace ed = ax::NodeEditor; #include "IconsMaterialDesignIcons.h" #include "story_project.h" -MediaNode::MediaNode(const std::string &title, IStoryProject &proj) +MediaNode::MediaNode(const std::string &title, IStoryManager &proj) : BaseNode(title, proj) - , m_project(proj) + , m_story(proj) { Gui::LoadRawImage("fairy.png", m_image); @@ -87,8 +87,6 @@ void MediaNode::Draw() DrawPins(); - - BaseNode::FrameEnd(); } @@ -144,7 +142,7 @@ void MediaNode::DrawProperties() if (ImGui::Button(m_buttonUniqueName.c_str())) { - m_project.PlaySoundFile(m_soundPath); + m_story.PlaySoundFile(m_soundPath); } ImGui::SameLine(); @@ -163,7 +161,7 @@ void MediaNode::DrawProperties() if (ImGui::BeginPopup("popup_button")) { ImGui::SeparatorText(isImage ? "Images" : "Sounds"); - auto [filtreDebut, filtreFin] = isImage ? m_project.Images() : m_project.Sounds(); + auto [filtreDebut, filtreFin] = isImage ? m_story.Images() : m_story.Sounds(); int n = 0; for (auto it = filtreDebut; it != filtreFin; ++it, n++) { @@ -188,13 +186,13 @@ void MediaNode::DrawProperties() void MediaNode::SetImage(const std::string &f) { m_image.name = f; - m_image.Load(m_project.BuildFullAssetsPath(f)); + m_image.Load(m_story.BuildFullAssetsPath(f)); } void MediaNode::SetSound(const std::string &f) { m_soundName = f; - m_soundPath = m_project.BuildFullAssetsPath(m_soundName); + m_soundPath = m_story.BuildFullAssetsPath(m_soundName); } @@ -238,14 +236,14 @@ std::string MediaNode::GenerateConstants() << " DC32, " << nb_out_conns << ", "; - std::list> conns = m_project.GetNodeConnections(GetId()); + std::list> conns = m_story.GetNodeConnections(GetId()); int i = 0; for (auto & c : conns) { std::stringstream ssChoice; // On va chercher le label d'entrée du noeud connecté à l'autre bout - ss << m_project.GetNodeEntryLabel(c->inNodeId); + ss << m_story.GetNodeEntryLabel(c->inNodeId); if (i < (nb_out_conns - 1)) { ss << ", "; @@ -311,7 +309,7 @@ std::string MediaNode::Build() } else if (nb_out_conns == 1) // it is a transition node { - std::list> conns = m_project.GetNodeConnections(GetId()); + std::list> conns = m_story.GetNodeConnections(GetId()); for (auto c : conns) @@ -320,7 +318,7 @@ std::string MediaNode::Build() { // On place dans R0 le prochain noeud à exécuter en cas de OK ss << "lcons r0, " - << m_project.GetNodeEntryLabel(c->inNodeId) << "\n" + << m_story.GetNodeEntryLabel(c->inNodeId) << "\n" << "ret\n"; } } diff --git a/story-editor/src/media_node.h b/story-editor/src/media_node.h index 5198512..e05b445 100644 --- a/story-editor/src/media_node.h +++ b/story-editor/src/media_node.h @@ -6,7 +6,7 @@ #include #include "base_node.h" -#include "i_story_project.h" +#include "i_story_manager.h" #include "gui.h" #include @@ -14,7 +14,7 @@ class MediaNode : public BaseNode { public: - MediaNode(const std::string &title, IStoryProject &proj); + MediaNode(const std::string &title, IStoryManager &proj); void Draw() override; @@ -25,7 +25,7 @@ public: virtual std::string GetEntryLabel() override; virtual std::string GenerateConstants() override; private: - IStoryProject &m_project; + IStoryManager &m_story; Gui::Image m_image; std::string m_soundName; std::string m_soundPath; diff --git a/story-editor/src/node_editor_window.cpp b/story-editor/src/node_editor_window.cpp index e6cb600..ab60239 100644 --- a/story-editor/src/node_editor_window.cpp +++ b/story-editor/src/node_editor_window.cpp @@ -10,9 +10,9 @@ #include "gui.h" -NodeEditorWindow::NodeEditorWindow(IStoryProject &proj) +NodeEditorWindow::NodeEditorWindow(IStoryManager &proj) : WindowBase("Node editor") - , m_project(proj) + , m_story(proj) { registerNode("media-node"); @@ -47,7 +47,7 @@ void NodeEditorWindow::LoadNode(const nlohmann::json &nodeJson) nlohmann::json internalDataJson = nodeJson["internal-data"]; std::string type = nodeJson["type"].get(); - auto n = createNode(type, "", m_project); + auto n = createNode(type, "", m_story); if (n) { n->SetType(type); // FIXME: set type in createNode factory? @@ -225,7 +225,7 @@ uint32_t NodeEditorWindow::FindFirstNode() const if (!foundConnection) { id = n->GetId(); - m_project.Log("First node is: " + std::to_string(id)); + m_story.Log("First node is: " + std::to_string(id)); break; } } diff --git a/story-editor/src/node_editor_window.h b/story-editor/src/node_editor_window.h index 60788b3..9a2bdf2 100644 --- a/story-editor/src/node_editor_window.h +++ b/story-editor/src/node_editor_window.h @@ -9,7 +9,7 @@ #include #include "base_node.h" #include "window_base.h" -#include "i_story_project.h" +#include "i_story_manager.h" #include "story_project.h" #include "json.hpp" @@ -48,7 +48,7 @@ public: std::shared_ptr model; }; - NodeEditorWindow(IStoryProject &proj); + NodeEditorWindow(IStoryManager &proj); ~NodeEditorWindow(); virtual void Draw() override; @@ -63,7 +63,7 @@ public: std::shared_ptr GetSelectedNode(); private: - IStoryProject &m_project; + IStoryManager &m_story; ed::EditorContext* m_context = nullptr; @@ -90,12 +90,12 @@ private: template struct Factory { - static std::shared_ptr create_func(const std::string &title, IStoryProject &proj) { + static std::shared_ptr create_func(const std::string &title, IStoryManager &proj) { return std::make_shared(title, proj); } }; - typedef std::shared_ptr (*GenericCreator)(const std::string &title, IStoryProject &proj); + typedef std::shared_ptr (*GenericCreator)(const std::string &title, IStoryManager &proj); typedef std::map Registry; Registry m_registry; @@ -104,7 +104,7 @@ private: m_registry.insert(typename Registry::value_type(key, Factory::create_func)); } - std::shared_ptr createNode(const std::string& key, const std::string &title, IStoryProject &proj) { + std::shared_ptr createNode(const std::string& key, const std::string &title, IStoryManager &proj) { typename Registry::const_iterator i = m_registry.find(key); if (i == m_registry.end()) { throw std::invalid_argument(std::string(__PRETTY_FUNCTION__) + diff --git a/story-editor/src/resources_window.cpp b/story-editor/src/resources_window.cpp index 20ff73e..f7b90b2 100644 --- a/story-editor/src/resources_window.cpp +++ b/story-editor/src/resources_window.cpp @@ -8,9 +8,9 @@ //static thread_pool pool; -ResourcesWindow::ResourcesWindow(IStoryProject &project) +ResourcesWindow::ResourcesWindow(IStoryManager &project) : WindowBase("Resources") - , m_project(project) + , m_story(project) { } @@ -44,7 +44,7 @@ void ResourcesWindow::ChooseFile() std::filesystem::path p(filePathName); - std::filesystem::path p2 = m_project.BuildFullAssetsPath( p.filename()); + std::filesystem::path p2 = m_story.BuildFullAssetsPath( p.filename()); std::filesystem::copy(p, p2, std::filesystem::copy_options::overwrite_existing); auto res = std::make_shared(); @@ -56,7 +56,7 @@ void ResourcesWindow::ChooseFile() res->format = ext; res->type = m_soundFile ? "sound" : "image"; res->file = p.filename().generic_string(); - m_project.AddResource(res); + m_story.AddResource(res); } // close @@ -104,7 +104,7 @@ void ResourcesWindow::Draw() ImGui::TableHeadersRow(); - auto [b, e] = m_project.Resources(); + auto [b, e] = m_story.Resources(); int id = 1000; for (auto it = b; it != e; ++it) @@ -152,7 +152,7 @@ void ResourcesWindow::Draw() ImGui::TableNextColumn(); if (ImGui::SmallButton("Delete")) { - m_project.DeleteResource(it); + m_story.DeleteResource(it); quitLoop = true; } ImGui::PopID(); diff --git a/story-editor/src/resources_window.h b/story-editor/src/resources_window.h index 4248146..fee3882 100644 --- a/story-editor/src/resources_window.h +++ b/story-editor/src/resources_window.h @@ -3,18 +3,18 @@ #include #include #include -#include "i_story_project.h" +#include "i_story_manager.h" #include "window_base.h" class ResourcesWindow : public WindowBase { public: - ResourcesWindow(IStoryProject &project); + ResourcesWindow(IStoryManager &project); ~ResourcesWindow(); virtual void Draw() override; private: - IStoryProject &m_project; + IStoryManager &m_story; bool m_showImportDialog{false}; bool m_soundFile{false};