mirror of
https://github.com/arabine/open-story-teller.git
synced 2025-12-10 18:33:15 +01:00
Compare commits
2 commits
d6df8b65ab
...
6ec1f39db7
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
6ec1f39db7 | ||
|
|
47552d4719 |
12 changed files with 264 additions and 52 deletions
|
|
@ -208,6 +208,24 @@ public:
|
|||
return result;
|
||||
}
|
||||
|
||||
static std::string ValueTypeToString(ValueType type) {
|
||||
switch (type) {
|
||||
case ValueType::INTEGER: return "Integer";
|
||||
case ValueType::FLOAT: return "Float";
|
||||
case ValueType::BOOL: return "Bool";
|
||||
case ValueType::STRING: return "String";
|
||||
default: return "Unknown";
|
||||
}
|
||||
}
|
||||
|
||||
static ValueType StringToValueType(const std::string& type) {
|
||||
if (type == "Integer") return ValueType::INTEGER;
|
||||
if (type == "Float") return ValueType::FLOAT;
|
||||
if (type == "Bool") return ValueType::BOOL;
|
||||
if (type == "String") return ValueType::STRING;
|
||||
throw std::runtime_error("[variable.h] StringToValueType(): Invalid value type string");
|
||||
}
|
||||
|
||||
private:
|
||||
std::string m_variableName; // nom humain
|
||||
ValueType m_valueType;
|
||||
|
|
|
|||
|
|
@ -118,12 +118,18 @@ private:
|
|||
auto* varNode = inputNode->GetAs<VariableNode>();
|
||||
if (varNode) {
|
||||
auto var = varNode->GetVariable();
|
||||
// Generate code to load the variable value
|
||||
// FIXME: hardcoded 4 bytes, replace by actual real variable size
|
||||
m_assembly << " load r" << reg << ", $" << var->GetLabel() << ", 4" << "; Load variable " << var->GetVariableName() << "\n";
|
||||
m_assembly << " push r" << reg << "\n";
|
||||
// Assuming we have a function to load the variable value
|
||||
// m_assembly << " load r0, " << varNode->GetVariableName() << "\n";
|
||||
|
||||
if (var)
|
||||
{
|
||||
// Generate code to load the variable value
|
||||
// FIXME: hardcoded 4 bytes, replace by actual real variable size
|
||||
m_assembly << " load r" << reg << ", $" << var->GetLabel() << ", 4" << "; Load variable " << var->GetVariableName() << "\n";
|
||||
m_assembly << " push r" << reg << "\n";
|
||||
}
|
||||
else
|
||||
{
|
||||
throw std::runtime_error("ERROR! Variable not set in node: " + inputNode->node->GetId());
|
||||
}
|
||||
}
|
||||
reg++;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -10,6 +10,7 @@ PrintNode::PrintNode(const std::string &type)
|
|||
// Create empty variable in memory
|
||||
auto v = std::make_shared<Variable>(m_label);
|
||||
v->SetTextValue("");
|
||||
v->SetConstant(true);
|
||||
m_label = v->GetLabel();
|
||||
m_variables[m_label] = v;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -19,7 +19,7 @@ StoryProject::StoryProject(ILogger &log)
|
|||
: m_log(log)
|
||||
{
|
||||
// registerNode<MediaNode>("media-node");
|
||||
registerNode<FunctionNode>("operator-node");
|
||||
registerNode<OperatorNode>("operator-node");
|
||||
registerNode<FunctionNode>("function-node");
|
||||
registerNode<VariableNode>("variable-node");
|
||||
registerNode<PrintNode>("print-node");
|
||||
|
|
@ -384,6 +384,7 @@ bool StoryProject::UseResource(const std::string &label)
|
|||
|
||||
bool StoryProject::GenerateScript(std::string &codeStr)
|
||||
{
|
||||
bool retCode = true;
|
||||
std::stringstream code;
|
||||
|
||||
// Empty resources usage
|
||||
|
|
@ -403,43 +404,40 @@ bool StoryProject::GenerateScript(std::string &codeStr)
|
|||
// Create generator
|
||||
AssemblyGeneratorChip32 generator(context);
|
||||
|
||||
|
||||
generator.Reset();
|
||||
|
||||
// Generate header comments
|
||||
generator.GenerateHeader();
|
||||
|
||||
// Generate data section
|
||||
generator.StartSection(AssemblyGenerator::Section::DATA);
|
||||
for (const auto & p : m_pages)
|
||||
try
|
||||
{
|
||||
p->BuildNodesVariables(generator);
|
||||
generator.Reset();
|
||||
|
||||
// Generate header comments
|
||||
generator.GenerateHeader();
|
||||
|
||||
// Generate text section
|
||||
generator.StartSection(AssemblyGenerator::Section::TEXT);
|
||||
for (const auto & p : m_pages)
|
||||
{
|
||||
p->BuildNodes(generator);
|
||||
}
|
||||
|
||||
// Generate data section
|
||||
generator.StartSection(AssemblyGenerator::Section::DATA);
|
||||
for (const auto & p : m_pages)
|
||||
{
|
||||
p->BuildNodesVariables(generator);
|
||||
}
|
||||
generator.GenerateGlobalVariables(m_variables);
|
||||
|
||||
generator.GenerateExit();
|
||||
|
||||
}
|
||||
generator.GenerateGlobalVariables(m_variables);
|
||||
|
||||
// Generate text section
|
||||
generator.StartSection(AssemblyGenerator::Section::TEXT);
|
||||
|
||||
for (const auto & p : m_pages)
|
||||
catch (const std::exception &e)
|
||||
{
|
||||
p->BuildNodes(generator);
|
||||
m_log.Log(e.what(), true);
|
||||
retCode = false;
|
||||
}
|
||||
|
||||
generator.GenerateExit();
|
||||
|
||||
codeStr = generator.GetAssembly();
|
||||
|
||||
// Add our utility functions
|
||||
// std::string buffer;
|
||||
|
||||
// std::ifstream f("scripts/media.chip32");
|
||||
// f.seekg(0, std::ios::end);
|
||||
// buffer.resize(f.tellg());
|
||||
// f.seekg(0);
|
||||
// f.read(buffer.data(), buffer.size());
|
||||
// codeStr += buffer;
|
||||
|
||||
return true;
|
||||
return retCode;
|
||||
}
|
||||
|
||||
bool StoryProject::GenerateBinary(const std::string &code, Chip32::Assembler::Error &err)
|
||||
|
|
@ -503,6 +501,40 @@ bool StoryProject::Load(ResourceManager &manager)
|
|||
ModelFromJson(j);
|
||||
m_initialized = true;
|
||||
}
|
||||
|
||||
if (j.contains("variables"))
|
||||
{
|
||||
nlohmann::json variablesData = j["variables"];
|
||||
|
||||
for (const auto &obj : variablesData)
|
||||
{
|
||||
auto v = std::make_shared<Variable>(obj["label"].get<std::string>());
|
||||
v->SetUuid(obj["uuid"].get<std::string>());
|
||||
v->SetValueType(Variable::StringToValueType(obj["type"].get<std::string>()));
|
||||
v->SetScalePower(obj["scale"].get<int>());
|
||||
v->SetConstant(obj["constant"].get<bool>());
|
||||
v->SetVariableName(obj["name"].get<std::string>());
|
||||
|
||||
if (v->IsFloat())
|
||||
{
|
||||
v->SetFloatValue(std::stof(obj["value"].get<std::string>()));
|
||||
}
|
||||
else if (v->IsInteger())
|
||||
{
|
||||
v->SetIntegerValue(std::stoi(obj["value"].get<std::string>()));
|
||||
}
|
||||
else if (v->IsString())
|
||||
{
|
||||
v->SetTextValue(obj["value"].get<std::string>());
|
||||
}
|
||||
else if (v->IsBool())
|
||||
{
|
||||
v->SetBoolValue(obj["value"].get<std::string>() == "true");
|
||||
}
|
||||
|
||||
m_variables.push_back(v);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -544,6 +576,40 @@ void StoryProject::Save(ResourceManager &manager)
|
|||
ModelToJson(model);
|
||||
j["pages"] = model;
|
||||
|
||||
nlohmann::json variablesData;
|
||||
for (const auto &v : m_variables)
|
||||
{
|
||||
std::string value;
|
||||
|
||||
if (v->IsFloat())
|
||||
{
|
||||
value = std::to_string(v->GetFloatValue());
|
||||
}
|
||||
else if (v->IsInteger())
|
||||
{
|
||||
value = std::to_string(v->GetIntegerValue());
|
||||
}
|
||||
else if (v->IsString())
|
||||
{
|
||||
value = v->GetStringValue();
|
||||
}
|
||||
else if (v->IsBool())
|
||||
{
|
||||
value = v->GetBoolValue() ? "true" : "false";
|
||||
}
|
||||
|
||||
nlohmann::json obj = {{"name", v->GetVariableName()},
|
||||
{"label", v->GetLabel()},
|
||||
{"uuid", v->GetUuid()},
|
||||
{"value", value},
|
||||
{"scale", v->GetScalePower()},
|
||||
{"constant", v->IsConstant()},
|
||||
{"type", Variable::ValueTypeToString(v->GetValueType())}};
|
||||
|
||||
variablesData.push_back(obj);
|
||||
}
|
||||
j["variables"] = variablesData;
|
||||
|
||||
std::ofstream o(m_project_file_path);
|
||||
o << std::setw(4) << j << std::endl;
|
||||
}
|
||||
|
|
@ -555,6 +621,7 @@ void StoryProject::Clear()
|
|||
m_working_dir = "";
|
||||
m_project_file_path = "";
|
||||
m_initialized = false;
|
||||
m_variables.clear();
|
||||
}
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -87,7 +87,7 @@ uint8_t vm_syscall(chip32_ctx_t *ctx, uint8_t code)
|
|||
if (m_chip32_ctx.registers[R0] != 0)
|
||||
{
|
||||
// image file name address is in R0
|
||||
// QString imageFile = m_model.BuildFullImagePath(GetFileNameFromMemory(m_chip32_ctx.registers[R0]));
|
||||
// QString imageFile = m_model.BuildFullImagePath(GetStringFromMemory(m_chip32_ctx.registers[R0]));
|
||||
// m_ostHmiDock->SetImage(imageFile);
|
||||
get_file_from_memory(ImageFile, m_chip32_ctx.registers[R0]);
|
||||
fs_task_image_start(ImageFile);
|
||||
|
|
@ -96,7 +96,7 @@ uint8_t vm_syscall(chip32_ctx_t *ctx, uint8_t code)
|
|||
if (m_chip32_ctx.registers[R1] != 0)
|
||||
{
|
||||
// sound file name address is in R1
|
||||
// QString soundFile = m_model.BuildFullSoundPath(GetFileNameFromMemory(m_chip32_ctx.registers[R1]));
|
||||
// QString soundFile = m_model.BuildFullSoundPath(GetStringFromMemory(m_chip32_ctx.registers[R1]));
|
||||
// qDebug() << ", Sound: " << soundFile;
|
||||
// m_model.PlaySoundFile(soundFile);
|
||||
get_file_from_memory(SoundFile, m_chip32_ctx.registers[R1]);
|
||||
|
|
|
|||
|
|
@ -104,6 +104,21 @@ std::shared_ptr<StoryProject> LibraryManager::GetStory(const std::string &uuid)
|
|||
return current;
|
||||
}
|
||||
|
||||
void LibraryManager::RemoveStory(const std::string &uuid)
|
||||
{
|
||||
for (const auto &s : m_projectsList)
|
||||
{
|
||||
if (s->GetUuid() == uuid)
|
||||
{
|
||||
// Just rename the project file, keep the whole directory
|
||||
auto oldname = s->GetProjectFilePath();
|
||||
std::filesystem::rename(oldname, oldname + "__removed");
|
||||
break;
|
||||
}
|
||||
}
|
||||
Scan();
|
||||
}
|
||||
|
||||
std::string LibraryManager::IndexFileName() const
|
||||
{
|
||||
auto p = std::filesystem::path(m_library_path) / "index.ost";
|
||||
|
|
|
|||
|
|
@ -45,6 +45,7 @@ public:
|
|||
std::string GetStoreUrl() const { return m_storeUrl; }
|
||||
|
||||
void AddStory(IStoryDb::Info &info, int origin);
|
||||
void RemoveStory(const std::string &uuid);
|
||||
|
||||
void ParseCommunityStore(const std::string &jsonFileName);
|
||||
void ParseCommercialStore(const std::string &jsonFileName);
|
||||
|
|
|
|||
|
|
@ -116,6 +116,30 @@ void BaseNodeWidget::FrameStart()
|
|||
}
|
||||
}
|
||||
m_firstFrame = false;
|
||||
|
||||
|
||||
// Title
|
||||
|
||||
const char * text = m_base->GetTypeName().c_str();
|
||||
// Obtenir la position courante du curseur
|
||||
ImVec2 pos = ImGui::GetCursorScreenPos();
|
||||
|
||||
// Définir les dimensions du texte
|
||||
ImVec2 text_size = ImGui::CalcTextSize(text);
|
||||
|
||||
// Ajouter un padding autour du texte
|
||||
float padding = 5.0f;
|
||||
ImVec2 rect_min = ImVec2(pos.x - padding, pos.y - padding);
|
||||
ImVec2 rect_max = ImVec2(pos.x + text_size.x + padding, pos.y + text_size.y + padding);
|
||||
|
||||
// Définir la couleur du rectangle (bleu avec transparence)
|
||||
ImU32 bg_color = ImGui::GetColorU32(ImVec4(0.3f, 0.3f, 0.7f, 1.0f));
|
||||
|
||||
// Dessiner le rectangle de fond
|
||||
ImGui::GetWindowDrawList()->AddRectFilled(rect_min, rect_max, bg_color);
|
||||
|
||||
// Afficher le texte
|
||||
ImGui::TextUnformatted(text);
|
||||
}
|
||||
|
||||
void BaseNodeWidget::FrameEnd()
|
||||
|
|
|
|||
|
|
@ -481,6 +481,8 @@ void LibraryWindow::Draw()
|
|||
);
|
||||
}
|
||||
|
||||
std::string rmUuid;
|
||||
|
||||
if (ImGui::BeginTable("library_table", 3, tableFlags))
|
||||
{
|
||||
ImGui::TableSetupColumn("Name", ImGuiTableColumnFlags_WidthFixed);
|
||||
|
|
@ -539,11 +541,16 @@ void LibraryWindow::Draw()
|
|||
ImGui::SameLine();
|
||||
if (ImGui::SmallButton("Remove"))
|
||||
{
|
||||
|
||||
rmUuid = p->GetUuid();
|
||||
}
|
||||
ImGui::PopID();
|
||||
}
|
||||
ImGui::EndTable();
|
||||
|
||||
if (!rmUuid.empty())
|
||||
{
|
||||
m_libraryManager.RemoveStory(rmUuid);
|
||||
}
|
||||
}
|
||||
ImGui::EndTabItem();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -64,7 +64,7 @@ MainWindow::~MainWindow()
|
|||
}
|
||||
|
||||
|
||||
std::string MainWindow::GetFileNameFromMemory(uint32_t addr)
|
||||
std::string MainWindow::GetStringFromMemory(uint32_t addr)
|
||||
{
|
||||
char strBuf[100];
|
||||
bool isRam = addr & 0x80000000;
|
||||
|
|
@ -77,6 +77,7 @@ std::string MainWindow::GetFileNameFromMemory(uint32_t addr)
|
|||
return strBuf;
|
||||
}
|
||||
|
||||
|
||||
void MainWindow::Play()
|
||||
{
|
||||
|
||||
|
|
@ -268,7 +269,36 @@ void MainWindow::ProcessStory()
|
|||
}
|
||||
else if (m_dbg.run_result > VM_OK)
|
||||
{
|
||||
Log("VM critical error", true);
|
||||
std::string error = "VM Error: ";
|
||||
switch (m_dbg.run_result)
|
||||
{
|
||||
case VM_ERR_STACK_OVERFLOW:
|
||||
error += "Stack overflow";
|
||||
break;
|
||||
case VM_ERR_STACK_UNDERFLOW:
|
||||
error += "Stack underflow";
|
||||
break;
|
||||
case VM_ERR_INVALID_ADDRESS:
|
||||
error += "Invalid address";
|
||||
break;
|
||||
case VM_ERR_UNSUPPORTED_OPCODE:
|
||||
error += "Invalid address";
|
||||
break;
|
||||
case VM_ERR_UNKNOWN_OPCODE:
|
||||
error += "Unknown opcode";
|
||||
break;
|
||||
case VM_ERR_UNHANDLED_INTERRUPT:
|
||||
error += "Unhandled interrupt";
|
||||
break;
|
||||
case VM_ERR_INVALID_REGISTER:
|
||||
error += "Invalid register";
|
||||
break;
|
||||
default:
|
||||
error += "Unknown error";
|
||||
break;
|
||||
}
|
||||
error += " (line: " + std::to_string(m_dbg.line) + ")";
|
||||
Log(error, true);
|
||||
}
|
||||
|
||||
// In this case, we wait for single step debugger
|
||||
|
|
@ -289,7 +319,7 @@ uint8_t MainWindow::Syscall(chip32_ctx_t *ctx, uint8_t code)
|
|||
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]));
|
||||
std::string imageFile = m_story->BuildFullAssetsPath(GetStringFromMemory(m_chip32_ctx.registers[R0]));
|
||||
Log("Image: " + imageFile);
|
||||
m_emulatorWindow.SetImage(imageFile);
|
||||
}
|
||||
|
|
@ -301,7 +331,7 @@ uint8_t MainWindow::Syscall(chip32_ctx_t *ctx, uint8_t code)
|
|||
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]));
|
||||
std::string soundFile = m_story->BuildFullAssetsPath(GetStringFromMemory(m_chip32_ctx.registers[R1]));
|
||||
Log("Sound: " + soundFile);
|
||||
m_player.Play(soundFile);
|
||||
}
|
||||
|
|
@ -325,7 +355,52 @@ uint8_t MainWindow::Syscall(chip32_ctx_t *ctx, uint8_t code)
|
|||
// if timeout is set to zero, wait for infinite and beyond
|
||||
retCode = SYSCALL_RET_WAIT_EV; // set the VM in pause
|
||||
}
|
||||
else if (code == 3)
|
||||
{
|
||||
// FIXME
|
||||
}
|
||||
else // Printf
|
||||
if (code == 4)
|
||||
{
|
||||
// In R0: string with escaped characters
|
||||
// R1: Number of arguments
|
||||
// R2, R3 ... arguments
|
||||
|
||||
// Integers: stored in registers by values
|
||||
// Strings: first character address in register
|
||||
|
||||
std::string text = GetStringFromMemory(ctx->registers[R0]);
|
||||
|
||||
int arg_count = ctx->registers[R1];
|
||||
char working_buf[200] = {0};
|
||||
|
||||
switch(arg_count){
|
||||
case 0:
|
||||
Log(text);
|
||||
break;
|
||||
case 1:
|
||||
snprintf(working_buf, sizeof(working_buf), text.c_str(), ctx->registers[R2]);
|
||||
Log(working_buf);
|
||||
break;
|
||||
case 2:
|
||||
snprintf(working_buf, sizeof(working_buf), text.c_str(), ctx->registers[R2], ctx->registers[R3]);
|
||||
Log(working_buf);
|
||||
break;
|
||||
case 3:
|
||||
snprintf(working_buf, sizeof(working_buf), text.c_str(), ctx->registers[R2], ctx->registers[R3], ctx->registers[R4]);
|
||||
Log(working_buf);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
// WAIT (sleep)
|
||||
else if (code == 5)
|
||||
{
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(ctx->registers[R0]));
|
||||
}
|
||||
|
||||
|
||||
return retCode;
|
||||
}
|
||||
|
|
@ -849,11 +924,11 @@ void MainWindow::RefreshProjectInformation()
|
|||
|
||||
void MainWindow::CloseProject()
|
||||
{
|
||||
// if (m_story)
|
||||
// {
|
||||
// m_story->Clear();
|
||||
// m_story.reset();
|
||||
// }
|
||||
if (m_story)
|
||||
{
|
||||
m_story->Clear();
|
||||
m_story.reset();
|
||||
}
|
||||
|
||||
m_resources.Clear();
|
||||
|
||||
|
|
|
|||
|
|
@ -188,7 +188,7 @@ private:
|
|||
|
||||
void UpdateVmView();
|
||||
uint8_t Syscall(chip32_ctx_t *ctx, uint8_t code);
|
||||
std::string GetFileNameFromMemory(uint32_t addr);
|
||||
std::string GetStringFromMemory(uint32_t addr);
|
||||
void ProcessStory();
|
||||
void StepInstruction();
|
||||
void RefreshProjectInformation();
|
||||
|
|
|
|||
|
|
@ -15,8 +15,6 @@ VariablesWindow::VariablesWindow(IStoryManager &proj)
|
|||
void VariablesWindow::Initialize()
|
||||
{
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue