From 016282064e8d0204ebc77567639d5f2bdfe2d512 Mon Sep 17 00:00:00 2001 From: "anthony@rabine.fr" Date: Wed, 15 May 2024 15:44:38 +0200 Subject: [PATCH] Fix media output format, fix link creation --- shared/i_story_project.h | 2 + shared/resource.cpp | 1 + shared/story_project.cpp | 29 +++- shared/story_project.h | 2 + story-editor/CMakeLists.txt | 37 +++-- story-editor/src/emulator_window.cpp | 2 + story-editor/src/gui.cpp | 8 -- story-editor/src/i_story_manager.h | 1 + story-editor/src/main_window.cpp | 37 ++++- story-editor/src/main_window.h | 1 + story-editor/src/media_converter.cpp | 131 ++++-------------- .../src/node_editor/base_node_widget.h | 2 + .../src/node_editor/node_editor_window.cpp | 86 ++++++++++-- .../src/node_editor/node_editor_window.h | 4 +- story-editor/src/node_engine/media_node.cpp | 4 +- 15 files changed, 197 insertions(+), 150 deletions(-) diff --git a/shared/i_story_project.h b/shared/i_story_project.h index 09b1499..eb8604d 100644 --- a/shared/i_story_project.h +++ b/shared/i_story_project.h @@ -10,6 +10,8 @@ public: virtual ~IStoryProject() {}; virtual std::list> GetNodeConnections(const std::string &nodeId) = 0; virtual int OutputsCount(const std::string &nodeId) = 0; + virtual std::string ImageExtension(const std::string &filename) const = 0; + virtual std::string SoundExtension(const std::string &filename) const = 0; }; diff --git a/shared/resource.cpp b/shared/resource.cpp index d2499d9..2679bab 100644 --- a/shared/resource.cpp +++ b/shared/resource.cpp @@ -27,3 +27,4 @@ std::string Resource::SoundFormatToString(SoundFormat format) } return text; } + diff --git a/shared/story_project.cpp b/shared/story_project.cpp index a711c3b..16e9e83 100644 --- a/shared/story_project.cpp +++ b/shared/story_project.cpp @@ -119,7 +119,6 @@ void StoryProject::ModelToJson(nlohmann::json &model) { nlohmann::json c(*cnx); connections.push_back(c); - // Connection cnx = LinkToModel(linkInfo->ed_link->InputId, linkInfo->ed_link->OutputId); } model["connections"] = connections; @@ -275,6 +274,32 @@ int StoryProject::OutputsCount(const std::string &nodeId) return count; } +std::string StoryProject::ImageExtension(const std::string &filename) const +{ + std::string ext = SysLib::GetFileExtension(filename); + if (m_imageFormat == Resource::ImageFormat::IMG_FORMAT_QOIF) + { + return "qoi"; + } + + return ext; +} + +std::string StoryProject::SoundExtension(const std::string &filename) const +{ + std::string ext = SysLib::GetFileExtension(filename); + if (m_soundFormat == Resource::SoundFormat::SND_FORMAT_QOAF) + { + return "qoa"; + } + else if (m_soundFormat == Resource::SoundFormat::SND_FORMAT_WAV) + { + return "wav"; + } + + return ext; +} + std::list> StoryProject::GetNodeConnections(const std::string &nodeId) { std::list> c; @@ -555,7 +580,7 @@ std::string StoryProject::BuildFullAssetsPath(const std::string &fileName) const std::string StoryProject::FileToConstant(const std::string &FileName, const std::string &extension) { std::string f = SysLib::RemoveFileExtension(FileName); - return "$" + f + " DC8 \"" + f + extension + "\", 8\r\n"; + return "$" + f + " DC8 \"" + f + "." + extension + "\", 8\r\n"; } diff --git a/shared/story_project.h b/shared/story_project.h index 2779bd1..cc6c0a8 100644 --- a/shared/story_project.h +++ b/shared/story_project.h @@ -135,6 +135,8 @@ public: virtual std::list> GetNodeConnections(const std::string &nodeId) override; std::string FindFirstNode() const; virtual int OutputsCount(const std::string &nodeId) override; + virtual std::string ImageExtension(const std::string &filename) const override; + virtual std::string SoundExtension(const std::string &filename) const override; std::shared_ptr CreateNode(const std::string& type); void AddConnection(std::shared_ptr c); diff --git a/story-editor/CMakeLists.txt b/story-editor/CMakeLists.txt index 8f10968..1139640 100644 --- a/story-editor/CMakeLists.txt +++ b/story-editor/CMakeLists.txt @@ -148,23 +148,23 @@ include_directories(${sdl3_mixer_SOURCE_DIR}/include) # ========================================================================================================================= # SDL3-Image # ========================================================================================================================= -# FetchContent_Declare( -# SDL2_image -# GIT_REPOSITORY https://github.com/libsdl-org/SDL_image.git -# GIT_TAG origin/main -# GIT_SHALLOW TRUE -# GIT_PROGRESS TRUE -# ) +FetchContent_Declare( + sdl_image + GIT_REPOSITORY https://github.com/libsdl-org/SDL_image.git + GIT_TAG origin/main + GIT_SHALLOW TRUE + GIT_PROGRESS TRUE +) -# # START ADDITION -# set(SDL2IMAGE_INSTALL OFF) -# set(BUILD_SHARED_LIBS FALSE) -# # END ADDITION -add_subdirectory(libs/SDL_image) -include_directories(libs/SDL_image/include) +set(SDL3IMAGE_INSTALL OFF) +set(BUILD_SHARED_LIBS FALSE) +FetchContent_MakeAvailable(sdl_image) +include_directories(${sdl_image_SOURCE_DIR}/include) -# FetchContent_MakeAvailable(SDL2_image) +# ========================================================================================================================= +# Project sources +# ========================================================================================================================= set(SRCS src/main.cpp @@ -332,11 +332,12 @@ target_compile_definitions(${STORY_EDITOR_PROJECT} PUBLIC cimg_display=0) target_compile_definitions(${STORY_EDITOR_PROJECT} PUBLIC "$<$:DEBUG>") -target_link_directories(${STORY_EDITOR_PROJECT} PUBLIC ${sdl3_BINARY_DIR} ${curl_BINARY_DIR} ${CMAKE_BINARY_DIR}/libs/SDL_image) +target_link_directories(${STORY_EDITOR_PROJECT} PUBLIC ${sdl3_BINARY_DIR} ${curl_BINARY_DIR}) # On est obligé de passer par une variable pour injecter # certaines informations à CPACK set(SDL_BIN_DIR ${sdl3_BINARY_DIR}) +set(SDL_IMAGE_BIN_DIR ${sdl_image_BINARY_DIR}) if(UNIX) target_link_libraries(${STORY_EDITOR_PROJECT} @@ -389,6 +390,12 @@ if(WIN32) set(CPACK_NSIS_MUI_ICON "${CMAKE_SOURCE_DIR}/story-editor-logo.ico") endif() +if(LINUX) + install_files("." FILES "${SDL_BIN_DIR}/SDL3.so") + install_files("." FILES "${SDL_IMAGE_BIN_DIR}/SDL3_image.so") + +endif() + if (APPLE) set(CPACK_GENERATOR "DragNDrop") set(MACOSX_BUNDLE_INFO_PLIST ${PROJECT_SOURCE_DIR}/bundle.plist.in) diff --git a/story-editor/src/emulator_window.cpp b/story-editor/src/emulator_window.cpp index 11494f4..6a9dba7 100644 --- a/story-editor/src/emulator_window.cpp +++ b/story-editor/src/emulator_window.cpp @@ -99,6 +99,8 @@ void EmulatorWindow::Draw() ImGui::SameLine(); + ImGui::Text("VM state: %s", m_story.VmState().c_str()); + WindowBase::EndDraw(); } diff --git a/story-editor/src/gui.cpp b/story-editor/src/gui.cpp index c8e3131..cc12f6a 100644 --- a/story-editor/src/gui.cpp +++ b/story-editor/src/gui.cpp @@ -36,7 +36,6 @@ 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) @@ -50,13 +49,6 @@ 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) diff --git a/story-editor/src/i_story_manager.h b/story-editor/src/i_story_manager.h index 269ac92..5105f63 100644 --- a/story-editor/src/i_story_manager.h +++ b/story-editor/src/i_story_manager.h @@ -58,6 +58,7 @@ public: virtual void Pause() = 0; virtual void Next() = 0; virtual void Previous() = 0; + virtual std::string VmState() const = 0; }; #endif // I_STORY_MANAGER_H diff --git a/story-editor/src/main_window.cpp b/story-editor/src/main_window.cpp index ab47bdc..2e23ae5 100644 --- a/story-editor/src/main_window.cpp +++ b/story-editor/src/main_window.cpp @@ -93,16 +93,44 @@ void MainWindow::Pause() void MainWindow::Next() { - Log("End of audio track"); + Log("Next button"); m_eventQueue.push({VmEventType::EvNextButton}); } void MainWindow::Previous() { - Log("End of audio track"); + Log("Previous button"); m_eventQueue.push({VmEventType::EvPreviousButton}); } +std::string MainWindow::VmState() const +{ + std::string state = "Unknown"; + + switch (m_dbg.run_result) + { + case VM_READY: + state = "VM Ready"; + break; + case VM_FINISHED: + state = "VM Finished"; + break; + case VM_SKIPED: + state = "VM Skiped"; + break; + case VM_WAIT_EVENT: + state = "VM Wait Event"; + break; + case VM_OK: + state = "VM Ok"; + break; + default: + state = "VM Error"; + break; + } + return state; +} + void MainWindow::EndOfAudio() { Log("End of audio track"); @@ -659,6 +687,7 @@ void MainWindow::SaveProject() { nlohmann::json model; m_story->Save(m_resources); + Log("Project saved"); } void MainWindow::OpenProject(const std::string &uuid) @@ -858,8 +887,8 @@ void MainWindow::Loop() // Rendering and event handling Uint64 frameTime = SDL_GetTicks() - frameStart; // Temps écoulé pour la frame - if (frameTime < 16) { // Limite de 60 FPS - SDL_Delay(16 - frameTime); // Attendez pour compléter la frame + if (frameTime < 32) { // 16 ms = 60 FPS + SDL_Delay(32 - frameTime); // Attendez pour compléter la frame } diff --git a/story-editor/src/main_window.h b/story-editor/src/main_window.h index afecdcc..1697a9d 100644 --- a/story-editor/src/main_window.h +++ b/story-editor/src/main_window.h @@ -144,6 +144,7 @@ private: virtual void Pause() override; virtual void Next() override; virtual void Previous() override; + virtual std::string VmState() const override; // From ILogger diff --git a/story-editor/src/media_converter.cpp b/story-editor/src/media_converter.cpp index c38de3d..e0763eb 100644 --- a/story-editor/src/media_converter.cpp +++ b/story-editor/src/media_converter.cpp @@ -14,19 +14,39 @@ #define STBI_NO_LINEAR #include "stb_image.h" -#define QOI_IMPLEMENTATION -#undef QOI_NO_STDIO -#include "qoi.h" - #define DR_MP3_IMPLEMENTATION #include "dr_mp3.h" +#include "qoi.h" + + +static int qoi_encode_and_write(const char *filename, const void *data, const qoi_desc *desc) { + FILE *f = fopen(filename, "wb"); + int size; + void *encoded; + + if (!f) { + return 0; + } + + encoded = qoi_encode(data, desc, &size); + if (!encoded) { + fclose(f); + return 0; + } + + fwrite(encoded, 1, size, f); + fclose(f); + + free(encoded); + return size; +} + MediaConverter::MediaConverter() { } - int MediaConverter::ImageToQoi(const std::string &inputFileName, const std::string &outputFileName) { void *pixels = NULL; @@ -54,7 +74,8 @@ int MediaConverter::ImageToQoi(const std::string &inputFileName, const std::stri desc.width = w; desc.height = h; - int encoded = qoi_write(outputFileName.c_str(), pixels, &desc); + + int encoded = qoi_encode_and_write(outputFileName.c_str(), pixels, &desc); free(pixels); if (!encoded) @@ -241,101 +262,3 @@ int MediaConverter::OggToWav(const std::string &inputFileName, const std::string return cSuccess; } - -/* - -OGG TO WAV - -#define STB_VORBIS_HEADER_ONLY -#include "stb_vorbis.c" - -#include -#include - -// Function to read the entire contents of a file into memory -unsigned char* read_entire_file(const char* filename, int* length) { - FILE* f = fopen(filename, "rb"); - if (!f) return NULL; - fseek(f, 0, SEEK_END); - long size = ftell(f); - fseek(f, 0, SEEK_SET); - unsigned char* buffer = (unsigned char*)malloc(size); - if (!buffer) { - fclose(f); - return NULL; - } - fread(buffer, 1, size, f); - fclose(f); - if (length) *length = (int)size; - return buffer; -} - -int main(int argc, char** argv) { - if (argc != 3) { - printf("Usage: %s input.ogg output.wav\n", argv[0]); - return 1; - } - - const char* input_filename = argv[1]; - const char* output_filename = argv[2]; - - int ogg_length; - unsigned char* ogg_data = read_entire_file(input_filename, &ogg_length); - if (!ogg_data) { - printf("Failed to read input file %s\n", input_filename); - return 1; - } - - int channels, sample_rate; - short* samples = stb_vorbis_decode_memory(ogg_data, ogg_length, &channels, &sample_rate); - if (!samples) { - printf("Failed to decode OGG file %s\n", input_filename); - free(ogg_data); - return 1; - } - - // Write WAV file header - FILE* wav_file = fopen(output_filename, "wb"); - if (!wav_file) { - printf("Failed to create output file %s\n", output_filename); - free(ogg_data); - free(samples); - return 1; - } - fwrite("RIFF", 1, 4, wav_file); - int total_size = 36 + channels * (sample_rate * sizeof(short)); - fwrite(&total_size, 4, 1, wav_file); - fwrite("WAVEfmt ", 1, 8, wav_file); - int format_size = 16; - fwrite(&format_size, 4, 1, wav_file); - short format_type = 1; // PCM - fwrite(&format_type, 2, 1, wav_file); - fwrite(&channels, 2, 1, wav_file); - fwrite(&sample_rate, 4, 1, wav_file); - int byte_rate = sample_rate * channels * sizeof(short); - fwrite(&byte_rate, 4, 1, wav_file); - short block_align = channels * sizeof(short); - fwrite(&block_align, 2, 1, wav_file); - short bits_per_sample = 16; - fwrite(&bits_per_sample, 2, 1, wav_file); - fwrite("data", 1, 4, wav_file); - int data_size = channels * (sample_rate * sizeof(short)); - fwrite(&data_size, 4, 1, wav_file); - - // Write sample data - fwrite(samples, sizeof(short), sample_rate * channels, wav_file); - - fclose(wav_file); - - free(ogg_data); - free(samples); - - printf("Conversion complete. WAV file saved as %s\n", output_filename); - - return 0; -} - - - -*/ - diff --git a/story-editor/src/node_editor/base_node_widget.h b/story-editor/src/node_editor/base_node_widget.h index 684dcbf..55f8769 100644 --- a/story-editor/src/node_editor/base_node_widget.h +++ b/story-editor/src/node_editor/base_node_widget.h @@ -177,6 +177,8 @@ public: atIndex = 0; for (auto &i : m_node->Outputs) { + // std::cout << "Output Pin id: " << (int)i.ID.Get() << std::endl; + if (i.ID == pinId) { found = true; diff --git a/story-editor/src/node_editor/node_editor_window.cpp b/story-editor/src/node_editor/node_editor_window.cpp index dabfefe..f36e75b 100644 --- a/story-editor/src/node_editor/node_editor_window.cpp +++ b/story-editor/src/node_editor/node_editor_window.cpp @@ -167,29 +167,79 @@ void NodeEditorWindow::CreateLink(std::shared_ptr model, ed::PinId i m_links.push_back(conn); } +// retourne 1 si c'est une sortie, 2 une entrée, 0 pas trouvé +int NodeEditorWindow::FindNodeAndPin(ed::PinId pinId, int &foundIndex, std::string &foundNodeId) +{ + int success = 0; + for (const auto & n : m_nodes) + { + // std::cout << "---> Node: " << n->Base()->GetId() << std::endl; + if (n->HasOnputPinId(pinId, foundIndex)) + { + foundNodeId = n->Base()->GetId(); + success = 1; + break; + } + if (n->HasInputPinId(pinId, foundIndex)) + { + foundNodeId = n->Base()->GetId(); + success = 2; + break; + } + } + + return success; +} + +bool NodeEditorWindow::FillConnection(std::shared_ptr c, ed::PinId pinId) +{ + bool success = false; + std::string nodeId; + int nodeIndex; + int ret = FindNodeAndPin(pinId, nodeIndex, nodeId); + if (ret > 0) + { + if (ret == 1) + { + c->outNodeId = nodeId; + c->outPortIndex = nodeIndex; + } + else + { + c->inNodeId = nodeId; + c->inPortIndex = nodeIndex; + } + success = true; + } + return success; +} + +/* std::shared_ptr NodeEditorWindow::LinkToModel(ed::PinId InputId, ed::PinId OutputId) { auto c = std::make_shared(); - int index; + int foundIndex = -1; for (const auto & n : m_nodes) { - if (n->HasOnputPinId(OutputId, index)) + // std::cout << "---> Node: " << n->Base()->GetId() << std::endl; + + if (n->HasOnputPinId(OutputId, foundIndex)) { c->outNodeId = n->Base()->GetId(); - c->outPortIndex = index; + c->outPortIndex = foundIndex; } - if (n->HasInputPinId(InputId, index)) + if (n->HasInputPinId(InputId, foundIndex)) { c->inNodeId = n->Base()->GetId(); - c->inPortIndex = index; + c->inPortIndex = foundIndex; } } return c; -} +}*/ std::shared_ptr NodeEditorWindow::GetSelectedNode() @@ -243,8 +293,8 @@ void NodeEditorWindow::Draw() // Handle creation action, returns true if editor want to create new object (node or link) if (ed::BeginCreate()) { - ed::PinId inputPinId, outputPinId; - if (ed::QueryNewLink(&inputPinId, &outputPinId)) + ed::PinId startId, endId; + if (ed::QueryNewLink(&startId, &endId)) { // QueryNewLink returns true if editor want to create new link between pins. // @@ -258,18 +308,26 @@ void NodeEditorWindow::Draw() // * input invalid, output valid - user started to drag new ling from output pin // * input valid, output valid - user dragged link over other pin, can be validated - if (inputPinId && outputPinId) // both are valid, let's accept link + if (startId && endId) // both are valid, let's accept link { // ed::AcceptNewItem() return true when user release mouse button. if (ed::AcceptNewItem()) { - auto c = LinkToModel(inputPinId, outputPinId); - m_story->AddConnection(c); + auto c = std::make_shared(); - CreateLink(c, inputPinId, outputPinId); + // On cherche à quel noeud appartien les pin (selon si le lien a été créé à partir d'une entrée ou d'une sortie) + if (FillConnection(c, startId)) + { + if (FillConnection(c, endId)) + { + m_story->AddConnection(c); - // Draw new link. - ed::Link(m_links.back()->ed_link->Id, inputPinId, outputPinId); + CreateLink(c, startId, endId); + + // Draw new link. + ed::Link(m_links.back()->ed_link->Id, startId, endId); + } + } } // You may choose to reject connection between these nodes diff --git a/story-editor/src/node_editor/node_editor_window.h b/story-editor/src/node_editor/node_editor_window.h index d1ea2b0..365f048 100644 --- a/story-editor/src/node_editor/node_editor_window.h +++ b/story-editor/src/node_editor/node_editor_window.h @@ -116,6 +116,8 @@ private: ed::PinId GetInputPin(const std::string &modelNodeId, int pinIndex); ed::PinId GetOutputPin(const std::string &modelNodeId, int pinIndex); void CreateLink(std::shared_ptr model, ed::PinId inId, ed::PinId outId); - std::shared_ptr LinkToModel(ed::PinId InputId, ed::PinId OutputId); + // std::shared_ptr LinkToModel(ed::PinId InputId, ed::PinId OutputId); + int FindNodeAndPin(ed::PinId pinId, int &foundIndex, std::string &foundNodeId); + bool FillConnection(std::shared_ptr c, ed::PinId pinId); }; diff --git a/story-editor/src/node_engine/media_node.cpp b/story-editor/src/node_engine/media_node.cpp index 69132c3..a661434 100644 --- a/story-editor/src/node_engine/media_node.cpp +++ b/story-editor/src/node_engine/media_node.cpp @@ -24,11 +24,11 @@ std::string MediaNode::GenerateConstants(IStoryProject &story, int nb_out_conns) if (image.size() > 0) { - s = StoryProject::FileToConstant(image, ".qoi"); // FIXME: Generate the extension setup in user option of output format + s = StoryProject::FileToConstant(image, story.ImageExtension(image)); } if (sound.size() > 0) { - s += StoryProject::FileToConstant(sound, ".wav"); // FIXME: Generate the extension setup in user option of output format + s += StoryProject::FileToConstant(sound, story.SoundExtension(sound)); // FIXME: Generate the extension setup in user option of output format }