diff --git a/.gitignore b/.gitignore
index abe5c0a..f05c3c0 100644
--- a/.gitignore
+++ b/.gitignore
@@ -38,3 +38,5 @@ build-story-editor-Desktop_Qt_6_5_1_GCC_64bit-Release/
build-story-player-Desktop_Qt_6_5_1_GCC_64bit-Debug/
build-story-player-Desktop_Qt_GCC_64bit-Debug/
+
+*.user
diff --git a/README.md b/README.md
index 89f143e..39cd0c5 100644
--- a/README.md
+++ b/README.md
@@ -45,7 +45,7 @@ Current status:
We propose a basic editor tool to create your own stories. The generated story script runs on our micro virtual machine and allow generate complex stories.
-
+
Work in progress:
- Project management
@@ -57,6 +57,17 @@ Planned nodes:
- Loop
- Conditional
+# Story Player
+
+The Story plater is a purely software implementation of a simple story player. It is provided as an example and a test device for the micro virtual machine. It is very portable and should run on a large number of platforms.
+
+
+
+Technolologies used:
+- C language
+- Raylib for graphics and sounds
+- CMake build system
+
# License
MIT License
diff --git a/images/ost-1/audio_amplifier.png b/art/ost-1/audio_amplifier.png
similarity index 100%
rename from images/ost-1/audio_amplifier.png
rename to art/ost-1/audio_amplifier.png
diff --git a/images/ost-1/audio_board.webp b/art/ost-1/audio_board.webp
similarity index 100%
rename from images/ost-1/audio_board.webp
rename to art/ost-1/audio_board.webp
diff --git a/images/ost-1/complete.png b/art/ost-1/complete.png
similarity index 100%
rename from images/ost-1/complete.png
rename to art/ost-1/complete.png
diff --git a/images/ost-1/langan-nano.jpg b/art/ost-1/langan-nano.jpg
similarity index 100%
rename from images/ost-1/langan-nano.jpg
rename to art/ost-1/langan-nano.jpg
diff --git a/images/ost-1/speaker_4ohms_3w.png b/art/ost-1/speaker_4ohms_3w.png
similarity index 100%
rename from images/ost-1/speaker_4ohms_3w.png
rename to art/ost-1/speaker_4ohms_3w.png
diff --git a/images/story_editor_preview.png b/art/story_editor_preview.png
similarity index 100%
rename from images/story_editor_preview.png
rename to art/story_editor_preview.png
diff --git a/art/story_player.png b/art/story_player.png
new file mode 100644
index 0000000..3226810
Binary files /dev/null and b/art/story_player.png differ
diff --git a/software/chip32/chip32_vm.c b/software/chip32/chip32_vm.c
index 4d08d68..525bb3f 100644
--- a/software/chip32/chip32_vm.c
+++ b/software/chip32/chip32_vm.c
@@ -146,7 +146,7 @@ chip32_result_t chip32_step(chip32_ctx_t *ctx)
if (ctx->syscall != NULL)
{
- if (ctx->syscall(code) != 0)
+ if (ctx->syscall(ctx, code) != 0)
{
result = VM_WAIT_EVENT;
}
diff --git a/software/chip32/chip32_vm.h b/software/chip32/chip32_vm.h
index 54e6abc..ebd93eb 100644
--- a/software/chip32/chip32_vm.h
+++ b/software/chip32/chip32_vm.h
@@ -185,13 +185,15 @@ typedef struct
} virtual_mem_t;
-typedef uint8_t (*syscall_t)(uint8_t);
+typedef struct chip32_ctx_t chip32_ctx_t;
+
+typedef uint8_t (*syscall_t)(chip32_ctx_t *, uint8_t);
#define SYSCALL_RET_OK 0 ///< Default state, continue execution immediately
#define SYSCALL_RET_WAIT_EV 1 ///< Sets the VM in wait for event state
-typedef struct
+struct chip32_ctx_t
{
virtual_mem_t rom;
virtual_mem_t ram;
@@ -202,7 +204,7 @@ typedef struct
uint32_t registers[REGISTER_COUNT];
syscall_t syscall;
-} chip32_ctx_t;
+};
// =======================================================================================
// VM RUN
diff --git a/story-player/CMakeLists.txt b/story-player/CMakeLists.txt
index 6f6b44c..7e24b86 100644
--- a/story-player/CMakeLists.txt
+++ b/story-player/CMakeLists.txt
@@ -1,5 +1,5 @@
cmake_minimum_required(VERSION 3.11) # FetchContent is available in 3.11+
-project(raylib_template)
+project(story-player)
# Generate compile_commands.json
set(CMAKE_EXPORT_COMPILE_COMMANDS ON)
@@ -25,7 +25,17 @@ endif()
# Our Project
-add_executable(${PROJECT_NAME} main.c raygui.h)
+add_executable(${PROJECT_NAME}
+ main.c
+ raygui.h
+ ../software/chip32/chip32_assembler.cpp
+ ../software/chip32/chip32_vm.c
+ ../software/chip32/chip32_assembler.h
+ ../software/chip32/chip32_vm.h
+)
+include_directories(../software/chip32)
+include_directories(../software/library)
+
#set(raylib_VERBOSE 1)
target_link_libraries(${PROJECT_NAME} raylib)
diff --git a/story-player/CMakeLists.txt.user b/story-player/CMakeLists.txt.user
deleted file mode 100644
index 5ea892c..0000000
--- a/story-player/CMakeLists.txt.user
+++ /dev/null
@@ -1,434 +0,0 @@
-
-
-
-
-
- EnvironmentId
- {75eff57d-71d0-4697-b143-c9d65b3913b6}
-
-
- ProjectExplorer.Project.ActiveTarget
- 0
-
-
- ProjectExplorer.Project.EditorSettings
-
- true
- false
- true
-
- Cpp
-
- CppGlobal
-
-
-
- QmlJS
-
- QmlJSGlobal
-
-
- 2
- UTF-8
- false
- 4
- false
- 80
- true
- true
- 1
- false
- true
- false
- 0
- true
- true
- 0
- 8
- true
- false
- 1
- true
- true
- true
- *.md, *.MD, Makefile
- false
- true
- true
-
-
-
- ProjectExplorer.Project.PluginSettings
-
-
- true
- false
- true
- true
- true
- true
-
-
- 0
- true
-
- true
- true
- Builtin.DefaultTidyAndClazy
- 6
-
-
-
- true
-
-
-
-
- ProjectExplorer.Project.Target.0
-
- Desktop
- Desktop Qt 6.5.1 GCC 64bit
- Desktop Qt 6.5.1 GCC 64bit
- qt.qt6.651.gcc_64_kit
- 0
- 0
- 0
-
- Debug
- 2
- false
-
- -DCMAKE_GENERATOR:STRING=Ninja
--DCMAKE_BUILD_TYPE:STRING=Debug
--DCMAKE_PROJECT_INCLUDE_BEFORE:FILEPATH=%{buildDir}/.qtc/package-manager/auto-setup.cmake
--DQT_QMAKE_EXECUTABLE:FILEPATH=%{Qt:qmakeExecutable}
--DCMAKE_PREFIX_PATH:PATH=%{Qt:QT_INSTALL_PREFIX}
--DCMAKE_C_COMPILER:FILEPATH=%{Compiler:Executable:C}
--DCMAKE_CXX_COMPILER:FILEPATH=%{Compiler:Executable:Cxx}
--DCMAKE_CXX_FLAGS_INIT:STRING=%{Qt:QML_DEBUG_FLAG}
- 0
- /mnt/data/git/open-story-teller/build-story-player-Desktop_Qt_6_5_1_GCC_64bit-Debug
-
-
-
-
- all
-
- false
-
- true
- Compilation
- CMakeProjectManager.MakeStep
-
- 1
- Compiler
- Compiler
- ProjectExplorer.BuildSteps.Build
-
-
-
-
-
- clean
-
- false
-
- true
- Compilation
- CMakeProjectManager.MakeStep
-
- 1
- Nettoyer
- Nettoyer
- ProjectExplorer.BuildSteps.Clean
-
- 2
- false
-
- false
-
- Debug
- CMakeProjectManager.CMakeBuildConfiguration
-
-
- Release
- 2
- false
-
- -DCMAKE_GENERATOR:STRING=Ninja
--DCMAKE_BUILD_TYPE:STRING=Release
--DCMAKE_PROJECT_INCLUDE_BEFORE:FILEPATH=%{buildDir}/.qtc/package-manager/auto-setup.cmake
--DQT_QMAKE_EXECUTABLE:FILEPATH=%{Qt:qmakeExecutable}
--DCMAKE_PREFIX_PATH:PATH=%{Qt:QT_INSTALL_PREFIX}
--DCMAKE_C_COMPILER:FILEPATH=%{Compiler:Executable:C}
--DCMAKE_CXX_COMPILER:FILEPATH=%{Compiler:Executable:Cxx}
--DCMAKE_CXX_FLAGS_INIT:STRING=%{Qt:QML_DEBUG_FLAG}
- /mnt/data/git/open-story-teller/build-story-player-Desktop_Qt_6_5_1_GCC_64bit-Release
-
-
-
-
- all
-
- false
-
- true
- CMakeProjectManager.MakeStep
-
- 1
- Compiler
- Compiler
- ProjectExplorer.BuildSteps.Build
-
-
-
-
-
- clean
-
- false
-
- true
- CMakeProjectManager.MakeStep
-
- 1
- Nettoyer
- Nettoyer
- ProjectExplorer.BuildSteps.Clean
-
- 2
- false
-
- false
-
- Release
- CMakeProjectManager.CMakeBuildConfiguration
-
-
- RelWithDebInfo
- 2
- false
-
- -DCMAKE_GENERATOR:STRING=Ninja
--DCMAKE_BUILD_TYPE:STRING=RelWithDebInfo
--DCMAKE_PROJECT_INCLUDE_BEFORE:FILEPATH=%{buildDir}/.qtc/package-manager/auto-setup.cmake
--DQT_QMAKE_EXECUTABLE:FILEPATH=%{Qt:qmakeExecutable}
--DCMAKE_PREFIX_PATH:PATH=%{Qt:QT_INSTALL_PREFIX}
--DCMAKE_C_COMPILER:FILEPATH=%{Compiler:Executable:C}
--DCMAKE_CXX_COMPILER:FILEPATH=%{Compiler:Executable:Cxx}
--DCMAKE_CXX_FLAGS_INIT:STRING=%{Qt:QML_DEBUG_FLAG}
- /mnt/data/git/open-story-teller/build-story-player-Desktop_Qt_6_5_1_GCC_64bit-RelWithDebInfo
-
-
-
-
- all
-
- false
-
- true
- CMakeProjectManager.MakeStep
-
- 1
- Compiler
- Compiler
- ProjectExplorer.BuildSteps.Build
-
-
-
-
-
- clean
-
- false
-
- true
- CMakeProjectManager.MakeStep
-
- 1
- Nettoyer
- Nettoyer
- ProjectExplorer.BuildSteps.Clean
-
- 2
- false
-
- false
-
- Release with Debug Information
- CMakeProjectManager.CMakeBuildConfiguration
-
-
- RelWithDebInfo
- 2
- false
-
- -DCMAKE_GENERATOR:STRING=Ninja
--DCMAKE_BUILD_TYPE:STRING=RelWithDebInfo
--DCMAKE_PROJECT_INCLUDE_BEFORE:FILEPATH=%{buildDir}/.qtc/package-manager/auto-setup.cmake
--DQT_QMAKE_EXECUTABLE:FILEPATH=%{Qt:qmakeExecutable}
--DCMAKE_PREFIX_PATH:PATH=%{Qt:QT_INSTALL_PREFIX}
--DCMAKE_C_COMPILER:FILEPATH=%{Compiler:Executable:C}
--DCMAKE_CXX_COMPILER:FILEPATH=%{Compiler:Executable:Cxx}
--DCMAKE_CXX_FLAGS_INIT:STRING=%{Qt:QML_DEBUG_FLAG}
- 0
- /mnt/data/git/open-story-teller/build-story-player-Desktop_Qt_6_5_1_GCC_64bit-Profile
-
-
-
-
- all
-
- false
-
- true
- CMakeProjectManager.MakeStep
-
- 1
- Compiler
- Compiler
- ProjectExplorer.BuildSteps.Build
-
-
-
-
-
- clean
-
- false
-
- true
- CMakeProjectManager.MakeStep
-
- 1
- Nettoyer
- Nettoyer
- ProjectExplorer.BuildSteps.Clean
-
- 2
- false
-
- false
-
- Profile
- CMakeProjectManager.CMakeBuildConfiguration
-
-
- MinSizeRel
- 2
- false
-
- -DCMAKE_GENERATOR:STRING=Ninja
--DCMAKE_BUILD_TYPE:STRING=MinSizeRel
--DCMAKE_PROJECT_INCLUDE_BEFORE:FILEPATH=%{buildDir}/.qtc/package-manager/auto-setup.cmake
--DQT_QMAKE_EXECUTABLE:FILEPATH=%{Qt:qmakeExecutable}
--DCMAKE_PREFIX_PATH:PATH=%{Qt:QT_INSTALL_PREFIX}
--DCMAKE_C_COMPILER:FILEPATH=%{Compiler:Executable:C}
--DCMAKE_CXX_COMPILER:FILEPATH=%{Compiler:Executable:Cxx}
--DCMAKE_CXX_FLAGS_INIT:STRING=%{Qt:QML_DEBUG_FLAG}
- /mnt/data/git/open-story-teller/build-story-player-Desktop_Qt_6_5_1_GCC_64bit-MinSizeRel
-
-
-
-
- all
-
- false
-
- true
- CMakeProjectManager.MakeStep
-
- 1
- Compiler
- Compiler
- ProjectExplorer.BuildSteps.Build
-
-
-
-
-
- clean
-
- false
-
- true
- CMakeProjectManager.MakeStep
-
- 1
- Nettoyer
- Nettoyer
- ProjectExplorer.BuildSteps.Clean
-
- 2
- false
-
- false
-
- Minimum Size Release
- CMakeProjectManager.CMakeBuildConfiguration
-
- 5
-
-
- 0
- Déploiement
- Déploiement
- ProjectExplorer.BuildSteps.Deploy
-
- 1
-
- false
- ProjectExplorer.DefaultDeployConfiguration
-
- 1
-
- true
- true
- true
-
- 0
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
-
-
- 2
-
- raylib_template
- CMakeProjectManager.CMakeRunConfiguration.raylib_template
- raylib_template
- false
- true
- true
- false
- true
- /mnt/data/git/open-story-teller/story-player
- /mnt/data/git/open-story-teller/build-story-player-Desktop_Qt_6_5_1_GCC_64bit-Debug
-
- 1
-
-
-
- ProjectExplorer.Project.TargetCount
- 1
-
-
- ProjectExplorer.Project.Updater.FileVersion
- 22
-
-
- Version
- 22
-
-
diff --git a/story-player/gui_file_dialog.h b/story-player/gui_file_dialog.h
index e593d8a..a6043ec 100644
--- a/story-player/gui_file_dialog.h
+++ b/story-player/gui_file_dialog.h
@@ -270,7 +270,7 @@ void GuiFileDialog(GuiFileDialogState *state)
state->windowActive = !GuiWindowBox(state->windowBounds, "#198# Select File Dialog");
// Draw previous directory button + logic
- if (GuiButton((Rectangle){ state->windowBounds.x + state->windowBounds.width - 48, state->windowBounds.y + 24 + 12, 40, 24 }, "< .."))
+ if (GuiButton((Rectangle){ state->windowBounds.x + state->windowBounds.width - 48, state->windowBounds.y + 24 + 12, 40, 24 }, "#117#"))
{
// Move dir path one level up
strcpy(state->dirPathText, GetPrevDirectoryPath(state->dirPathText));
@@ -345,7 +345,7 @@ void GuiFileDialog(GuiFileDialogState *state)
// Draw bottom controls
//--------------------------------------------------------------------------------------
GuiLabel((Rectangle){ state->windowBounds.x + 8, state->windowBounds.y + state->windowBounds.height - 68, 60, 24 }, "File name:");
- if (GuiTextBox((Rectangle){ state->windowBounds.x + 72, state->windowBounds.y + state->windowBounds.height - 68, state->windowBounds.width - 184, 24 }, state->fileNameText, 128, state->fileNameEditMode))
+ if (GuiTextBox((Rectangle){ state->windowBounds.x + 72, state->windowBounds.y + state->windowBounds.height - 68, state->windowBounds.width - 80, 24 }, state->fileNameText, 128, state->fileNameEditMode))
{
if (*state->fileNameText)
{
@@ -372,10 +372,7 @@ void GuiFileDialog(GuiFileDialogState *state)
state->fileNameEditMode = !state->fileNameEditMode;
}
- GuiLabel((Rectangle){ state->windowBounds.x + 8, state->windowBounds.y + state->windowBounds.height - 24 - 12, 68, 24 }, "File filter:");
- GuiComboBox((Rectangle){ state->windowBounds.x + 72, state->windowBounds.y + state->windowBounds.height - 24 - 12, state->windowBounds.width - 184, 24 }, "All files", &state->fileTypeActive);
-
- state->SelectFilePressed = GuiButton((Rectangle){ state->windowBounds.x + state->windowBounds.width - 96 - 8, state->windowBounds.y + state->windowBounds.height - 68, 96, 24 }, "Select");
+ state->SelectFilePressed = GuiButton((Rectangle){ state->windowBounds.x + state->windowBounds.width - 96 *2 - 8*2, state->windowBounds.y + state->windowBounds.height - 24 - 12, 96, 24 }, "Select");
if (GuiButton((Rectangle){ state->windowBounds.x + state->windowBounds.width - 96 - 8, state->windowBounds.y + state->windowBounds.height - 24 - 12, 96, 24 }, "Cancel")) state->windowActive = false;
//--------------------------------------------------------------------------------------
@@ -418,12 +415,84 @@ static inline int FileCompare(const char *d1, const char *d2, const char *dir)
return strcmp(d1, d2);
}
+
+#include
+#include
+#include
+#include
+
+int is_regular_file(const char *path)
+{
+ struct stat path_stat;
+ stat(path, &path_stat);
+ return S_ISREG(path_stat.st_mode);
+}
+
+#define MAX_FILEPATH_CAPACITY 8192 // Maximum capacity for filepath
+#define MAX_FILEPATH_LENGTH 4096 // Maximum length for filepaths (Linux PATH_MAX default value)
+
+
+// Scan all files and directories in a base path
+// WARNING: files.paths[] must be previously allocated and
+// contain enough space to store all required paths
+static void MyScanDirectoryFiles(const char *basePath, FilePathList *files, const char *filter)
+{
+ static char path[MAX_FILEPATH_LENGTH] = { 0 };
+ memset(path, 0, MAX_FILEPATH_LENGTH);
+
+ struct dirent *dp = NULL;
+ DIR *dir = opendir(basePath);
+
+ if (dir != NULL)
+ {
+ while ((dp = readdir(dir)) != NULL)
+ {
+ if ((strcmp(dp->d_name, ".") != 0) &&
+ (strcmp(dp->d_name, "..") != 0) && (dp->d_name[0] != '.'))
+ {
+ sprintf(path, "%s/%s", basePath, dp->d_name);
+
+ if ((filter != NULL) && (is_regular_file(path)))
+ {
+ if (IsFileExtension(path, filter))
+ {
+ strcpy(files->paths[files->count], path);
+ files->count++;
+ }
+ }
+ else
+ {
+ strcpy(files->paths[files->count], path);
+ files->count++;
+ }
+ }
+ }
+
+ closedir(dir);
+ }
+}
+
+
+FilePathList MyLoadDirectoryFilesEx(const char *basePath, const char *filter)
+{
+ FilePathList files = { 0 };
+
+ files.capacity = MAX_FILEPATH_CAPACITY;
+ files.paths = (char **)RL_CALLOC(files.capacity, sizeof(char *));
+ for (unsigned int i = 0; i < files.capacity; i++) files.paths[i] = (char *)RL_CALLOC(MAX_FILEPATH_LENGTH, sizeof(char));
+
+ // WARNING: basePath is always prepended to scanned paths
+ MyScanDirectoryFiles(basePath, &files, filter);
+
+ return files;
+}
+
// Read files in new path
static void ReloadDirectoryFiles(GuiFileDialogState *state)
{
UnloadDirectoryFiles(state->dirFiles);
- state->dirFiles = LoadDirectoryFilesEx(state->dirPathText, (state->filterExt[0] == '\0')? NULL : state->filterExt, false);
+ state->dirFiles = MyLoadDirectoryFilesEx(state->dirPathText, (state->filterExt[0] == '\0')? NULL : state->filterExt);
state->itemFocused = 0;
// Reset dirFilesIcon memory
diff --git a/story-player/main.c b/story-player/main.c
index 920b876..6da16d3 100644
--- a/story-player/main.c
+++ b/story-player/main.c
@@ -24,11 +24,177 @@
#define GUI_FILE_DIALOG_IMPLEMENTATION
#include "gui_file_dialog.h"
+#include "chip32_vm.h"
+#include
+
+int set_filename_from_memory(chip32_ctx_t *ctx, uint32_t addr, char *filename_mem)
+{
+ int valid = 0;
+
+ // Test if address is valid
+
+ bool isRam = addr & 0x80000000;
+ addr &= 0xFFFF; // mask the RAM/ROM bit, ensure 16-bit addressing
+ if (isRam) {
+ strcpy(&filename_mem[0], (const char *)&ctx->ram.mem[addr]);
+ } else {
+ strcpy(&filename_mem[0], (const char *)&ctx->rom.mem[addr]);
+ }
+
+ return valid;
+}
+
+
+chip32_result_t vm_load_script(chip32_ctx_t *ctx, const char *filename)
+{
+ chip32_result_t run_result = VM_FINISHED;
+ FILE *fp = fopen(filename, "rb");
+ if (fp != NULL)
+ {
+ fseek(fp, 0L, SEEK_END);
+ long int sz = ftell(fp);
+ fseek(fp, 0L, SEEK_SET);
+
+ if (sz <= ctx->rom.size)
+ {
+ fread(ctx->rom.mem, sz, 1, fp);
+ run_result = VM_OK;
+ chip32_initialize(ctx);
+ }
+ fclose(fp);
+ }
+ return run_result;
+}
+
+#define MAX_PATH 260
+
+void get_home_path(char *homedir)
+{
+#ifdef _WIN32
+ snprintf(homedir, MAX_PATH, "%s%s", getenv("HOMEDRIVE"), getenv("HOMEPATH"));
+#else
+ snprintf(homedir, MAX_PATH, "%s", getenv("HOME"));
+#endif
+}
+
+
+void get_parent_dir(const char *path, char *parent)
+{
+ int parentLen;
+ char* last = strrchr(path, '/');
+
+ if (last != NULL) {
+
+ parentLen = strlen(path) - strlen(last + 1);
+ strncpy(parent, path, parentLen);
+ }
+}
+
+
+static Music gMusic;
+static char root_dir[260];
+static bool gMusicLoaded = false;
+
+static Texture texture = { 0 };
+
+#define EV_BUTTON_OK 0x01
+#define EV_BUTTON_LEFT 0x02
+#define EV_BUTTON_RIGHT 0x04
+
+uint8_t story_player_syscall(chip32_ctx_t *ctx, uint8_t code)
+{
+ uint8_t retCode = SYSCALL_RET_OK;
+
+ static char image_path[260];
+ static char sound_path[260];
+
+ if (code == 1) // // Execute media
+ {
+ printf("SYSCALL 1\n");
+ fflush(stdout);
+// UnloadTexture(*tex);
+// *tex =
+
+ if (ctx->registers[R0] != 0)
+ {
+ // sound file name address is in R1
+ char image[100];
+ set_filename_from_memory(ctx, ctx->registers[R0], image);
+
+ strcpy(image_path, root_dir);
+ strcat(image_path, "images/");
+ strcat(image_path, image);
+
+ texture = LoadTexture(image_path);
+ }
+ else
+ {
+ UnloadTexture(texture);
+ }
+
+
+ if (ctx->registers[R1] != 0)
+ {
+ // sound file name address is in R1
+ char sound[100];
+ set_filename_from_memory(ctx, ctx->registers[R1], sound);
+
+ strcpy(sound_path, root_dir);
+ strcat(sound_path, "sounds/");
+ strcat(sound_path, sound);
+
+ gMusic = LoadMusicStream(sound_path);
+ gMusic.looping = false;
+ gMusicLoaded = true;
+
+ if (IsMusicReady(gMusic))
+ {
+ PlayMusicStream(gMusic);
+ }
+ }
+ retCode = SYSCALL_RET_WAIT_EV; // set the VM in pause
+ }
+ else if (code == 2) // Wait Event
+ {
+ printf("SYSCALL 2\n");
+ fflush(stdout);
+ retCode = SYSCALL_RET_WAIT_EV; // set the VM in pause
+ }
+ return retCode;
+}
+
+
//------------------------------------------------------------------------------------
// Program main entry point
//------------------------------------------------------------------------------------
int main()
{
+ // VM Stuff
+ //---------------------------------------------------------------------------------------
+ uint8_t rom_data[16*1024];
+ uint8_t ram_data[16*1024];
+ chip32_ctx_t chip32_ctx;
+
+ chip32_ctx.stack_size = 512;
+
+ chip32_ctx.rom.mem = rom_data;
+ chip32_ctx.rom.addr = 0;
+ chip32_ctx.rom.size = sizeof(rom_data);
+
+ chip32_ctx.ram.mem = ram_data;
+ chip32_ctx.ram.addr = sizeof(rom_data);
+ chip32_ctx.ram.size = sizeof(ram_data);
+
+ chip32_ctx.syscall = story_player_syscall;
+
+ chip32_result_t run_result = VM_FINISHED;
+
+ // Directories
+ //---------------------------------------------------------------------------------------
+ char homedir[MAX_PATH];
+
+ get_home_path(homedir);
+
// Initialization
//---------------------------------------------------------------------------------------
int screenWidth = 800;
@@ -41,7 +207,6 @@ int main()
GuiSetStyle(DEFAULT, BACKGROUND_COLOR, 0x133D42ff);
GuiSetStyle(DEFAULT, TEXT_SIZE, 14);
- GuiSetIconScale(3);
GuiSetStyle(DEFAULT, BORDER_COLOR_NORMAL, 0x6DBFB2ff);
GuiSetStyle(DEFAULT, TEXT_COLOR_NORMAL, 0xffffffff);
@@ -53,16 +218,18 @@ int main()
GuiSetFont(fontTtf);
-
// Custom file dialog
GuiFileDialogState fileDialogState = InitGuiFileDialog(GetWorkingDirectory());
- Texture2D logoTexture = LoadTexture("logo-color2.png"); // Texture loading
+ strcpy(fileDialogState.filterExt, ".c32");
+ strcpy(fileDialogState.dirPathText, homedir);
+ Texture2D logoTexture = LoadTexture("logo-color2.png");
bool exitWindow = false;
char fileNameToLoad[512] = { 0 };
- Texture texture = { 0 };
+ InitAudioDevice();
+ UnloadMusicStream(gMusic);
SetTargetFPS(60);
//--------------------------------------------------------------------------------------
@@ -76,16 +243,35 @@ int main()
if (fileDialogState.SelectFilePressed)
{
- // Load image file (if supported extension)
if (IsFileExtension(fileDialogState.fileNameText, ".c32"))
{
strcpy(fileNameToLoad, TextFormat("%s/%s", fileDialogState.dirPathText, fileDialogState.fileNameText));
- UnloadTexture(texture);
- texture = LoadTexture(fileNameToLoad);
+ run_result = vm_load_script(&chip32_ctx, fileNameToLoad);
+ get_parent_dir(fileNameToLoad, root_dir);
+ printf("Root directory: %s\n", root_dir);
}
fileDialogState.SelectFilePressed = false;
}
+
+ // VM next instruction
+ if (run_result == VM_OK)
+ {
+ run_result = chip32_step(&chip32_ctx);
+ }
+
+ if (gMusicLoaded)
+ {
+ UpdateMusicStream(gMusic);
+ if (!IsMusicStreamPlaying(gMusic))
+ {
+ StopMusicStream(gMusic);
+ UnloadMusicStream(gMusic);
+ gMusicLoaded = false;
+ run_result = VM_OK; // continue VM execution
+ }
+ }
+
//----------------------------------------------------------------------------------
// Draw
@@ -94,39 +280,76 @@ int main()
ClearBackground(GetColor(GuiGetStyle(DEFAULT, BACKGROUND_COLOR)));
+
DrawTextureEx(logoTexture, (Vector2){ (float)10, (float)10 }, 0, 0.15, WHITE);
- DrawTexture(texture, GetScreenWidth()/2 - texture.width/2, GetScreenHeight()/2 - texture.height/2 - 5, WHITE);
-// DrawRectangleLines(GetScreenWidth()/2 - texture.width/2, GetScreenHeight()/2 - texture.height/2 - 5, texture.width, texture.height, BLACK);
+ // Image de l'histoire
+ DrawRectangle(220, 25, 320, 240, WHITE);
+ DrawTexture(texture, 220, 25, WHITE);
-// DrawText(fileNameToLoad, 208, GetScreenHeight() - 20, 10, GRAY);
+ GuiSetIconScale(3);
- // raygui: controls drawing
- //----------------------------------------------------------------------------------
- if (fileDialogState.windowActive) GuiLock();
+ if (GuiButton((Rectangle){ 20, 140, 60, 60 }, "#05#"))
+ {
+ fileDialogState.windowActive = true;
+ }
- if (GuiButton((Rectangle){ 20, 140, 60, 60 }, "#05#")) fileDialogState.windowActive = true;
-
- // Pause ICON_PLAYER_PAUSE
+ // ICON_PLAYER_PAUSE
if (GuiButton((Rectangle){ 20 + 65, 140, 60, 60 }, "#132#"))
{
}
- // House ICON_HOUSE
+ // ICON_HOUSE
if (GuiButton((Rectangle){ 20 + 2*65, 140, 60, 60 }, "#185#"))
{
}
+ // ICON_ARROW_LEFT
+ if (GuiButton((Rectangle){ 20, 205, 60, 60 }, "#114#"))
+ {
+ if (run_result == VM_WAIT_EVENT)
+ {
+ chip32_ctx.registers[R0] = EV_BUTTON_LEFT;
+ run_result = VM_OK;
+ }
+ }
+
+ // ICON_OK_TICK
+ if (GuiButton((Rectangle){ 20 + 65, 205, 60, 60 }, "#112#"))
+ {
+ if (run_result == VM_WAIT_EVENT)
+ {
+ chip32_ctx.registers[R0] = EV_BUTTON_OK;
+ run_result = VM_OK;
+ }
+ }
+
+ // ICON_ARROW_RIGHT
+ if (GuiButton((Rectangle){ 20 + 2*65, 205, 60, 60 }, "#115#"))
+ {
+ if (run_result == VM_WAIT_EVENT)
+ {
+ chip32_ctx.registers[R0] = EV_BUTTON_RIGHT;
+ run_result = VM_OK;
+ }
+ }
+
+ // raygui: controls drawing
+ //----------------------------------------------------------------------------------
+
+ if (fileDialogState.windowActive) GuiLock();
GuiUnlock();
// GUI: Dialog Window
//--------------------------------------------------------------------------------
+ GuiSetIconScale(1);
GuiFileDialog(&fileDialogState);
//--------------------------------------------------------------------------------
+
//----------------------------------------------------------------------------------
EndDrawing();
@@ -135,8 +358,10 @@ int main()
// De-Initialization
//--------------------------------------------------------------------------------------
+ UnloadTexture(logoTexture); // Unload texture
UnloadTexture(texture); // Unload texture
+ CloseAudioDevice();
CloseWindow(); // Close window and OpenGL context
//--------------------------------------------------------------------------------------