mirror of
https://github.com/arabine/open-story-teller.git
synced 2025-12-06 17:09:06 +01:00
better event, better audio, add QOI to emulator, emulator is executed
This commit is contained in:
parent
a730ea4e0b
commit
41b52e3532
30 changed files with 690 additions and 216 deletions
|
|
@ -130,6 +130,7 @@ typedef enum
|
||||||
|
|
||||||
typedef enum
|
typedef enum
|
||||||
{
|
{
|
||||||
|
VM_READY, // VM Ready to be started
|
||||||
VM_FINISHED, // execution completed (i.e. got halt instruction)
|
VM_FINISHED, // execution completed (i.e. got halt instruction)
|
||||||
VM_SKIPED, // skipped instruction
|
VM_SKIPED, // skipped instruction
|
||||||
VM_WAIT_EVENT, // execution paused since we hit the maximum instructions
|
VM_WAIT_EVENT, // execution paused since we hit the maximum instructions
|
||||||
|
|
|
||||||
|
|
@ -13,10 +13,14 @@ the simple_mixing example for how best to do this.
|
||||||
#define MINIAUDIO_IMPLEMENTATION
|
#define MINIAUDIO_IMPLEMENTATION
|
||||||
#include "miniaudio.h"
|
#include "miniaudio.h"
|
||||||
|
|
||||||
|
#include <functional>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
|
#include "audio_player.h"
|
||||||
|
|
||||||
|
|
||||||
ma_event g_stopEvent; /* <-- Signaled by the audio thread, waited on by the main thread. */
|
static ThreadSafeQueue<AudioCommand> g_audioQueue;
|
||||||
|
static ma_decoder decoder;
|
||||||
|
static ma_device device;
|
||||||
|
|
||||||
void data_callback(ma_device* pDevice, void* pOutput, const void* pInput, ma_uint32 frameCount)
|
void data_callback(ma_device* pDevice, void* pOutput, const void* pInput, ma_uint32 frameCount)
|
||||||
{
|
{
|
||||||
|
|
@ -28,20 +32,23 @@ void data_callback(ma_device* pDevice, void* pOutput, const void* pInput, ma_uin
|
||||||
ma_uint64 framesRead;
|
ma_uint64 framesRead;
|
||||||
ma_result result = ma_decoder_read_pcm_frames(pDecoder, pOutput, frameCount, &framesRead);
|
ma_result result = ma_decoder_read_pcm_frames(pDecoder, pOutput, frameCount, &framesRead);
|
||||||
|
|
||||||
if (framesRead < frameCount) {
|
|
||||||
// Reached the end.
|
if (result == MA_AT_END) {
|
||||||
ma_event_signal(&g_stopEvent);
|
g_audioQueue.push({"end", ""});
|
||||||
}
|
}
|
||||||
|
// if (framesRead < frameCount) {
|
||||||
|
// // Reached the end.
|
||||||
|
// ma_event_signal(&g_stopEvent);
|
||||||
|
// }
|
||||||
|
|
||||||
(void)pInput;
|
(void)pInput;
|
||||||
}
|
}
|
||||||
|
|
||||||
int miniaudio_play(const char* filename)
|
|
||||||
|
static int miniaudio_play(const char* filename)
|
||||||
{
|
{
|
||||||
ma_result result;
|
ma_result result;
|
||||||
ma_decoder decoder;
|
|
||||||
ma_device_config deviceConfig;
|
ma_device_config deviceConfig;
|
||||||
ma_device device;
|
|
||||||
|
|
||||||
result = ma_decoder_init_file(filename, NULL, &decoder);
|
result = ma_decoder_init_file(filename, NULL, &decoder);
|
||||||
if (result != MA_SUCCESS) {
|
if (result != MA_SUCCESS) {
|
||||||
|
|
@ -62,8 +69,6 @@ int miniaudio_play(const char* filename)
|
||||||
return -3;
|
return -3;
|
||||||
}
|
}
|
||||||
|
|
||||||
ma_event_init(&g_stopEvent);
|
|
||||||
|
|
||||||
if (ma_device_start(&device) != MA_SUCCESS) {
|
if (ma_device_start(&device) != MA_SUCCESS) {
|
||||||
printf("Failed to start playback device.\n");
|
printf("Failed to start playback device.\n");
|
||||||
ma_device_uninit(&device);
|
ma_device_uninit(&device);
|
||||||
|
|
@ -71,14 +76,67 @@ int miniaudio_play(const char* filename)
|
||||||
return -4;
|
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;
|
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();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
47
software/library/audio_player.h
Normal file
47
software/library/audio_player.h
Normal file
|
|
@ -0,0 +1,47 @@
|
||||||
|
#ifndef AUDIO_PLAYER_H
|
||||||
|
#define AUDIO_PLAYER_H
|
||||||
|
|
||||||
|
#include "miniaudio.h"
|
||||||
|
#include <string>
|
||||||
|
#include <thread>
|
||||||
|
#include <mutex>
|
||||||
|
#include <thread>
|
||||||
|
#include <condition_variable>
|
||||||
|
#include <queue>
|
||||||
|
#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
|
||||||
|
|
@ -4,21 +4,16 @@
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
#include <queue>
|
#include <queue>
|
||||||
#include <filesystem>
|
#include <filesystem>
|
||||||
|
|
||||||
#include "json.hpp"
|
#include "json.hpp"
|
||||||
|
|
||||||
StoryProject::StoryProject()
|
StoryProject::StoryProject()
|
||||||
{
|
{
|
||||||
m_audioThread = std::thread( std::bind(&StoryProject::AudioThread, this) );
|
|
||||||
}
|
}
|
||||||
|
|
||||||
StoryProject::~StoryProject()
|
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<uint8_t> &m_program)
|
||||||
|
|
||||||
void StoryProject::Initialize(const std::string &file_path)
|
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);
|
std::filesystem::path p(file_path);
|
||||||
m_working_dir= p.parent_path().generic_string();
|
m_working_dir= p.parent_path().generic_string();
|
||||||
|
|
||||||
|
|
@ -243,7 +238,7 @@ void StoryProject::Save(const nlohmann::json &model, ResourceManager &manager)
|
||||||
{
|
{
|
||||||
nlohmann::json resourcesData;
|
nlohmann::json resourcesData;
|
||||||
|
|
||||||
auto [b, e] = manager.filter("");
|
auto [b, e] = manager.Items();
|
||||||
for (auto it = b; it != e; ++it)
|
for (auto it = b; it != e; ++it)
|
||||||
{
|
{
|
||||||
nlohmann::json obj = {{"type", (*it)->type},
|
nlohmann::json obj = {{"type", (*it)->type},
|
||||||
|
|
@ -258,7 +253,7 @@ void StoryProject::Save(const nlohmann::json &model, ResourceManager &manager)
|
||||||
|
|
||||||
j["nodegraph"] = model;
|
j["nodegraph"] = model;
|
||||||
|
|
||||||
std::ofstream o(m_project_file_path);
|
std::ofstream o(m_story_file_path);
|
||||||
o << std::setw(4) << j << std::endl;
|
o << std::setw(4) << j << std::endl;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -364,32 +359,6 @@ std::string StoryProject::GetFileExtension(const std::string &fileName)
|
||||||
return "";
|
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)
|
void StoryProject::SetImageFormat(ImageFormat format)
|
||||||
{
|
{
|
||||||
m_imageFormat = format;
|
m_imageFormat = format;
|
||||||
|
|
@ -408,7 +377,7 @@ void StoryProject::SetDisplayFormat(int w, int h)
|
||||||
|
|
||||||
std::string StoryProject::GetProjectFilePath() const
|
std::string StoryProject::GetProjectFilePath() const
|
||||||
{
|
{
|
||||||
return m_project_file_path;
|
return m_story_file_path;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string StoryProject::GetWorkingDir() const
|
std::string StoryProject::GetWorkingDir() const
|
||||||
|
|
@ -5,47 +5,13 @@
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <filesystem>
|
#include <filesystem>
|
||||||
#include "json.hpp"
|
#include "json.hpp"
|
||||||
#include <condition_variable>
|
|
||||||
#include <queue>
|
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include <random>
|
#include <random>
|
||||||
#include <thread>
|
|
||||||
#include <mutex>
|
|
||||||
#include "json.hpp"
|
#include "json.hpp"
|
||||||
#include "resource_manager.h"
|
#include "resource_manager.h"
|
||||||
|
#include "audio_player.h"
|
||||||
template <typename T>
|
|
||||||
class ThreadSafeQueue {
|
|
||||||
std::mutex mutex;
|
|
||||||
std::condition_variable cond_var;
|
|
||||||
std::queue<T> 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;
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -141,9 +107,8 @@ public:
|
||||||
static void EraseString(std::string &theString, const std::string &toErase);
|
static void EraseString(std::string &theString, const std::string &toErase);
|
||||||
static std::string ToUpper(const std::string &input);
|
static std::string ToUpper(const std::string &input);
|
||||||
|
|
||||||
|
|
||||||
void SaveStory(const std::vector<uint8_t> &m_program);
|
void SaveStory(const std::vector<uint8_t> &m_program);
|
||||||
void PlaySoundFile(const std::string &fileName);
|
|
||||||
private:
|
private:
|
||||||
// Project properties and location
|
// Project properties and location
|
||||||
std::string m_name; /// human readable name
|
std::string m_name; /// human readable name
|
||||||
|
|
@ -156,17 +121,13 @@ private:
|
||||||
std::string m_titleSound;
|
std::string m_titleSound;
|
||||||
|
|
||||||
std::filesystem::path m_working_dir; /// Temporary folder based on the uuid, where the archive is unzipped
|
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_w{320};
|
||||||
int m_display_h{240};
|
int m_display_h{240};
|
||||||
|
|
||||||
std::thread m_audioThread;
|
|
||||||
ThreadSafeQueue<AudioCommand> m_audioQueue;
|
|
||||||
|
|
||||||
ImageFormat m_imageFormat{IMG_FORMAT_BMP_4BITS};
|
ImageFormat m_imageFormat{IMG_FORMAT_BMP_4BITS};
|
||||||
SoundFormat m_soundFormat{SND_FORMAT_WAV};
|
SoundFormat m_soundFormat{SND_FORMAT_WAV};
|
||||||
void AudioThread();
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // STORY_PROJECT_H
|
#endif // STORY_PROJECT_H
|
||||||
52
software/library/thread_safe_queue.h
Normal file
52
software/library/thread_safe_queue.h
Normal file
|
|
@ -0,0 +1,52 @@
|
||||||
|
#ifndef THREAD_SAFE_QUEUE_H
|
||||||
|
#define THREAD_SAFE_QUEUE_H
|
||||||
|
|
||||||
|
#include <thread>
|
||||||
|
#include <condition_variable>
|
||||||
|
#include <mutex>
|
||||||
|
#include <queue>
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
class ThreadSafeQueue {
|
||||||
|
std::mutex mutex;
|
||||||
|
std::condition_variable cond_var;
|
||||||
|
std::queue<T> 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
|
||||||
|
|
@ -131,10 +131,10 @@ set(SRCS
|
||||||
src/connection.cpp
|
src/connection.cpp
|
||||||
src/connection.h
|
src/connection.h
|
||||||
|
|
||||||
src/uuid.h
|
src/media_converter.cpp
|
||||||
src/resource_manager.h
|
src/media_converter.h
|
||||||
src/i_story_project.h
|
|
||||||
src/resource.h
|
src/i_story_manager.h
|
||||||
|
|
||||||
libs/ImGuiColorTextEdit/TextEditor.cpp
|
libs/ImGuiColorTextEdit/TextEditor.cpp
|
||||||
libs/ImGuiColorTextEdit/TextEditor.h
|
libs/ImGuiColorTextEdit/TextEditor.h
|
||||||
|
|
@ -155,13 +155,15 @@ set(SRCS
|
||||||
|
|
||||||
../software/chip32/chip32_assembler.cpp
|
../software/chip32/chip32_assembler.cpp
|
||||||
../software/chip32/chip32_vm.c
|
../software/chip32/chip32_vm.c
|
||||||
../software/library/miniaudio.c
|
../software/library/audio_player.cpp
|
||||||
|
../software/library/audio_player.h
|
||||||
../software/library/miniaudio.h
|
../software/library/miniaudio.h
|
||||||
|
../software/library/uuid.h
|
||||||
src/story_project.cpp
|
../software/library/resource.h
|
||||||
src/story_project.h
|
../software/library/resource_manager.h
|
||||||
src/media_converter.cpp
|
../software/library/story_project.cpp
|
||||||
src/media_converter.h
|
../software/library/story_project.h
|
||||||
|
../software/library/thread_safe_queue.h
|
||||||
)
|
)
|
||||||
|
|
||||||
if(WIN32)
|
if(WIN32)
|
||||||
|
|
|
||||||
|
|
@ -27,6 +27,7 @@ bool equals(InputIt1 first1, InputIt1 last1,
|
||||||
TextEditor::TextEditor()
|
TextEditor::TextEditor()
|
||||||
: mLineSpacing(1.0f)
|
: mLineSpacing(1.0f)
|
||||||
, mUndoIndex(0)
|
, mUndoIndex(0)
|
||||||
|
, mExternalUndoBuffer(nullptr)
|
||||||
, mTabSize(4)
|
, mTabSize(4)
|
||||||
, mOverwrite(false)
|
, mOverwrite(false)
|
||||||
, mReadOnly(false)
|
, mReadOnly(false)
|
||||||
|
|
@ -41,15 +42,10 @@ TextEditor::TextEditor()
|
||||||
, mColorRangeMin(0)
|
, mColorRangeMin(0)
|
||||||
, mColorRangeMax(0)
|
, mColorRangeMax(0)
|
||||||
, mSelectionMode(SelectionMode::Normal)
|
, mSelectionMode(SelectionMode::Normal)
|
||||||
, mCheckComments(true)
|
|
||||||
, mLastClick(-1.0f)
|
|
||||||
, mHandleKeyboardInputs(true)
|
|
||||||
, mHandleMouseInputs(true)
|
|
||||||
, mIgnoreImGuiChild(false)
|
|
||||||
, mShowWhitespaces(true)
|
|
||||||
, mShowShortTabGlyphs(false)
|
, mShowShortTabGlyphs(false)
|
||||||
|
, mCheckComments(true)
|
||||||
, mStartTime(std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::system_clock::now().time_since_epoch()).count())
|
, mStartTime(std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::system_clock::now().time_since_epoch()).count())
|
||||||
, mExternalUndoBuffer(nullptr)
|
, mLastClick(-1.0f)
|
||||||
{
|
{
|
||||||
SetPalette(GetDarkPalette());
|
SetPalette(GetDarkPalette());
|
||||||
SetLanguageDefinition(LanguageDefinition::HLSL());
|
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)
|
// Draw line number (right aligned)
|
||||||
snprintf(buf, 16, "%d ", lineNo + 1);
|
snprintf(buf, 16, "%d ", lineNo + 1);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -247,6 +247,10 @@ public:
|
||||||
void SetErrorMarkers(const ErrorMarkers& aMarkers) { mErrorMarkers = aMarkers; }
|
void SetErrorMarkers(const ErrorMarkers& aMarkers) { mErrorMarkers = aMarkers; }
|
||||||
void SetBreakpoints(const Breakpoints& aMarkers) { mBreakpoints = 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 Render(const char* aTitle, const ImVec2& aSize = ImVec2(), bool aBorder = false);
|
||||||
void SetText(const std::string& aText);
|
void SetText(const std::string& aText);
|
||||||
std::string GetText() const;
|
std::string GetText() const;
|
||||||
|
|
@ -386,10 +390,10 @@ private:
|
||||||
bool mCursorPositionChanged;
|
bool mCursorPositionChanged;
|
||||||
int mColorRangeMin, mColorRangeMax;
|
int mColorRangeMin, mColorRangeMax;
|
||||||
SelectionMode mSelectionMode;
|
SelectionMode mSelectionMode;
|
||||||
bool mHandleKeyboardInputs;
|
bool mHandleKeyboardInputs{true};
|
||||||
bool mHandleMouseInputs;
|
bool mHandleMouseInputs{true};
|
||||||
bool mIgnoreImGuiChild;
|
bool mIgnoreImGuiChild{false};
|
||||||
bool mShowWhitespaces;
|
bool mShowWhitespaces{true};
|
||||||
bool mShowShortTabGlyphs;
|
bool mShowShortTabGlyphs;
|
||||||
|
|
||||||
Palette mPaletteBase;
|
Palette mPaletteBase;
|
||||||
|
|
@ -404,6 +408,6 @@ private:
|
||||||
Coordinates mInteractiveStart, mInteractiveEnd;
|
Coordinates mInteractiveStart, mInteractiveEnd;
|
||||||
std::string mLineBuffer;
|
std::string mLineBuffer;
|
||||||
uint64_t mStartTime;
|
uint64_t mStartTime;
|
||||||
|
|
||||||
float mLastClick;
|
float mLastClick;
|
||||||
|
int mExecutionMarker{-1};
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -5,8 +5,8 @@
|
||||||
|
|
||||||
unsigned long BaseNode::s_nextId = 1;
|
unsigned long BaseNode::s_nextId = 1;
|
||||||
|
|
||||||
BaseNode::BaseNode(const std::string &title, IStoryProject &proj)
|
BaseNode::BaseNode(const std::string &title, IStoryManager &proj)
|
||||||
: m_project(proj)
|
: m_story(proj)
|
||||||
{
|
{
|
||||||
// m_id = UUID().String();
|
// m_id = UUID().String();
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -7,7 +7,7 @@
|
||||||
#include <string>
|
#include <string>
|
||||||
|
|
||||||
#include "json.hpp"
|
#include "json.hpp"
|
||||||
#include "i_story_project.h"
|
#include "i_story_manager.h"
|
||||||
|
|
||||||
#include <imgui_node_editor.h>
|
#include <imgui_node_editor.h>
|
||||||
namespace ed = ax::NodeEditor;
|
namespace ed = ax::NodeEditor;
|
||||||
|
|
@ -101,7 +101,7 @@ public:
|
||||||
float y;
|
float y;
|
||||||
};
|
};
|
||||||
|
|
||||||
BaseNode(const std::string &title, IStoryProject &proj);
|
BaseNode(const std::string &title, IStoryManager &proj);
|
||||||
|
|
||||||
|
|
||||||
virtual void Draw() = 0;
|
virtual void Draw() = 0;
|
||||||
|
|
@ -223,7 +223,7 @@ public:
|
||||||
void DeleteOutput();
|
void DeleteOutput();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
IStoryProject &m_project;
|
IStoryManager &m_story;
|
||||||
|
|
||||||
std::unique_ptr<Node> m_node;
|
std::unique_ptr<Node> m_node;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -18,8 +18,8 @@ void CodeEditor::Initialize()
|
||||||
|
|
||||||
|
|
||||||
// "breakpoint" markers
|
// "breakpoint" markers
|
||||||
m_breakPoints.insert(42);
|
// m_breakPoints.insert(42);
|
||||||
mEditor.SetBreakpoints(m_breakPoints);
|
// mEditor.SetBreakpoints(m_breakPoints);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -15,6 +15,11 @@ public:
|
||||||
void SetScript(const std::string &txt);
|
void SetScript(const std::string &txt);
|
||||||
void ClearErrors();
|
void ClearErrors();
|
||||||
void AddError(int line, const std::string &text);
|
void AddError(int line, const std::string &text);
|
||||||
|
|
||||||
|
void HighlightLine(int line)
|
||||||
|
{
|
||||||
|
mEditor.SetExecutionMarker(line);
|
||||||
|
}
|
||||||
private:
|
private:
|
||||||
TextEditor mEditor;
|
TextEditor mEditor;
|
||||||
TextEditor::Breakpoints m_breakPoints;
|
TextEditor::Breakpoints m_breakPoints;
|
||||||
|
|
|
||||||
|
|
@ -2,9 +2,9 @@
|
||||||
#include "gui.h"
|
#include "gui.h"
|
||||||
#include "IconsMaterialDesignIcons.h"
|
#include "IconsMaterialDesignIcons.h"
|
||||||
|
|
||||||
EmulatorWindow::EmulatorWindow(IStoryProject &proj)
|
EmulatorWindow::EmulatorWindow(IStoryManager &proj)
|
||||||
: WindowBase("Emulator")
|
: 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));
|
// ImGui::Image((void*)(intptr_t)my_image_texture, ImVec2(313, 367));
|
||||||
|
|
||||||
// float sz = ImGui::GetTextLineHeight();
|
// float sz = ImGui::GetTextLineHeight();
|
||||||
|
|
||||||
ImVec2 p = ImGui::GetCursorScreenPos();
|
ImVec2 p = ImGui::GetCursorScreenPos();
|
||||||
|
|
||||||
|
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::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));
|
ImGui::SetCursorScreenPos(ImVec2(p.x, p.y + 244));
|
||||||
|
|
||||||
|
|
@ -42,13 +51,25 @@ void EmulatorWindow::Draw()
|
||||||
ImGui::PushFont(ImGui::GetFont());
|
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::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::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::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::GetFont()->Scale = old_size;
|
||||||
ImGui::PopFont();
|
ImGui::PopFont();
|
||||||
|
|
@ -57,9 +78,20 @@ void EmulatorWindow::Draw()
|
||||||
|
|
||||||
if (ImGui::Button("Build"))
|
if (ImGui::Button("Build"))
|
||||||
{
|
{
|
||||||
m_project.Build();
|
m_story.Build();
|
||||||
}
|
}
|
||||||
ImGui::SameLine();
|
ImGui::SameLine();
|
||||||
|
|
||||||
WindowBase::EndDraw();
|
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));
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,17 +1,22 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "window_base.h"
|
#include "window_base.h"
|
||||||
#include "i_story_project.h"
|
#include "i_story_manager.h"
|
||||||
|
#include "gui.h"
|
||||||
|
|
||||||
class EmulatorWindow : public WindowBase
|
class EmulatorWindow : public WindowBase
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
EmulatorWindow(IStoryProject &proj);
|
EmulatorWindow(IStoryManager &proj);
|
||||||
|
|
||||||
void Initialize();
|
void Initialize();
|
||||||
virtual void Draw() override;
|
virtual void Draw() override;
|
||||||
|
|
||||||
|
void ClearImage();
|
||||||
|
void SetImage(const std::string &image);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
IStoryProject &m_project;
|
IStoryManager &m_story;
|
||||||
|
Gui::Image m_image;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -22,6 +22,7 @@ your use of the corresponding standard functions.
|
||||||
|
|
||||||
#include "IconsMaterialDesignIcons.h"
|
#include "IconsMaterialDesignIcons.h"
|
||||||
#include "IconsFontAwesome5_c.h"
|
#include "IconsFontAwesome5_c.h"
|
||||||
|
#include "qoi.h"
|
||||||
|
|
||||||
static void glfw_error_callback(int error, const char* description)
|
static void glfw_error_callback(int error, const char* description)
|
||||||
{
|
{
|
||||||
|
|
@ -34,24 +35,59 @@ static SDL_Renderer* renderer{nullptr};
|
||||||
|
|
||||||
#include "stb_image.h"
|
#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
|
// Simple helper function to load an image into a OpenGL texture with common settings
|
||||||
bool LoadTextureFromFile(const char* filename, Gui::Image &img)
|
bool LoadTextureFromFile(const char* filename, Gui::Image &img)
|
||||||
{
|
{
|
||||||
|
|
||||||
|
|
||||||
|
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;
|
int channels;
|
||||||
unsigned char* data = stbi_load(filename, &img.w, &img.h, &channels, 0);
|
data = stbi_load(filename, &img.w, &img.h, &channels, 0);
|
||||||
|
|
||||||
if (data == nullptr) {
|
if (data == nullptr) {
|
||||||
fprintf(stderr, "Failed to load image: %s\n", stbi_failure_reason());
|
fprintf(stderr, "Failed to load image: %s\n", stbi_failure_reason());
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// SDL3
|
// SDL3
|
||||||
// SDL_Surface* surface = SDL_CreateSurfaceFrom((void*)data, img.w, img.h, 4 * img.w, SDL_PIXELFORMAT_RGBA8888);
|
// SDL_Surface* surface = SDL_CreateSurfaceFrom((void*)data, img.w, img.h, 4 * img.w, SDL_PIXELFORMAT_RGBA8888);
|
||||||
|
|
||||||
// SDL2
|
// SDL2
|
||||||
SDL_Surface* surface = SDL_CreateRGBSurfaceFrom((void*)data, img.w, img.h, channels * 8, channels * img.w,
|
surface = SDL_CreateRGBSurfaceFrom((void*)data, img.w, img.h, channels * 8, channels * img.w,
|
||||||
0x000000ff, 0x0000ff00, 0x00ff0000, 0xff000000);
|
0x000000ff, 0x0000ff00, 0x00ff0000, 0xff000000);
|
||||||
|
stbi_image_free(data);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
if (surface == nullptr) {
|
if (surface == nullptr) {
|
||||||
|
|
@ -67,7 +103,7 @@ bool LoadTextureFromFile(const char* filename, Gui::Image &img)
|
||||||
|
|
||||||
// SDL_DestroySurface(surface); // SDL3
|
// SDL_DestroySurface(surface); // SDL3
|
||||||
SDL_FreeSurface(surface); // SDL2
|
SDL_FreeSurface(surface); // SDL2
|
||||||
stbi_image_free(data);
|
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
#ifndef I_STORY_PROJECT_H
|
#ifndef I_STORY_MANAGER_H
|
||||||
#define I_STORY_PROJECT_H
|
#define I_STORY_MANAGER_H
|
||||||
|
|
||||||
|
|
||||||
#include <string>
|
#include <string>
|
||||||
|
|
@ -10,10 +10,10 @@
|
||||||
#include "resource.h"
|
#include "resource.h"
|
||||||
#include "connection.h"
|
#include "connection.h"
|
||||||
|
|
||||||
class IStoryProject
|
class IStoryManager
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
virtual ~IStoryProject() {}
|
virtual ~IStoryManager() {}
|
||||||
|
|
||||||
virtual void Log(const std::string &txt, bool critical = false) = 0;
|
virtual void Log(const std::string &txt, bool critical = false) = 0;
|
||||||
virtual void PlaySoundFile(const std::string &fileName) = 0;
|
virtual void PlaySoundFile(const std::string &fileName) = 0;
|
||||||
|
|
@ -31,7 +31,12 @@ public:
|
||||||
virtual void Build() = 0;
|
virtual void Build() = 0;
|
||||||
virtual std::list<std::shared_ptr<Connection>> GetNodeConnections(unsigned long nodeId) = 0;
|
virtual std::list<std::shared_ptr<Connection>> GetNodeConnections(unsigned long nodeId) = 0;
|
||||||
virtual std::string GetNodeEntryLabel(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
|
||||||
|
|
@ -4,6 +4,7 @@
|
||||||
|
|
||||||
#include "platform_folders.h"
|
#include "platform_folders.h"
|
||||||
#include "uuid.h"
|
#include "uuid.h"
|
||||||
|
#include "media_converter.h"
|
||||||
|
|
||||||
#ifdef USE_WINDOWS_OS
|
#ifdef USE_WINDOWS_OS
|
||||||
#include <winsock2.h>
|
#include <winsock2.h>
|
||||||
|
|
@ -22,9 +23,24 @@ MainWindow::MainWindow()
|
||||||
: m_emulatorWindow(*this)
|
: m_emulatorWindow(*this)
|
||||||
, m_resourcesWindow(*this)
|
, m_resourcesWindow(*this)
|
||||||
, m_nodeEditorWindow(*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<uint8_t(chip32_ctx_t *, uint8_t)>::func = std::bind(&MainWindow::Syscall, this, std::placeholders::_1, std::placeholders::_2);
|
||||||
|
m_chip32_ctx.syscall = static_cast<syscall_t>(Callback<uint8_t(chip32_ctx_t *, uint8_t)>::callback);
|
||||||
|
|
||||||
|
m_story.Clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
MainWindow::~MainWindow()
|
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()
|
void MainWindow::DrawStatusBar()
|
||||||
{
|
{
|
||||||
float statusWindowHeight = ImGui::GetFrameHeight() * 1.4f;
|
float statusWindowHeight = ImGui::GetFrameHeight() * 1.4f;
|
||||||
|
|
@ -221,11 +425,11 @@ void MainWindow::OpenProjectDialog()
|
||||||
std::string filePath = ImGuiFileDialog::Instance()->GetCurrentPath();
|
std::string filePath = ImGuiFileDialog::Instance()->GetCurrentPath();
|
||||||
|
|
||||||
|
|
||||||
m_project.Initialize(filePathName);
|
m_story.Initialize(filePathName);
|
||||||
|
|
||||||
nlohmann::json model;
|
nlohmann::json model;
|
||||||
|
|
||||||
if (m_project.Load(filePathName, model, m_resources))
|
if (m_story.Load(filePathName, model, m_resources))
|
||||||
{
|
{
|
||||||
Log("Open project success");
|
Log("Open project success");
|
||||||
m_nodeEditorWindow.Load(model);
|
m_nodeEditorWindow.Load(model);
|
||||||
|
|
@ -247,7 +451,7 @@ void MainWindow::OpenProjectDialog()
|
||||||
|
|
||||||
void MainWindow::EnableProject()
|
void MainWindow::EnableProject()
|
||||||
{
|
{
|
||||||
auto proj = m_project.GetProjectFilePath();
|
auto proj = m_story.GetProjectFilePath();
|
||||||
// Add to recent if not exists
|
// Add to recent if not exists
|
||||||
if (std::find(m_recentProjects.begin(), m_recentProjects.end(), proj) != m_recentProjects.end())
|
if (std::find(m_recentProjects.begin(), m_recentProjects.end(), proj) != m_recentProjects.end())
|
||||||
{
|
{
|
||||||
|
|
@ -426,21 +630,21 @@ void MainWindow::NewProjectPopup()
|
||||||
|
|
||||||
if (valid)
|
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)
|
if (display_item_current_idx == 0)
|
||||||
{
|
{
|
||||||
m_project.SetDisplayFormat(320, 240);
|
m_story.SetDisplayFormat(320, 240);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
m_project.SetDisplayFormat(640, 480);
|
m_story.SetDisplayFormat(640, 480);
|
||||||
}
|
}
|
||||||
|
|
||||||
m_project.SetImageFormat(GetImageFormat(image_item_current_idx));
|
m_story.SetImageFormat(GetImageFormat(image_item_current_idx));
|
||||||
m_project.SetSoundFormat(GetSoundFormat(sound_item_current_idx));
|
m_story.SetSoundFormat(GetSoundFormat(sound_item_current_idx));
|
||||||
m_project.SetName(project_name);
|
m_story.SetName(project_name);
|
||||||
m_project.SetUuid(UUID().String());
|
m_story.SetUuid(UUID().String());
|
||||||
|
|
||||||
SaveProject();
|
SaveProject();
|
||||||
EnableProject();
|
EnableProject();
|
||||||
|
|
@ -466,12 +670,12 @@ void MainWindow::SaveProject()
|
||||||
{
|
{
|
||||||
nlohmann::json model;
|
nlohmann::json model;
|
||||||
m_nodeEditorWindow.Save(model);
|
m_nodeEditorWindow.Save(model);
|
||||||
m_project.Save(model, m_resources);
|
m_story.Save(model, m_resources);
|
||||||
}
|
}
|
||||||
|
|
||||||
void MainWindow::CloseProject()
|
void MainWindow::CloseProject()
|
||||||
{
|
{
|
||||||
m_project.Clear();
|
m_story.Clear();
|
||||||
m_nodeEditorWindow.Clear();
|
m_nodeEditorWindow.Clear();
|
||||||
|
|
||||||
// m_model.Clear();
|
// m_model.Clear();
|
||||||
|
|
@ -505,6 +709,10 @@ void MainWindow::Loop()
|
||||||
DrawMainMenuBar();
|
DrawMainMenuBar();
|
||||||
// DrawStatusBar();
|
// DrawStatusBar();
|
||||||
|
|
||||||
|
|
||||||
|
ProcessStory();
|
||||||
|
|
||||||
|
|
||||||
// ------------ Draw all windows
|
// ------------ Draw all windows
|
||||||
m_consoleWindow.Draw();
|
m_consoleWindow.Draw();
|
||||||
m_emulatorWindow.Draw();
|
m_emulatorWindow.Draw();
|
||||||
|
|
@ -543,12 +751,12 @@ void MainWindow::Log(const std::string &txt, bool critical)
|
||||||
void MainWindow::PlaySoundFile(const std::string &fileName)
|
void MainWindow::PlaySoundFile(const std::string &fileName)
|
||||||
{
|
{
|
||||||
Log("Play sound file: " + fileName);
|
Log("Play sound file: " + fileName);
|
||||||
m_project.PlaySoundFile(fileName);
|
m_player.Play(fileName);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string MainWindow::BuildFullAssetsPath(const std::string &fileName) const
|
std::string MainWindow::BuildFullAssetsPath(const std::string &fileName) const
|
||||||
{
|
{
|
||||||
return m_project.BuildFullAssetsPath(fileName);
|
return m_story.BuildFullAssetsPath(fileName);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::pair<FilterIterator, FilterIterator> MainWindow::Images()
|
std::pair<FilterIterator, FilterIterator> MainWindow::Images()
|
||||||
|
|
@ -647,9 +855,9 @@ void MainWindow::GenerateBinary()
|
||||||
// FIXME
|
// FIXME
|
||||||
// m_ramView->SetMemory(m_ram_data, sizeof(m_ram_data));
|
// m_ramView->SetMemory(m_ram_data, sizeof(m_ram_data));
|
||||||
// m_romView->SetMemory(m_rom_data, m_program.size());
|
// m_romView->SetMemory(m_rom_data, m_program.size());
|
||||||
m_project.SaveStory(m_program);
|
m_story.SaveStory(m_program);
|
||||||
chip32_initialize(&m_chip32_ctx);
|
chip32_initialize(&m_chip32_ctx);
|
||||||
m_dbg.run_result = VM_OK;
|
m_dbg.run_result = VM_READY;
|
||||||
UpdateVmView();
|
UpdateVmView();
|
||||||
// DebugContext::DumpCodeAssembler(m_assembler);
|
// DebugContext::DumpCodeAssembler(m_assembler);
|
||||||
}
|
}
|
||||||
|
|
@ -672,14 +880,70 @@ void MainWindow::UpdateVmView()
|
||||||
{
|
{
|
||||||
// FIXME
|
// FIXME
|
||||||
// m_vmDock->updateRegistersView(m_chip32_ctx);
|
// 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<Chip32::Instr>::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
|
// Refresh RAM content
|
||||||
// m_ramView->SetMemory(m_ram_data, m_chip32_ctx.ram.size);
|
// m_ramView->SetMemory(m_ram_data, m_chip32_ctx.ram.size);
|
||||||
}
|
}
|
||||||
|
|
||||||
void MainWindow::ConvertResources()
|
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()
|
void MainWindow::SaveParams()
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,9 @@
|
||||||
#ifndef MAINWINDOW_H
|
#ifndef MAINWINDOW_H
|
||||||
#define MAINWINDOW_H
|
#define MAINWINDOW_H
|
||||||
|
|
||||||
|
|
||||||
|
#include <functional>
|
||||||
|
|
||||||
#include "gui.h"
|
#include "gui.h"
|
||||||
#include "console_window.h"
|
#include "console_window.h"
|
||||||
#include "code_editor.h"
|
#include "code_editor.h"
|
||||||
|
|
@ -13,7 +16,8 @@
|
||||||
#include "chip32_assembler.h"
|
#include "chip32_assembler.h"
|
||||||
#include "chip32_vm.h"
|
#include "chip32_vm.h"
|
||||||
#include "story_project.h"
|
#include "story_project.h"
|
||||||
#include "i_story_project.h"
|
#include "i_story_manager.h"
|
||||||
|
#include "thread_safe_queue.h"
|
||||||
|
|
||||||
struct DebugContext
|
struct DebugContext
|
||||||
{
|
{
|
||||||
|
|
@ -25,6 +29,10 @@ struct DebugContext
|
||||||
|
|
||||||
std::set<int> m_breakpoints;
|
std::set<int> m_breakpoints;
|
||||||
|
|
||||||
|
void Stop() {
|
||||||
|
run_result = VM_FINISHED;
|
||||||
|
}
|
||||||
|
|
||||||
static void DumpCodeAssembler(Chip32::Assembler & assembler) {
|
static void DumpCodeAssembler(Chip32::Assembler & assembler) {
|
||||||
|
|
||||||
for (std::vector<Chip32::Instr>::const_iterator iter = assembler.Begin();
|
for (std::vector<Chip32::Instr>::const_iterator iter = assembler.Begin();
|
||||||
|
|
@ -51,7 +59,7 @@ struct DebugContext
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
#include <functional>
|
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
struct Callback;
|
struct Callback;
|
||||||
|
|
@ -70,7 +78,7 @@ std::function<Ret(Params...)> Callback<Ret(Params...)>::func;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
class MainWindow : public IStoryProject
|
class MainWindow : public IStoryManager, public IAudioEvent
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
MainWindow();
|
MainWindow();
|
||||||
|
|
@ -80,8 +88,9 @@ public:
|
||||||
void Loop();
|
void Loop();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
enum VmEventType { EvNoEvent, EvStep, EvOkButton, EvLeftButton, EvRightButton, EvAudioFinished};
|
||||||
|
|
||||||
StoryProject m_project;
|
StoryProject m_story;
|
||||||
|
|
||||||
// VM
|
// VM
|
||||||
uint8_t m_rom_data[16*1024];
|
uint8_t m_rom_data[16*1024];
|
||||||
|
|
@ -95,6 +104,7 @@ private:
|
||||||
DebugContext m_dbg;
|
DebugContext m_dbg;
|
||||||
std::string m_currentCode;
|
std::string m_currentCode;
|
||||||
|
|
||||||
|
|
||||||
std::vector<std::string> m_recentProjects;
|
std::vector<std::string> m_recentProjects;
|
||||||
|
|
||||||
ResourceManager m_resources;
|
ResourceManager m_resources;
|
||||||
|
|
@ -110,8 +120,17 @@ private:
|
||||||
|
|
||||||
PropertiesWindow m_PropertiesWindow;
|
PropertiesWindow m_PropertiesWindow;
|
||||||
|
|
||||||
|
AudioPlayer m_player;
|
||||||
|
|
||||||
// From IStoryProject (proxy to StoryProject class)
|
struct VmEvent
|
||||||
|
{
|
||||||
|
VmEventType type;
|
||||||
|
};
|
||||||
|
|
||||||
|
ThreadSafeQueue<VmEvent> m_eventQueue;
|
||||||
|
|
||||||
|
|
||||||
|
// From IStoryManager (proxy to StoryProject class)
|
||||||
virtual void Log(const std::string &txt, bool critical = false) override;
|
virtual void Log(const std::string &txt, bool critical = false) override;
|
||||||
virtual void PlaySoundFile(const std::string &fileName) override;;
|
virtual void PlaySoundFile(const std::string &fileName) override;;
|
||||||
virtual std::string BuildFullAssetsPath(const std::string &fileName) const override;
|
virtual std::string BuildFullAssetsPath(const std::string &fileName) const override;
|
||||||
|
|
@ -125,6 +144,13 @@ private:
|
||||||
virtual void Build() override;
|
virtual void Build() override;
|
||||||
virtual std::list<std::shared_ptr<Connection>> GetNodeConnections(unsigned long nodeId) override;
|
virtual std::list<std::shared_ptr<Connection>> GetNodeConnections(unsigned long nodeId) override;
|
||||||
virtual std::string GetNodeEntryLabel(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 SaveParams();
|
||||||
void LoadParams();
|
void LoadParams();
|
||||||
|
|
@ -143,6 +169,10 @@ private:
|
||||||
void ConvertResources();
|
void ConvertResources();
|
||||||
void GenerateBinary();
|
void GenerateBinary();
|
||||||
void UpdateVmView();
|
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
|
#endif // MAINWINDOW_H
|
||||||
|
|
|
||||||
|
|
@ -4,9 +4,9 @@ namespace ed = ax::NodeEditor;
|
||||||
#include "IconsMaterialDesignIcons.h"
|
#include "IconsMaterialDesignIcons.h"
|
||||||
#include "story_project.h"
|
#include "story_project.h"
|
||||||
|
|
||||||
MediaNode::MediaNode(const std::string &title, IStoryProject &proj)
|
MediaNode::MediaNode(const std::string &title, IStoryManager &proj)
|
||||||
: BaseNode(title, proj)
|
: BaseNode(title, proj)
|
||||||
, m_project(proj)
|
, m_story(proj)
|
||||||
{
|
{
|
||||||
Gui::LoadRawImage("fairy.png", m_image);
|
Gui::LoadRawImage("fairy.png", m_image);
|
||||||
|
|
||||||
|
|
@ -87,8 +87,6 @@ void MediaNode::Draw()
|
||||||
|
|
||||||
DrawPins();
|
DrawPins();
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
BaseNode::FrameEnd();
|
BaseNode::FrameEnd();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
@ -144,7 +142,7 @@ void MediaNode::DrawProperties()
|
||||||
|
|
||||||
if (ImGui::Button(m_buttonUniqueName.c_str()))
|
if (ImGui::Button(m_buttonUniqueName.c_str()))
|
||||||
{
|
{
|
||||||
m_project.PlaySoundFile(m_soundPath);
|
m_story.PlaySoundFile(m_soundPath);
|
||||||
}
|
}
|
||||||
|
|
||||||
ImGui::SameLine();
|
ImGui::SameLine();
|
||||||
|
|
@ -163,7 +161,7 @@ void MediaNode::DrawProperties()
|
||||||
if (ImGui::BeginPopup("popup_button")) {
|
if (ImGui::BeginPopup("popup_button")) {
|
||||||
ImGui::SeparatorText(isImage ? "Images" : "Sounds");
|
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;
|
int n = 0;
|
||||||
for (auto it = filtreDebut; it != filtreFin; ++it, n++)
|
for (auto it = filtreDebut; it != filtreFin; ++it, n++)
|
||||||
{
|
{
|
||||||
|
|
@ -188,13 +186,13 @@ void MediaNode::DrawProperties()
|
||||||
void MediaNode::SetImage(const std::string &f)
|
void MediaNode::SetImage(const std::string &f)
|
||||||
{
|
{
|
||||||
m_image.name = 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)
|
void MediaNode::SetSound(const std::string &f)
|
||||||
{
|
{
|
||||||
m_soundName = 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, "
|
<< " DC32, "
|
||||||
<< nb_out_conns << ", ";
|
<< nb_out_conns << ", ";
|
||||||
|
|
||||||
std::list<std::shared_ptr<Connection>> conns = m_project.GetNodeConnections(GetId());
|
std::list<std::shared_ptr<Connection>> conns = m_story.GetNodeConnections(GetId());
|
||||||
int i = 0;
|
int i = 0;
|
||||||
for (auto & c : conns)
|
for (auto & c : conns)
|
||||||
{
|
{
|
||||||
std::stringstream ssChoice;
|
std::stringstream ssChoice;
|
||||||
|
|
||||||
// On va chercher le label d'entrée du noeud connecté à l'autre bout
|
// 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))
|
if (i < (nb_out_conns - 1))
|
||||||
{
|
{
|
||||||
ss << ", ";
|
ss << ", ";
|
||||||
|
|
@ -311,7 +309,7 @@ std::string MediaNode::Build()
|
||||||
}
|
}
|
||||||
else if (nb_out_conns == 1) // it is a transition node
|
else if (nb_out_conns == 1) // it is a transition node
|
||||||
{
|
{
|
||||||
std::list<std::shared_ptr<Connection>> conns = m_project.GetNodeConnections(GetId());
|
std::list<std::shared_ptr<Connection>> conns = m_story.GetNodeConnections(GetId());
|
||||||
|
|
||||||
|
|
||||||
for (auto c : conns)
|
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
|
// On place dans R0 le prochain noeud à exécuter en cas de OK
|
||||||
ss << "lcons r0, "
|
ss << "lcons r0, "
|
||||||
<< m_project.GetNodeEntryLabel(c->inNodeId) << "\n"
|
<< m_story.GetNodeEntryLabel(c->inNodeId) << "\n"
|
||||||
<< "ret\n";
|
<< "ret\n";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -6,7 +6,7 @@
|
||||||
#include <set>
|
#include <set>
|
||||||
|
|
||||||
#include "base_node.h"
|
#include "base_node.h"
|
||||||
#include "i_story_project.h"
|
#include "i_story_manager.h"
|
||||||
#include "gui.h"
|
#include "gui.h"
|
||||||
#include <imgui_node_editor.h>
|
#include <imgui_node_editor.h>
|
||||||
|
|
||||||
|
|
@ -14,7 +14,7 @@
|
||||||
class MediaNode : public BaseNode
|
class MediaNode : public BaseNode
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
MediaNode(const std::string &title, IStoryProject &proj);
|
MediaNode(const std::string &title, IStoryManager &proj);
|
||||||
|
|
||||||
void Draw() override;
|
void Draw() override;
|
||||||
|
|
||||||
|
|
@ -25,7 +25,7 @@ public:
|
||||||
virtual std::string GetEntryLabel() override;
|
virtual std::string GetEntryLabel() override;
|
||||||
virtual std::string GenerateConstants() override;
|
virtual std::string GenerateConstants() override;
|
||||||
private:
|
private:
|
||||||
IStoryProject &m_project;
|
IStoryManager &m_story;
|
||||||
Gui::Image m_image;
|
Gui::Image m_image;
|
||||||
std::string m_soundName;
|
std::string m_soundName;
|
||||||
std::string m_soundPath;
|
std::string m_soundPath;
|
||||||
|
|
|
||||||
|
|
@ -10,9 +10,9 @@
|
||||||
#include "gui.h"
|
#include "gui.h"
|
||||||
|
|
||||||
|
|
||||||
NodeEditorWindow::NodeEditorWindow(IStoryProject &proj)
|
NodeEditorWindow::NodeEditorWindow(IStoryManager &proj)
|
||||||
: WindowBase("Node editor")
|
: WindowBase("Node editor")
|
||||||
, m_project(proj)
|
, m_story(proj)
|
||||||
{
|
{
|
||||||
|
|
||||||
registerNode<MediaNode>("media-node");
|
registerNode<MediaNode>("media-node");
|
||||||
|
|
@ -47,7 +47,7 @@ void NodeEditorWindow::LoadNode(const nlohmann::json &nodeJson)
|
||||||
nlohmann::json internalDataJson = nodeJson["internal-data"];
|
nlohmann::json internalDataJson = nodeJson["internal-data"];
|
||||||
std::string type = nodeJson["type"].get<std::string>();
|
std::string type = nodeJson["type"].get<std::string>();
|
||||||
|
|
||||||
auto n = createNode(type, "", m_project);
|
auto n = createNode(type, "", m_story);
|
||||||
if (n)
|
if (n)
|
||||||
{
|
{
|
||||||
n->SetType(type); // FIXME: set type in createNode factory?
|
n->SetType(type); // FIXME: set type in createNode factory?
|
||||||
|
|
@ -225,7 +225,7 @@ uint32_t NodeEditorWindow::FindFirstNode() const
|
||||||
if (!foundConnection)
|
if (!foundConnection)
|
||||||
{
|
{
|
||||||
id = n->GetId();
|
id = n->GetId();
|
||||||
m_project.Log("First node is: " + std::to_string(id));
|
m_story.Log("First node is: " + std::to_string(id));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -9,7 +9,7 @@
|
||||||
#include <imgui_node_editor.h>
|
#include <imgui_node_editor.h>
|
||||||
#include "base_node.h"
|
#include "base_node.h"
|
||||||
#include "window_base.h"
|
#include "window_base.h"
|
||||||
#include "i_story_project.h"
|
#include "i_story_manager.h"
|
||||||
#include "story_project.h"
|
#include "story_project.h"
|
||||||
#include "json.hpp"
|
#include "json.hpp"
|
||||||
|
|
||||||
|
|
@ -48,7 +48,7 @@ public:
|
||||||
std::shared_ptr<Connection> model;
|
std::shared_ptr<Connection> model;
|
||||||
};
|
};
|
||||||
|
|
||||||
NodeEditorWindow(IStoryProject &proj);
|
NodeEditorWindow(IStoryManager &proj);
|
||||||
~NodeEditorWindow();
|
~NodeEditorWindow();
|
||||||
virtual void Draw() override;
|
virtual void Draw() override;
|
||||||
|
|
||||||
|
|
@ -63,7 +63,7 @@ public:
|
||||||
std::shared_ptr<BaseNode> GetSelectedNode();
|
std::shared_ptr<BaseNode> GetSelectedNode();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
IStoryProject &m_project;
|
IStoryManager &m_story;
|
||||||
|
|
||||||
ed::EditorContext* m_context = nullptr;
|
ed::EditorContext* m_context = nullptr;
|
||||||
|
|
||||||
|
|
@ -90,12 +90,12 @@ private:
|
||||||
|
|
||||||
template<class NodeType>
|
template<class NodeType>
|
||||||
struct Factory {
|
struct Factory {
|
||||||
static std::shared_ptr<BaseNode> create_func(const std::string &title, IStoryProject &proj) {
|
static std::shared_ptr<BaseNode> create_func(const std::string &title, IStoryManager &proj) {
|
||||||
return std::make_shared<NodeType>(title, proj);
|
return std::make_shared<NodeType>(title, proj);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef std::shared_ptr<BaseNode> (*GenericCreator)(const std::string &title, IStoryProject &proj);
|
typedef std::shared_ptr<BaseNode> (*GenericCreator)(const std::string &title, IStoryManager &proj);
|
||||||
typedef std::map<std::string, GenericCreator> Registry;
|
typedef std::map<std::string, GenericCreator> Registry;
|
||||||
Registry m_registry;
|
Registry m_registry;
|
||||||
|
|
||||||
|
|
@ -104,7 +104,7 @@ private:
|
||||||
m_registry.insert(typename Registry::value_type(key, Factory<Derived>::create_func));
|
m_registry.insert(typename Registry::value_type(key, Factory<Derived>::create_func));
|
||||||
}
|
}
|
||||||
|
|
||||||
std::shared_ptr<BaseNode> createNode(const std::string& key, const std::string &title, IStoryProject &proj) {
|
std::shared_ptr<BaseNode> createNode(const std::string& key, const std::string &title, IStoryManager &proj) {
|
||||||
typename Registry::const_iterator i = m_registry.find(key);
|
typename Registry::const_iterator i = m_registry.find(key);
|
||||||
if (i == m_registry.end()) {
|
if (i == m_registry.end()) {
|
||||||
throw std::invalid_argument(std::string(__PRETTY_FUNCTION__) +
|
throw std::invalid_argument(std::string(__PRETTY_FUNCTION__) +
|
||||||
|
|
|
||||||
|
|
@ -8,9 +8,9 @@
|
||||||
|
|
||||||
//static thread_pool pool;
|
//static thread_pool pool;
|
||||||
|
|
||||||
ResourcesWindow::ResourcesWindow(IStoryProject &project)
|
ResourcesWindow::ResourcesWindow(IStoryManager &project)
|
||||||
: WindowBase("Resources")
|
: WindowBase("Resources")
|
||||||
, m_project(project)
|
, m_story(project)
|
||||||
{
|
{
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
@ -44,7 +44,7 @@ void ResourcesWindow::ChooseFile()
|
||||||
|
|
||||||
|
|
||||||
std::filesystem::path p(filePathName);
|
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);
|
std::filesystem::copy(p, p2, std::filesystem::copy_options::overwrite_existing);
|
||||||
|
|
||||||
auto res = std::make_shared<Resource>();
|
auto res = std::make_shared<Resource>();
|
||||||
|
|
@ -56,7 +56,7 @@ void ResourcesWindow::ChooseFile()
|
||||||
res->format = ext;
|
res->format = ext;
|
||||||
res->type = m_soundFile ? "sound" : "image";
|
res->type = m_soundFile ? "sound" : "image";
|
||||||
res->file = p.filename().generic_string();
|
res->file = p.filename().generic_string();
|
||||||
m_project.AddResource(res);
|
m_story.AddResource(res);
|
||||||
}
|
}
|
||||||
|
|
||||||
// close
|
// close
|
||||||
|
|
@ -104,7 +104,7 @@ void ResourcesWindow::Draw()
|
||||||
|
|
||||||
ImGui::TableHeadersRow();
|
ImGui::TableHeadersRow();
|
||||||
|
|
||||||
auto [b, e] = m_project.Resources();
|
auto [b, e] = m_story.Resources();
|
||||||
|
|
||||||
int id = 1000;
|
int id = 1000;
|
||||||
for (auto it = b; it != e; ++it)
|
for (auto it = b; it != e; ++it)
|
||||||
|
|
@ -152,7 +152,7 @@ void ResourcesWindow::Draw()
|
||||||
ImGui::TableNextColumn();
|
ImGui::TableNextColumn();
|
||||||
if (ImGui::SmallButton("Delete"))
|
if (ImGui::SmallButton("Delete"))
|
||||||
{
|
{
|
||||||
m_project.DeleteResource(it);
|
m_story.DeleteResource(it);
|
||||||
quitLoop = true;
|
quitLoop = true;
|
||||||
}
|
}
|
||||||
ImGui::PopID();
|
ImGui::PopID();
|
||||||
|
|
|
||||||
|
|
@ -3,18 +3,18 @@
|
||||||
#include <vector>
|
#include <vector>
|
||||||
#include <map>
|
#include <map>
|
||||||
#include <mutex>
|
#include <mutex>
|
||||||
#include "i_story_project.h"
|
#include "i_story_manager.h"
|
||||||
#include "window_base.h"
|
#include "window_base.h"
|
||||||
|
|
||||||
class ResourcesWindow : public WindowBase
|
class ResourcesWindow : public WindowBase
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
ResourcesWindow(IStoryProject &project);
|
ResourcesWindow(IStoryManager &project);
|
||||||
~ResourcesWindow();
|
~ResourcesWindow();
|
||||||
virtual void Draw() override;
|
virtual void Draw() override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
IStoryProject &m_project;
|
IStoryManager &m_story;
|
||||||
|
|
||||||
bool m_showImportDialog{false};
|
bool m_showImportDialog{false};
|
||||||
bool m_soundFile{false};
|
bool m_soundFile{false};
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue