many many fixes for commercial story import, wip on transitions
Some checks failed
build-story-editor / build_linux (push) Has been cancelled
build-story-editor / build_win32 (push) Has been cancelled
Deploy / deploy (push) Has been cancelled

This commit is contained in:
anthony@rabine.fr 2025-01-17 14:44:13 +01:00
parent 879f5fbdbc
commit 6c76307f1b
20 changed files with 13528 additions and 3769 deletions

View file

@ -104,7 +104,9 @@
"cfenv": "cpp",
"source_location": "cpp",
"stdfloat": "cpp",
"text_encoding": "cpp"
"text_encoding": "cpp",
"serializers.h": "c",
"ni_parser.h": "c"
}
}

View file

@ -2,6 +2,8 @@
#include "sys_lib.h"
#include <algorithm>
#include <regex>
#include <filesystem>
#include <fstream>
void SysLib::EraseString(std::string &theString, const std::string &toErase)
{
@ -20,6 +22,29 @@ std::string SysLib::ToUpper(const std::string &input)
return str;
}
std::string SysLib::ToLower(const std::string &input)
{
std::string str = input;
std::transform(str.begin(), str.end(), str.begin(), ::tolower);
return str;
}
std::string SysLib::ReadFile(const std::string &filename)
{
// Open the stream to 'lock' the file.
std::ifstream f(filename, std::ios::in | std::ios::binary);
// Obtain the size of the file.
const auto sz = std::filesystem::file_size(filename);
// Create a buffer.
std::string result(sz, '\0');
// Read the whole file into the buffer.
f.read(result.data(), sz);
return result;
}
std::string SysLib::GetFileExtension(const std::string &fileName)
{
@ -52,6 +77,18 @@ std::string SysLib::GetFileName(const std::string &path)
}
}
std::string SysLib::GetDirectory(const std::string &filePath)
{
try {
std::filesystem::path absPath = std::filesystem::absolute(filePath);
std::filesystem::path dirPath = absPath.parent_path(); // Récupère le chemin sans le nom du fichier
return dirPath.string(); // Convertit le chemin en chaîne de caractères
} catch (const std::filesystem::filesystem_error& e) {
// std::cerr << "Erreur: " << e.what() << std::endl;
return "";
}
}
void SysLib::ReplaceCharacter(std::string &theString, const std::string &toFind, const std::string &toReplace)
{

View file

@ -8,9 +8,12 @@ public:
static std::string GetFileExtension(const std::string &FileName);
static std::string GetFileName(const std::string &path);
static std::string GetDirectory(const std::string &filePath);
static std::string RemoveFileExtension(const std::string &FileName);
static void ReplaceCharacter(std::string &theString, const std::string &toFind, const std::string &toReplace);
static std::string Normalize(const std::string &input);
static void EraseString(std::string &theString, const std::string &toErase);
static std::string ToUpper(const std::string &input);
static std::string ToLower(const std::string &input);
static std::string ReadFile(const std::string &filename);
};

View file

@ -11,5 +11,5 @@ add_library(ImGuiFileDialog STATIC
target_include_directories(ImGuiFileDialog PUBLIC ${CMAKE_CURRENT_SOURCE_DIR})
if(UNIX)
target_compile_options(ImGuiFileDialog PUBLIC "-Wno-unknown-pragmas")
target_compile_options(ImGuiFileDialog PUBLIC -Wno-unknown-pragmas)
endif()

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -2,24 +2,39 @@
// uncomment and modify defines under for customize ImGuiFileDialog
/////////////////////////////////
//// STL FILE SYSTEM ////////////
/////////////////////////////////
// uncomment if you need to use your FileSystem Interface
// if commented, you have two defualt interface, std::filesystem or dirent
// #define USE_CUSTOM_FILESYSTEM
// this options need c++17
// #define USE_STD_FILESYSTEM
// #define MAX_FILE_DIALOG_NAME_BUFFER 1024
// #define MAX_PATH_BUFFER_SIZE 1024
// the slash's buttons in path cna be used for quick select parallles directories
// #define USE_QUICK_PATH_SELECT
/////////////////////////////////
//// MISC ///////////////////////
/////////////////////////////////
// the spacing between button path's can be customized.
// if disabled the spacing is defined by the imgui theme
// define the space between path buttons
// #define CUSTOM_PATH_SPACING 2
// #define MAX_FILE_DIALOG_NAME_BUFFER 1024
// #define MAX_PATH_BUFFER_SIZE 1024
/////////////////////////////////
//// QUICK PATH /////////////////
/////////////////////////////////
// the slash's buttons in path cna be used for quick select parallles directories
// #define USE_QUICK_PATH_SELECT
/////////////////////////////////
//// THUMBNAILS /////////////////
/////////////////////////////////
// #define USE_THUMBNAILS
// the thumbnail generation use the stb_image and stb_resize lib who need to define the implementation
// btw if you already use them in your app, you can have compiler error due to "implemntation found in double"
@ -37,6 +52,10 @@
// #define DisplayMode_ThumbailsGrid_ButtonString "TG"
// #define DisplayMode_ThumbailsGrid_ButtonHelp "Thumbnails Grid"
/////////////////////////////////
//// EXPLORATION BY KEYS ////////
/////////////////////////////////
// #define USE_EXPLORATION_BY_KEYS
// this mapping by default is for GLFW but you can use another
// #include <GLFW/glfw3.h>
@ -49,10 +68,24 @@
// BackSpace for comming back to the last directory
// #define IGFD_KEY_BACKSPACE ImGuiKey_Backspace
/////////////////////////////////
//// SHORTCUTS => ctrl + KEY ////
/////////////////////////////////
// #define SelectAllFilesKey ImGuiKey_A
/////////////////////////////////
//// DIALOG EXIT ////////////////
/////////////////////////////////
// by ex you can quit the dialog by pressing the key excape
// #define USE_DIALOG_EXIT_WITH_KEY
// #define IGFD_EXIT_KEY ImGuiKey_Escape
/////////////////////////////////
//// WIDGETS ////////////////////
/////////////////////////////////
// widget
// begin combo widget
// #define IMGUI_BEGIN_COMBO ImGui::BeginCombo
@ -67,10 +100,14 @@
// standard button
// #define IMGUI_BUTTON ImGui::Button
/////////////////////////////////
//// STRING'S ///////////////////
/////////////////////////////////
// locales string
// #define createDirButtonString "+"
// #define resetButtonString "R"
// #define drivesButtonString "Drives"
// #define devicesButtonString "Devices"
// #define editPathButtonString "E"
// #define searchString "Search"
// #define dirEntryString "[DIR] "
@ -79,7 +116,7 @@
// #define fileNameString "File Name : "
// #define dirNameString "Directory Path :"
// #define buttonResetSearchString "Reset search"
// #define buttonDriveString "Drives"
// #define buttonDriveString "Devices"
// #define buttonEditPathString "Edit path\nYou can also right click on path buttons"
// #define buttonResetPathString "Reset to current directory"
// #define buttonCreateDirString "Create Directory"
@ -103,6 +140,10 @@
// "%Y/%m/%d %i:%M%p" give 2021:01:22 11:45PM
// #define DateTimeFormat "%Y/%m/%d %i:%M%p"
/////////////////////////////////
//// SORTING ICONS //////////////
/////////////////////////////////
// theses icons will appear in table headers
// #define USE_CUSTOM_SORTING_ICON
// #define tableHeaderAscendingIcon "A|"
@ -126,6 +167,10 @@
// #define defaultSortOrderDate true
// #define defaultSortOrderThumbnails true
/////////////////////////////////
//// PLACES FEATURES ////////////
/////////////////////////////////
// #define USE_PLACES_FEATURE
// #define PLACES_PANE_DEFAULT_SHOWN false
// #define placesPaneWith 150.0f
@ -137,12 +182,20 @@
// #define validatePlaceButtonString "ok"
// #define editPlaceButtonString "E"
//////////////////////////////////////
//// PLACES FEATURES : BOOKMARKS /////
//////////////////////////////////////
// a group for bookmarks will be added by default, but you can also create it yourself and many more
// #define USE_PLACES_BOOKMARKS
// #define PLACES_BOOKMARK_DEFAULT_OPEPEND true
// #define placesBookmarksGroupName "Bookmarks"
// #define placesBookmarksDisplayOrder 0 // to the first
//////////////////////////////////////
//// PLACES FEATURES : DEVICES ///////
//////////////////////////////////////
// a group for system devices (returned by IFileSystem), but you can also add yours
// by ex if you would like to display a specific icon for some devices
// #define USE_PLACES_DEVICES

File diff suppressed because it is too large Load diff

View file

@ -5,46 +5,47 @@ stb
single-file public domain (or MIT licensed) libraries for C/C++
# This project discusses security-relevant bugs in public in Github Issues and Pull Requests, and it may take significant time for security fixes to be implemented or merged. If this poses an unreasonable risk to your project, do not use stb libraries.
Noteworthy:
* image loader: [stb_image.h](stb_image.h)
* image writer: [stb_image_write.h](stb_image_write.h)
* image resizer: [stb_image_resize.h](stb_image_resize.h)
* image resizer: [stb_image_resize2.h](stb_image_resize2.h)
* font text rasterizer: [stb_truetype.h](stb_truetype.h)
* typesafe containers: [stb_ds.h](stb_ds.h)
Most libraries by stb, except: stb_dxt by Fabian "ryg" Giesen, stb_image_resize
by Jorge L. "VinoBS" Rodriguez, and stb_sprintf by Jeff Roberts.
Most libraries by stb, except: stb_dxt by Fabian "ryg" Giesen, original stb_image_resize
by Jorge L. "VinoBS" Rodriguez, and stb_image_resize2 and stb_sprintf by Jeff Roberts.
<a name="stb_libs"></a>
library | lastest version | category | LoC | description
--------------------- | ---- | -------- | --- | --------------------------------
**[stb_vorbis.c](stb_vorbis.c)** | 1.20 | audio | 5563 | decode ogg vorbis files from file/memory to float/16-bit signed output
**[stb_image.h](stb_image.h)** | 2.26 | graphics | 7762 | image loading/decoding from file/memory: JPG, PNG, TGA, BMP, PSD, GIF, HDR, PIC
**[stb_truetype.h](stb_truetype.h)** | 1.24 | graphics | 5011 | parse, decode, and rasterize characters from truetype fonts
**[stb_image_write.h](stb_image_write.h)** | 1.15 | graphics | 1690 | image writing to disk: PNG, TGA, BMP
**[stb_image_resize.h](stb_image_resize.h)** | 0.96 | graphics | 2631 | resize images larger/smaller with good quality
**[stb_rect_pack.h](stb_rect_pack.h)** | 1.00 | graphics | 628 | simple 2D rectangle packer with decent quality
**[stb_ds.h](stb_ds.h)** | 0.65 | utility | 1880 | typesafe dynamic array and hash tables for C, will compile in C++
**[stb_sprintf.h](stb_sprintf.h)** | 1.09 | utility | 1879 | fast sprintf, snprintf for C/C++
**[stretchy_buffer.h](stretchy_buffer.h)** | 1.04 | utility | 263 | typesafe dynamic array for C (i.e. approximation to vector<>), doesn't compile as C++
**[stb_textedit.h](stb_textedit.h)** | 1.13 | user&nbsp;interface | 1404 | guts of a text editor for games etc implementing them from scratch
**[stb_vorbis.c](stb_vorbis.c)** | 1.22 | audio | 5584 | decode ogg vorbis files from file/memory to float/16-bit signed output
**[stb_hexwave.h](stb_hexwave.h)** | 0.5 | audio | 680 | audio waveform synthesizer
**[stb_image.h](stb_image.h)** | 2.29 | graphics | 7985 | image loading/decoding from file/memory: JPG, PNG, TGA, BMP, PSD, GIF, HDR, PIC
**[stb_truetype.h](stb_truetype.h)** | 1.26 | graphics | 5077 | parse, decode, and rasterize characters from truetype fonts
**[stb_image_write.h](stb_image_write.h)** | 1.16 | graphics | 1724 | image writing to disk: PNG, TGA, BMP
**[stb_image_resize2.h](stb_image_resize2.h)** | 2.04 | graphics | 10325 | resize images larger/smaller with good quality
**[stb_rect_pack.h](stb_rect_pack.h)** | 1.01 | graphics | 623 | simple 2D rectangle packer with decent quality
**[stb_perlin.h](stb_perlin.h)** | 0.5 | graphics | 428 | perlin's revised simplex noise w/ different seeds
**[stb_ds.h](stb_ds.h)** | 0.67 | utility | 1895 | typesafe dynamic array and hash tables for C, will compile in C++
**[stb_sprintf.h](stb_sprintf.h)** | 1.10 | utility | 1906 | fast sprintf, snprintf for C/C++
**[stb_textedit.h](stb_textedit.h)** | 1.14 | user&nbsp;interface | 1429 | guts of a text editor for games etc implementing them from scratch
**[stb_voxel_render.h](stb_voxel_render.h)** | 0.89 | 3D&nbsp;graphics | 3807 | Minecraft-esque voxel rendering "engine" with many more features
**[stb_dxt.h](stb_dxt.h)** | 1.10 | 3D&nbsp;graphics | 753 | Fabian "ryg" Giesen's real-time DXT compressor
**[stb_perlin.h](stb_perlin.h)** | 0.5 | 3D&nbsp;graphics | 428 | revised Perlin noise (3D input, 1D output)
**[stb_dxt.h](stb_dxt.h)** | 1.12 | 3D&nbsp;graphics | 719 | Fabian "ryg" Giesen's real-time DXT compressor
**[stb_easy_font.h](stb_easy_font.h)** | 1.1 | 3D&nbsp;graphics | 305 | quick-and-dirty easy-to-deploy bitmap font for printing frame rate, etc
**[stb_tilemap_editor.h](stb_tilemap_editor.h)** | 0.41 | game&nbsp;dev | 4161 | embeddable tilemap editor
**[stb_tilemap_editor.h](stb_tilemap_editor.h)** | 0.42 | game&nbsp;dev | 4187 | embeddable tilemap editor
**[stb_herringbone_wa...](stb_herringbone_wang_tile.h)** | 0.7 | game&nbsp;dev | 1221 | herringbone Wang tile map generator
**[stb_c_lexer.h](stb_c_lexer.h)** | 0.11 | parsing | 966 | simplify writing parsers for C-like languages
**[stb_divide.h](stb_divide.h)** | 0.93 | math | 430 | more useful 32-bit modulus e.g. "euclidean divide"
**[stb_c_lexer.h](stb_c_lexer.h)** | 0.12 | parsing | 940 | simplify writing parsers for C-like languages
**[stb_divide.h](stb_divide.h)** | 0.94 | math | 433 | more useful 32-bit modulus e.g. "euclidean divide"
**[stb_connected_comp...](stb_connected_components.h)** | 0.96 | misc | 1049 | incrementally compute reachability on grids
**[stb.h](stb.h)** | 2.37 | misc | 14454 | helper functions for C, mostly redundant in C++; basically author's personal stuff
**[stb_leakcheck.h](stb_leakcheck.h)** | 0.6 | misc | 194 | quick-and-dirty malloc/free leak-checking
**[stb_include.h](stb_include.h)** | 0.02 | misc | 295 | implement recursive #include support, particularly for GLSL
Total libraries: 22
Total lines of C code: 56774
Total libraries: 21
Total lines of C code: 50806
FAQ
@ -60,6 +61,24 @@ They are also licensed under the MIT open source license, if you have lawyers
who are unhappy with public domain. Every source file includes an explicit
dual-license for you to choose from.
#### How do I use these libraries?
The idea behind single-header file libraries is that they're easy to distribute and deploy
because all the code is contained in a single file. By default, the .h files in here act as
their own header files, i.e. they declare the functions contained in the file but don't
actually result in any code getting compiled.
So in addition, you should select _exactly one_ C/C++ source file that actually instantiates
the code, preferably a file you're not editing frequently. This file should define a
specific macro (this is documented per-library) to actually enable the function definitions.
For example, to use stb_image, you should have exactly one C/C++ file that doesn't
include stb_image.h regularly, but instead does
#define STB_IMAGE_IMPLEMENTATION
#include "stb_image.h"
The right macro to define is pointed out right at the top of each of these libraries.
#### <a name="other_libs"></a> Are there other single-file public-domain/open source libraries with minimal dependencies out there?
[Yes.](https://github.com/nothings/single_file_libs)

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -37,6 +37,7 @@ your use of the corresponding standard functions.
#include "IconsMaterialDesignIcons.h"
#include "IconsFontAwesome5_c.h"
#include "serializers.h"
static void glfw_error_callback(int error, const char* description)
{
@ -48,42 +49,313 @@ static SDL_Renderer* renderer{nullptr};
#include "stb_image.h"
#include "sys_lib.h"
typedef struct {
uint16_t type; /* Magic identifier */
uint32_t size; /* File size in bytes */
uint16_t reserved1;
uint16_t reserved2;
uint32_t offset; /* Offset to image data, bytes */
} bmp_header_t;
typedef struct {
uint32_t size; /* Header size in bytes */
uint32_t width;
uint32_t height; /* Width and height of image */
uint16_t planes; /* Number of colour planes */
uint16_t bits; /* Bits per pixel */
uint32_t compression; /* Compression type */
uint32_t imagesize; /* Image size in bytes */
uint32_t xresolution;
uint32_t yresolution; /* Pixels per meter */
uint32_t ncolours; /* Number of colours */
uint32_t importantcolours; /* Important colours */
uint32_t rgb;
uint32_t rgb2;
} bmp_infoheader_t;
static const uint32_t HEADER_SIZE = 14;
static const uint32_t INFO_HEADER_SIZE = 40;
uint8_t parse_bmp(const uint8_t *data, bmp_header_t *header, bmp_infoheader_t *info_header)
{
uint8_t isBmp = 0;
// Header is 14 bytes length
isBmp = (data[0] == 'B') && (data[1] == 'M') ? 1 : 0;
header->size = leu32_get(data + 2);
header->offset = leu32_get(data + 10);
isBmp = isBmp & 1;
info_header->size = leu32_get(data + HEADER_SIZE);
info_header->width = leu32_get(data + HEADER_SIZE + 4);
info_header->height = leu32_get(data + HEADER_SIZE + 8);
info_header->planes = leu16_get(data + HEADER_SIZE + 12);
info_header->bits = leu16_get(data + HEADER_SIZE + 14);
info_header->compression = leu32_get(data + HEADER_SIZE + 16);
info_header->imagesize = leu32_get(data + HEADER_SIZE + 20);
info_header->xresolution = leu32_get(data + HEADER_SIZE + 24);
info_header->yresolution = leu32_get(data + HEADER_SIZE + 28);
info_header->ncolours = leu32_get(data + HEADER_SIZE + 32);
info_header->importantcolours = leu32_get(data + HEADER_SIZE + 36);
info_header->rgb = leu32_get(data + HEADER_SIZE + 40);
info_header->rgb2 = leu32_get(data + HEADER_SIZE + 44);
return isBmp;
}
// Code de décompression
void Decompress(uint8_t *bmpImage, uint32_t fileSize, SDL_Texture *texture)
{
uint32_t width = 320;
uint32_t height = 240;
bmp_header_t header;
bmp_infoheader_t info_header;
parse_bmp(bmpImage, &header, &info_header);
uint8_t *compressed = &bmpImage[header.offset];
uint32_t compressedSize = fileSize - header.offset;
uint32_t paletteSize = header.offset - (HEADER_SIZE + INFO_HEADER_SIZE);
printf("File size (from header):%d\r\n", (uint32_t)header.size);
printf("File size (from data):%d\r\n", (uint32_t)fileSize);
printf("Data offset:%d\r\n", (uint32_t)header.offset);
printf("Image size:%d\r\n", (uint32_t)info_header.size);
printf("width:%d\r\n", (uint32_t)info_header.width);
printf("height:%d\r\n", (uint32_t)info_header.height);
printf("Planes:%d\r\n", (uint32_t)info_header.planes);
printf("Bits:%d\r\n", (uint32_t)info_header.bits);
printf("Compression:%d\r\n", (uint32_t)info_header.compression); // 2 - 4 bit run length encoding
printf("Image size:%d\r\n", (uint32_t)info_header.imagesize);
printf("X resolution:%d\r\n", (uint32_t)info_header.xresolution);
printf("Y resolution:%d\r\n", (uint32_t)info_header.yresolution);
printf("Colors:%d\r\n", (uint32_t)info_header.ncolours);
printf("Important colors:%d\r\n", (uint32_t)info_header.importantcolours);
printf("RGB :%d\r\n", (uint32_t)info_header.rgb);
printf("RGB2 :%d\r\n", (uint32_t)info_header.rgb2);
uint8_t *palette = &bmpImage[HEADER_SIZE + INFO_HEADER_SIZE]; // 16 * 4 bytes = 64
// buffer de sortie, bitmap décompressé
uint8_t decompressed[320 * 240];
memset(decompressed, 0, 320*240);
// btea((uint32_t*) bmpImage, -128, key);
uint32_t pixel = 0; // specify the pixel offset
uint32_t i = 0;
do
{
uint8_t rleCmd = compressed[i];
if (rleCmd > 0)
{
uint8_t val = compressed[i + 1];
// repeat number of pixels
for (uint32_t j = 0; j < rleCmd; j++)
{
if ((j & 1) == 0)
{
decompressed[pixel] = (val & 0xF0) >>4;
}
else
{
decompressed[pixel] = (val & 0x0F);
}
pixel++;
}
i += 2; // jump pair instruction
}
else
{
uint8_t second = compressed[i + 1];
if (second == 0)
{
if (pixel % width)
{
// end of line
uint32_t lines = pixel / width;
uint32_t remaining = width - (pixel - (lines * width));
pixel += remaining;
}
i += 2;
}
else if (second == 1)
{
std::cout << "End of bitmap" << std::endl;
goto end;
}
else if (second == 2)
{
// delta N pixels and M lines
pixel += compressed[i + 2] + compressed[i + 3] * width;
i += 4;
}
else
{
// absolute mode
uint8_t *ptr = &compressed[i + 2];
// repeat number of pixels
for (uint32_t j = 0; j < second; j++)
{
if ((j & 1) == 0)
{
decompressed[pixel] = (*ptr & 0xF0) >> 4;
}
else
{
decompressed[pixel] = (*ptr & 0x0F);
ptr++;
}
pixel++;
}
i += 2 + (second / 2);
// padded in word boundary, jump if necessary
if ((second / 2) % 2)
{
i++;
}
}
}
if (pixel > (width * height))
{
std::cout << "Error!" << std::endl;
}
}
while( i < compressedSize);
end:
void *pixels;
int pitch;
SDL_LockTexture(texture, NULL, &pixels, &pitch);
// Définir la texture comme cible de rendu
SDL_SetRenderTarget(renderer, texture);
uint32_t x = 0, y = 0;
for (uint32_t i = 0; i < pixel; i++)
{
uint8_t val = decompressed[i];
if (val > 15)
{
std::cout << "Error!" << std::endl;
}
uint8_t *palettePtr = &palette[val * 4];
// Définir la couleur de rendu
SDL_SetRenderDrawColor(renderer, palettePtr[0], palettePtr[1], palettePtr[2], 255);
int flippedY = (height - 1) - y;
// Dessiner un point à la position (x, y)
SDL_RenderPoint(renderer, x, flippedY);
x++;
if (x >= width)
{
x = 0;
y++;
}
}
SDL_SetRenderTarget(renderer, NULL);
SDL_UnlockTexture(texture);
// std::ofstream outfile ("new.txt", std::ofstream::binary);
// outfile.write (reinterpret_cast<const char *>(decompressed), pixel / 2 );
// outfile.close();
}
// Simple helper function to load an image into a OpenGL texture with common settings
bool LoadTextureFromFile(const char* filename, Gui::Image &img)
{
SDL_Surface *surface, *temp;
bool useSdlImage = true;
surface = IMG_Load(filename);
if (!surface) {
SDL_Log("Couldn't load %s: %s\n", filename, SDL_GetError());
if (SysLib::GetFileExtension(filename) == "bmp")
{
// BMP
bmp_header_t header;
bmp_infoheader_t info_header;
uint8_t *data = nullptr;
size_t size = 0;
FILE *fil;
uint32_t offset;
fil = fopen(filename, "r");
// Lire tout le ficher
fseek(fil, 0, SEEK_END);
size = ftell(fil);
fseek(fil, 0, SEEK_SET);
uint8_t *bmpImage = (uint8_t *)malloc(size);
fread(bmpImage, 1, size, fil);
parse_bmp(bmpImage, &header, &info_header);
if (info_header.bits == 4)
{
auto tex = SDL_CreateTexture(renderer, SDL_PIXELFORMAT_RGBA32, SDL_TEXTUREACCESS_TARGET, info_header.width, info_header.height);
Decompress(bmpImage, size, tex);
useSdlImage = false;
img.texture = tex;
img.w = info_header.width;
img.h = info_header.height;
}
free(bmpImage);
}
if (useSdlImage)
{
surface = IMG_Load(filename);
if (!surface)
{
SDL_Log("Couldn't load %s: %s\n", filename, SDL_GetError());
return false;
}
/* Use the tonemap operator to convert to SDR output */
// const char *tonemap = NULL;
// SDL_SetStringProperty(SDL_GetSurfaceProperties(surface), SDL_PROP_SURFACE_TONEMAP_OPERATOR_STRING, tonemap);
temp = SDL_ConvertSurface(surface, SDL_PIXELFORMAT_RGBA32);
SDL_DestroySurface(surface);
if (!temp)
{
SDL_Log("Couldn't convert surface: %s\n", SDL_GetError());
return false;
}
img.texture = SDL_CreateTextureFromSurface(renderer, temp);
SDL_DestroySurface(temp);
if (!img.texture) {
SDL_Log("Couldn't create texture: %s\n", SDL_GetError());
return false;
}
}
/* Use the tonemap operator to convert to SDR output */
const char *tonemap = NULL;
SDL_SetStringProperty(SDL_GetSurfaceProperties(surface), SDL_PROP_SURFACE_TONEMAP_OPERATOR_STRING, tonemap);
temp = SDL_ConvertSurface(surface, SDL_PIXELFORMAT_RGBA32);
SDL_DestroySurface(surface);
if (!temp) {
SDL_Log("Couldn't convert surface: %s\n", SDL_GetError());
return false;
float w, h = 0;
SDL_GetTextureSize(static_cast<SDL_Texture*>(img.texture), &w, &h);
img.w = (int)w;
img.h = (int)h;
}
img.texture = SDL_CreateTextureFromSurface(renderer, temp);
SDL_DestroySurface(temp);
if (!img.texture) {
SDL_Log("Couldn't create texture: %s\n", SDL_GetError());
return false;
}
float w, h = 0;
SDL_GetTextureSize(static_cast<SDL_Texture*>(img.texture), &w, &h);
img.w = (int)w;
img.h = (int)h;
return true;
}

View file

@ -8,13 +8,14 @@
#define MAX_NB_NODES 1000
static ni_node_t gNodes[MAX_NB_NODES];
static struct {
uint32_t ri_size;
uint32_t si_size;
uint32_t li_size;
uint8_t gRiBlock[512];
uint8_t gSiBlock[512];
uint8_t gLiBlock[512];
uint8_t gRiBlock[XI_BLOCK_SIZE];
uint8_t gSiBlock[XI_BLOCK_SIZE];
uint8_t gLiBlock[XI_BLOCK_SIZE];
} pack;
#define DELTA 0x9e3779b9
@ -42,15 +43,6 @@ static void btea_decode(uint32_t *v, uint32_t n, const uint32_t *key)
static const uint32_t key[4] = {0x91bd7a0a, 0xa75440a9, 0xbbd49d6c, 0xe0dcc0e3};
void ni_set_ri_block(const uint8_t *data, uint32_t size)
{
memcpy(pack.gRiBlock, data, size);
pack.ri_size = size;
uint32_t n = size / 4;
btea_decode((uint32_t*)pack.gRiBlock, n, key);
}
uint32_t ni_get_ri_block(uint8_t *data)
{
memcpy(data, pack.gRiBlock, pack.ri_size);
@ -69,20 +61,38 @@ uint32_t ni_get_li_block(uint8_t *data)
return pack.li_size;
}
void ni_set_ri_block(const uint8_t *data, uint32_t size)
{
memcpy(pack.gRiBlock, data, size);
pack.ri_size = size;
ni_decode_block(pack.gRiBlock, size);
}
void ni_set_si_block(const uint8_t *data, uint32_t size)
{
memcpy(pack.gSiBlock, data, size);
pack.si_size = size;
uint32_t n = size / 4;
btea_decode((uint32_t*)pack.gSiBlock, n, key);
ni_decode_block(pack.gSiBlock, size);
}
void ni_set_li_block(const uint8_t *data, uint32_t size)
{
memcpy(pack.gLiBlock, data, size);
pack.li_size = size;
uint32_t n = size / 4;
btea_decode((uint32_t*) pack.gLiBlock, n, key);
ni_decode_block(pack.gLiBlock, size);
}
void ni_decode_block(uint8_t *data, uint32_t size)
{
if (size < 512)
{
uint32_t n = size / 4;
btea_decode((uint32_t*) data, n, key);
}
else
{
btea_decode((uint32_t*) data, 128, key);
}
}
void ni_decode_block512(uint8_t *data)
@ -115,14 +125,22 @@ bool ni_get_node_info(uint32_t index, node_info_t *node)
{
node->current = &gNodes[index];
// Copy sound file name
uint32_t offset = node->current->sound_asset_index_in_si * 12;
memcpy(node->si_file, &pack.gSiBlock[offset], 12);
node->si_file[12] = '\0';
if (node->current->sound_asset_index_in_si != 0xFFFFFFFF)
{
uint32_t offset = node->current->sound_asset_index_in_si * 12;
memcpy(node->si_file, &pack.gSiBlock[offset], 12);
node->si_file[12] = '\0';
}
else
{
// pas de son pour ce noeud
node->si_file[0] = '\0';
}
// Copy image file name
if (node->current->image_asset_index_in_ri != 0xFFFFFFFF)
{
offset = node->current->image_asset_index_in_ri * 12;
uint32_t offset = node->current->image_asset_index_in_ri * 12;
memcpy(node->ri_file, &pack.gRiBlock[offset], 12);
node->ri_file[12] = '\0';
}
@ -168,11 +186,11 @@ void ni_parse_nodes(ni_file_t *ni_file, const uint8_t *data)
ptr += 4;
n->sound_asset_index_in_si = leu32_get(ptr);
ptr += 4;
n->ok_transition_action_node_index_in_li = leu32_get(ptr);
n->ok_btn_node_idx_in_li = leu32_get(ptr);
ptr += 4;
n->ok_transition_number_of_options = leu32_get(ptr);
n->ok_btn_size_or_base_idx = leu32_get(ptr);
ptr += 4;
n->ok_transition_selected_option_index = leu32_get(ptr);
n->ok_btn_offset_from_base = leu32_get(ptr);
ptr += 4;
n->home_transition_action_node_index_in_li = leu32_get(ptr);
ptr += 4;

View file

@ -8,12 +8,15 @@
extern "C" {
#endif
#define XI_BLOCK_SIZE (8*1024)
typedef struct {
uint32_t image_asset_index_in_ri;
uint32_t sound_asset_index_in_si;
uint32_t ok_transition_action_node_index_in_li;
uint32_t ok_transition_number_of_options;
uint32_t ok_transition_selected_option_index;
uint32_t ok_btn_node_idx_in_li;
uint32_t ok_btn_size_or_base_idx;
uint32_t ok_btn_offset_from_base;
uint32_t home_transition_action_node_index_in_li;
uint32_t home_transition_number_of_options;
uint32_t home_transition_selected_option_index;
@ -47,7 +50,12 @@ typedef struct
uint32_t ni_get_number_of_images();
void ni_get_image(char buffer[13], uint32_t index);
uint32_t ni_get_node_index_in_li(uint32_t index_in_li, uint32_t selected);
// Block size at least 512 bytes be careful
void ni_decode_block512(uint8_t *data);
// block of any size
void ni_decode_block(uint8_t *data, uint32_t size);
bool ni_get_node_info(uint32_t index, node_info_t *node);
bool ni_parser(ni_file_t *ni_file, const uint8_t *data);

View file

@ -21,21 +21,6 @@ PackArchive::PackArchive(ILogger &log)
}
std::vector<std::string> PackArchive::GetImages()
{
std::vector<std::string> imgList;
for (uint32_t i = 0; i < ni_get_number_of_images(); i++)
{
char buffer[13];
ni_get_image(buffer, i);
imgList.push_back(buffer);
}
return imgList;
}
void PackArchive::Unzip(const std::string &filePath, const std::string &parent_dest_dir)
{
// std::string fileName = GetFileName(filePath);
@ -63,10 +48,6 @@ void PackArchive::Unzip(const std::string &filePath, const std::string &parent_d
(void) Zip::Unzip(filePath, parent_dest_dir, "");
}
static bool endsWith(const std::string& str, const std::string& suffix)
{
return str.size() >= suffix.size() && 0 == str.compare(str.size()-suffix.size(), suffix.size(), suffix);
}
bool StringToFile(const std::string &filePath, const std::string &data)
{
@ -154,12 +135,12 @@ std::vector<std::string> PackArchive::FilesInMemory(const std::string &type, con
return resList;
}
void PackArchive::ConvertCommercialFormat(StoryProject &proj, const std::string &basePath)
void PackArchive::ConvertCommercialFormat(StoryProject &proj, const std::filesystem::path &importBaseDir)
{
ResourceManager res(m_log);
// RI file is not ciphered
uint8_t data[512];
uint8_t data[XI_BLOCK_SIZE];
uint32_t size = ni_get_ri_block(data);
auto page = proj.GetPage(proj.MainUuid());
@ -175,7 +156,7 @@ void PackArchive::ConvertCommercialFormat(StoryProject &proj, const std::string
auto rData = std::make_shared<Resource>();
// origin
auto from = std::filesystem::path(basePath) / mPackName / "rf" / l;
auto from = importBaseDir / "rf" / l;
from += ".bmp";
// destination
@ -183,8 +164,8 @@ void PackArchive::ConvertCommercialFormat(StoryProject &proj, const std::string
auto to = proj.AssetsPath() / filename;
rData->file = filename;
rData->type = ResourceManager::ExtentionInfo(rData->file, ResourceManager::InfoType);
rData->format = ResourceManager::ExtentionInfo(rData->file, ResourceManager::InfoFormat);
rData->type = ResourceManager::ExtentionInfo(".bmp", ResourceManager::InfoType);
rData->format = ResourceManager::ExtentionInfo(".bmp", ResourceManager::InfoFormat);
res.Add(rData);
std::filesystem::copy(from, to, std::filesystem::copy_options::overwrite_existing);
@ -202,7 +183,7 @@ void PackArchive::ConvertCommercialFormat(StoryProject &proj, const std::string
auto rData = std::make_shared<Resource>();
// origin
auto from = std::filesystem::path(basePath) / mPackName / "sf" / l;
auto from = importBaseDir / "sf" / l;
from += ".mp3";
// destination
@ -210,8 +191,8 @@ void PackArchive::ConvertCommercialFormat(StoryProject &proj, const std::string
auto to = proj.AssetsPath() / filename;
rData->file = filename;
rData->type = ResourceManager::ExtentionInfo(rData->file, ResourceManager::InfoType);
rData->format = ResourceManager::ExtentionInfo(rData->file, ResourceManager::InfoFormat);
rData->type = ResourceManager::ExtentionInfo(".mp3", ResourceManager::InfoType);
rData->format = ResourceManager::ExtentionInfo(".mp3", ResourceManager::InfoFormat);
res.Add(rData);
std::filesystem::copy(from, to, std::filesystem::copy_options::overwrite_existing);
@ -233,8 +214,13 @@ void PackArchive::ConvertCommercialFormat(StoryProject &proj, const std::string
// key: node index, value: node uuidV4
std::map<int, std::string> nodeIds;
// key: node index, value: list of transitions
std::map<int, std::vector<uint32_t>> nodeTransitions;
// key: index in transition table
// value: list of node ids in desination
std::map<int, std::vector<int>> referencedIndexes;
// Direct nodes (no choices)
// key: nodeID source, value: nodeID destination
std::map<int, int> nodeLinks;
for (int i = 0; i < mNiFile.node_size; i++)
{
@ -255,33 +241,51 @@ void PackArchive::ConvertCommercialFormat(StoryProject &proj, const std::string
internalData["image"] = img.size() > 0 ? img + ".bmp" : "";
internalData["sound"] = snd.size() > 0 ? snd + ".mp3" : "";
std::cout << i << "\t==> Node\t" << img << "\t" << snd << std::endl;
std::cout << "\tOK node index in LI\t" << node_info.current->ok_btn_node_idx_in_li << std::endl;
std::cout << "\tOK number of options\t" << node_info.current->ok_btn_size_or_base_idx << std::endl;
std::cout << "\tOK selected option index\t" << node_info.current->ok_btn_offset_from_base << std::endl;
node->SetInternalData(internalData);
std::vector<uint32_t> jumpArray;
// Autre cas
if (node_info.current->ok_transition_number_of_options == 10)
if (node_info.current->wheel)
{
// For now, consider that this is a bad format
// In the future, consider using ok_transition_selected_option_index when ok_transition_number_of_options == 10
/*
Exemple d'un noeud de choix (wheel == true) avec trois noeuds :
node number 13 17 21
ok_btn_node_idx_in_li 36 36 36
ok_btn_size_or_base_idx 18 18 18
ok_btn_offset_from_base 0 2 4
// 00 00 00 00 ==> ok transition à zéro
// 0A 00 00 00 ==> nombre spécial, ou vraiment l'offset dans le fichier LI ?
// 01 00 00 00 ==> l'index dans le fichier LI à l'offset (disons, le premier élément)
Dans ce cas:
- le 18 est l'index de base sont situés les 3 choix
- 36+0 est l'index aller lors de l'appui sur OK pour le noeud 13
- 36+2 est l'index aller lors de l'appui sur OK pour le noeud 17
- 36+4 est l'index aller lors de l'appui sur OK pour le noeud 21
*/
jumpArray.push_back(transitions[node_info.current->ok_transition_action_node_index_in_li]);
// On ajouter ce noeud à la liste des références
// dans ce cas, le champs ok_btn_size_or_base_idx est interprété en tant que index
referencedIndexes[node_info.current->ok_btn_size_or_base_idx].push_back(i);
// On va créer le lien entre notre noeud et le noeud indiqué dans la table de transition
nodeLinks[i] = transitions[node_info.current->ok_btn_size_or_base_idx + node_info.current->ok_btn_offset_from_base];
}
else
{
// Vraies transitions
for (int jIndex = 0; jIndex < node_info.current->ok_transition_number_of_options; jIndex++)
{
jumpArray.push_back(transitions[node_info.current->ok_transition_action_node_index_in_li + jIndex]);
}
/*
ici, pas de wheel de sélection, donc c'est un son joué et un lien direct
*/
nodeLinks[i] = transitions[node_info.current->ok_btn_size_or_base_idx + node_info.current->ok_btn_offset_from_base];
}
nodeTransitions[i] = jumpArray;
}
else
{
@ -291,59 +295,26 @@ void PackArchive::ConvertCommercialFormat(StoryProject &proj, const std::string
}
// Create links, parse again the nodes
for (int i = 0; i < mNiFile.node_size; i++)
{
// for (int i = 0; i < mNiFile.node_size; i++)
//{
// std::cout << "Node id " << nodeIds[i] << " has " << nodeTransitions[i].size() << " transistions" << std::endl;
for (auto &j : nodeTransitions[i])
for (auto &j : nodeLinks)
{
auto c = std::make_shared<Connection>();
c->outNodeId = nodeIds[i];
c->outNodeId = nodeIds[j.first]; // source
c->outPortIndex = 0;
c->inNodeId = nodeIds[j];
c->inNodeId = nodeIds[j.second]; // destination
c->inPortIndex = 0;
page->AddLink(c);
}
}
//}
proj.Save(res);
}
bool PackArchive::LoadNiFile(const std::string &filePath)
{
bool success = false;
mZip.Close();
mCurrentNodeId = 0;
std::string fileName = SysLib::GetFileName(filePath);
std::string ext = SysLib::GetFileExtension(fileName);
SysLib::EraseString(fileName, "." + ext); // on retire l'extension du pack
mPackName = SysLib::ToUpper(fileName);
std::cout << "Pack name: " << mPackName << std::endl;
if (mZip.Open(filePath, true))
{
std::cout << "Number of files: " << mZip.NumberOfEntries() << std::endl;
if (ParseNIFile(mPackName))
{
success = true;
std::cout << "Parse NI file success\r\n" << std::endl;
ni_dump(&mNiFile);
ni_get_node_info(mCurrentNodeId, &mCurrentNode);
}
else
{
std::cout << "Parse NI file error\r\n" << std::endl;
}
}
return success;
}
std::string PackArchive::OpenImage(const std::string &fileName)
{
std::string f;
@ -461,127 +432,15 @@ bool PackArchive::ImportStudioFormat(const std::string &fileName, const std::str
return false;
}
std::string PackArchive::GetImage(const std::string &fileName)
{
//"C8B39950DE174EAA8E852A07FC468267/rf/000/05FB5530"
std::string imagePath = mPackName + "/rf/" + fileName;
SysLib::ReplaceCharacter(imagePath, "\\", "/");
std::cout << "Loading " + imagePath << std::endl;
return OpenImage(imagePath);
}
std::string PackArchive::CurrentImage()
{
return GetImage(std::string(mCurrentNode.ri_file));
}
std::string PackArchive::CurrentSound()
{
//"C8B39950DE174EAA8E852A07FC468267/sf/000/05FB5530"
std::string soundPath = mPackName + "/sf/" + std::string(mCurrentNode.si_file);
SysLib::ReplaceCharacter(soundPath, "\\", "/");
std::cout << "Loading " + soundPath << std::endl;
std::string f;
if (mZip.GetFile(soundPath, f))
{
ni_decode_block512(reinterpret_cast<uint8_t *>(f.data()));
return f;
}
else
{
std::cout << "Cannot load file from ZIP" << std::endl;
}
return "";
}
std::string PackArchive::CurrentSoundName()
{
return std::string(mCurrentNode.si_file);
}
bool PackArchive::AutoPlay()
{
return mCurrentNode.current->auto_play;
}
bool PackArchive::IsRoot() const
{
return mCurrentNodeId == 0;
}
bool PackArchive::IsWheelEnabled() const
{
return mCurrentNode.current->wheel;
}
void PackArchive::Next()
{
// L'index de circulation dans le tableau des transitions commence à 1 (pas à zéro ...)
uint32_t index = 1;
if (mCurrentNode.current->ok_transition_selected_option_index < mNodeForChoice.current->ok_transition_number_of_options)
{
index = mCurrentNode.current->ok_transition_selected_option_index + 1;
}
// sinon on revient à l'index 0 (début du tableau des transitions)
mCurrentNodeId = ni_get_node_index_in_li(mNodeForChoice.current->ok_transition_action_node_index_in_li, index - 1);
ni_get_node_info(mCurrentNodeId, &mCurrentNode);
}
void PackArchive::Previous()
{
// L'index de circulation dans le tableau des transitions commence à 1 (pas à zéro ...)
uint32_t index = 1;
if (mCurrentNode.current->ok_transition_selected_option_index > 1)
{
index = mCurrentNode.current->ok_transition_selected_option_index - 1;
}
else
{
index = mNodeForChoice.current->ok_transition_number_of_options;
}
mCurrentNodeId = ni_get_node_index_in_li(mNodeForChoice.current->ok_transition_action_node_index_in_li, index - 1);
ni_get_node_info(mCurrentNodeId, &mCurrentNode);
}
void PackArchive::OkButton()
{
if (mCurrentNode.current->home_transition_number_of_options > 0)
{
// On doit faire un choix!
// On sauvegarde ce noeud car il va servir pour naviguer dans les choix
mNodeIdForChoice = mCurrentNodeId;
ni_get_node_info(mNodeIdForChoice, &mNodeForChoice);
}
mCurrentNodeId = ni_get_node_index_in_li(mCurrentNode.current->ok_transition_action_node_index_in_li, mCurrentNode.current->ok_transition_selected_option_index);
ni_get_node_info(mCurrentNodeId, &mCurrentNode);
}
bool PackArchive::HasImage()
{
return std::string(mCurrentNode.ri_file).size() > 1;
}
bool PackArchive::ParseNIFile(const std::string &root)
bool PackArchive::ParseRootFiles(const std::filesystem::path &root)
{
bool success = true;
std::string f;
if (mZip.GetFile(root + "/li", f))
{
ni_set_li_block(reinterpret_cast<const uint8_t *>(f.data()), f.size());
}
else
{
success = false;
std::cout << "[PACK_ARCHIVE] Cannot find LI file" << std::endl;
}
if (mZip.GetFile(root + "/ri", f))
f = SysLib::ReadFile(root / "ri");
if (f.size() > 0)
{
// Deciphering is done in this function
ni_set_ri_block(reinterpret_cast<const uint8_t *>(f.data()), f.size());
}
else
@ -590,8 +449,10 @@ bool PackArchive::ParseNIFile(const std::string &root)
std::cout << "[PACK_ARCHIVE] Cannot find RI file" << std::endl;
}
if (mZip.GetFile(root + "/si", f))
f = SysLib::ReadFile(root / "si");
if (f.size() > 0)
{
// Deciphering is done in this function
ni_set_si_block(reinterpret_cast<const uint8_t *>(f.data()), f.size());
}
else
@ -600,12 +461,26 @@ bool PackArchive::ParseNIFile(const std::string &root)
std::cout << "[PACK_ARCHIVE] Cannot find SI file" << std::endl;
}
if (mZip.GetFile(root + "/ni", f))
f = SysLib::ReadFile(root / "li");
if (f.size() > 0)
{
// Deciphering is done in this function
ni_set_li_block(reinterpret_cast<const uint8_t *>(f.data()), f.size());
}
else
{
success = false;
std::cout << "[PACK_ARCHIVE] Cannot find LI file" << std::endl;
}
f = SysLib::ReadFile(root / "ni");
if (f.size() > 0)
{
success = success & ni_parser(&mNiFile, reinterpret_cast<const uint8_t *>(f.data()));
}
else
{
success = false;
std::cout << "[PACK_ARCHIVE] Cannot find NI file" << std::endl;
}
return success;

View file

@ -4,6 +4,7 @@
#include <ranges>
#include <string>
#include <vector>
#include <filesystem>
#include "zip.h"
#include "ni_parser.h"
@ -12,35 +13,92 @@
#include "i_logger.h"
#include "i_story_db.h"
#include "story_project.h"
#include "sys_lib.h"
class PackArchive
{
public:
PackArchive(ILogger &log);
bool LoadNiFile(const std::string &filePath);
std::string OpenImage(const std::string &fileName);
bool ImportStudioFormat(const std::string &fileName, const std::string &outputDir);
template<typename Range>
// requires std::ranges::range<Range>
void ImportCommercialFormat(const std::string &packFileName, const std::string &outputDir, Range&& range)
void ImportCommercialFormat(const std::string &packFileName, const std::string &libraryBaseDir, Range&& range)
{
auto uuid = Uuid().String();
std::string basePath = outputDir + "/" + uuid;
std::string outputBaseDir = libraryBaseDir + "/" + uuid;
Unzip(packFileName, basePath);
LoadNiFile(packFileName);
auto ext = SysLib::GetFileExtension(packFileName);
std::filesystem::path importBaseDir;
// Selon l'importation, l'UUID peut être partiel (à partir d'une carte SD) ou complet (pour un .pk)
std::string packUuidv4;
if (ext == "pk")
{
// Unzip all before analyze the pack
Unzip(packFileName, outputBaseDir);
// Le pack Lunii contient un répertoire contenant l'UUID sans tirets, upper case
packUuidv4 = SysLib::GetFileName(packFileName);
SysLib::EraseString(packUuidv4, "." + ext); // on retire l'extension du pack
importBaseDir = std::filesystem::path(outputBaseDir) / SysLib::ToUpper(packUuidv4);
}
else
{
// Ici on a choisi le fichier ni, donc on prend juste le répertoire parent
importBaseDir = SysLib::GetDirectory(packFileName);
std::string packDirNameOnly = SysLib::GetFileName(importBaseDir);
// Ici on va copier le répertoire dans un dossier de travail pour éviter de corrompre le
// répertoire d'origine (vu qu'on decipher tout)
const auto copyOptions = std::filesystem::copy_options::recursive
| std::filesystem::copy_options::update_existing
| std::filesystem::copy_options::overwrite_existing
;
std::string workingDir = std::filesystem::path(outputBaseDir) / packDirNameOnly;
std::filesystem::create_directories(workingDir);
std::filesystem::copy(importBaseDir, workingDir, copyOptions);
importBaseDir = workingDir; // on travaille là maintenant
packUuidv4 = SysLib::ToLower(packDirNameOnly); // le répertoire parent est l'UUID mais partiel !! (la fin d'un full UUID)
}
if (ParseRootFiles(importBaseDir))
{
m_log.Log("Parse NI file success");
ni_dump(&mNiFile);
}
else
{
m_log.Log("Parse NI file error", true);
}
StoryProject proj(m_log);
proj.New(uuid, outputDir);
auto packUuidv4 = normalizeUUID(mPackName);
proj.New(uuid, libraryBaseDir);
for (auto &info : range)
{
std::cout << info.uuid << std::endl;
if (info.uuid == packUuidv4)
bool foundStory = false;
// full UUIDv4 size
if (packUuidv4.size() == 32)
{
packUuidv4 = normalizeUUID(packUuidv4);
foundStory = (info.uuid == packUuidv4);
}
else
{
// Partial UUIDv4, uniquement les 8 derniers caractères
foundStory = info.uuid.ends_with(packUuidv4);
}
if (foundStory)
{
m_log.Log("Found commercial story: " + info.title);
proj.SetName(info.title);
@ -53,8 +111,7 @@ public:
}
}
std::string path = basePath + "/" + mPackName + "/rf";
for (const auto & entry : std::filesystem::directory_iterator(path))
for (const auto & entry : std::filesystem::directory_iterator(importBaseDir / "rf"))
{
if (entry.is_directory())
{
@ -63,8 +120,7 @@ public:
}
}
path = basePath + "/" + mPackName + "/sf";
for (const auto & entry : std::filesystem::directory_iterator(path))
for (const auto & entry : std::filesystem::directory_iterator(importBaseDir / "sf"))
{
if (entry.is_directory())
{
@ -73,21 +129,9 @@ public:
}
}
ConvertCommercialFormat(proj, basePath);
ConvertCommercialFormat(proj, importBaseDir);
}
std::string CurrentImage();
std::string CurrentSound();
std::string CurrentSoundName();
bool AutoPlay();
void OkButton();
bool HasImage();
std::vector<std::string> GetImages();
std::string GetImage(const std::string &fileName);
bool IsRoot() const;
bool IsWheelEnabled() const;
void Next();
void Previous();
void Unzip(const std::string &filePath, const std::string &parent_dest_dir);
bool ConvertJsonStudioToOst(const std::string &basePath, const std::string &uuid, const std::string &outputDir);
@ -96,16 +140,11 @@ public:
private:
ILogger &m_log;
Zip mZip;
std::string mPackName;
uint32_t mCurrentNodeId = 0;
uint32_t mNodeIdForChoice = 0;
node_info_t mNodeForChoice;
node_info_t mCurrentNode;
ni_file_t mNiFile;
void ConvertCommercialFormat(StoryProject &proj, const std::string &basePath);
void ConvertCommercialFormat(StoryProject &proj, const std::filesystem::path &importBaseDir);
bool ParseNIFile(const std::string &root);
bool ParseRootFiles(const std::filesystem::path &root);
// Convertit un UUID de type "3ADE540306254FFFA22B9025AC3678D9"
// en standard : 3ade5403-0625-4fff-a22b-9025ac3678d9

View file

@ -138,7 +138,7 @@ void LibraryWindow::Initialize()
std::cout << "Commercial store file already exists, skipping download" << std::endl;
ParseCommercialStoreDataCallback(true, m_commercialStoreFile);
}
else
else
{
m_downloadQueue.push({
"dl_commercial",
@ -469,12 +469,14 @@ void LibraryWindow::Draw()
IGFD::FileDialogConfig config;
config.path = m_libraryManager.LibraryPath();
config.countSelectionMax = 1;
config.sidePane = std::bind(&InfosPane, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3);
config.sidePaneWidth = 350.0f;
// config.sidePane = std::bind(&InfosPane, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3);
// config.sidePaneWidth = 350.0f;
config.flags = ImGuiFileDialogFlags_Modal;
const char *filters = "Commercial stories (*.pk ni){.pk, ((ni))}, Community stories (*.zip *.json){.zip,.json}";
ImGuiFileDialog::Instance()->OpenDialog("ImportStoryDlgKey",
"Import story",
".zip, .json, .pk",
filters,
config
);
}
@ -649,11 +651,16 @@ void LibraryWindow::Draw()
{
if (ImGuiFileDialog::Instance()->IsOk())
{
std::string filePathName = ImGuiFileDialog::Instance()->GetFilePathName();
std::string filePath = ImGuiFileDialog::Instance()->GetCurrentPath();
std::string filter = ImGuiFileDialog::Instance()->GetCurrentFilter();
// Import "Studio" or "Commercial" format
m_storyManager.ImportProject(filePathName, formatFilter);
std::map<std::string, std::string> sel = ImGuiFileDialog::Instance()->GetSelection();
if (sel.size() > 0)
{
std::string fileName = sel.begin()->first;
std::string filePathName = sel.begin()->second;
// Import "Studio" or "Commercial" format
m_storyManager.ImportProject(filePathName, formatFilter);
}
}
// close
ImGuiFileDialog::Instance()->Close();

View file

@ -7,6 +7,7 @@
#include "pack_archive.h"
#include "uuid.h"
#include "sys_lib.h"
#ifdef USE_WINDOWS_OS
#include <winsock2.h>
@ -47,6 +48,12 @@ MainWindow::MainWindow()
m_chip32_ctx.syscall = static_cast<syscall_t>(Callback<uint8_t(chip32_ctx_t *, uint8_t)>::callback);
CloseProject();
// define style for all directories
ImGuiFileDialog::Instance()->SetFileStyle(IGFD_FileStyleByTypeDir, "", ImVec4(0.5f, 1.0f, 0.9f, 0.9f), ICON_MDI_FOLDER);
// define style for all files
ImGuiFileDialog::Instance()->SetFileStyle(IGFD_FileStyleByTypeFile, "", ImVec4(1.0f, 1.0f, 1.0f, 1.0f), ICON_MDI_FILE);
}
MainWindow::~MainWindow()
@ -793,19 +800,27 @@ void MainWindow::OpenProject(const std::string &uuid)
}
void MainWindow::ImportProject(const std::string &fileName, int format)
void MainWindow::ImportProject(const std::string &filePathName, int format)
{
(void) format;
PackArchive archive(*this);
if (format == 0)
{
archive.ImportStudioFormat(fileName, m_libraryManager.LibraryPath());
}
else
{
archive.ImportCommercialFormat(fileName, m_libraryManager.LibraryPath(), m_libraryManager.CommercialDbView());
}
// On va déterminer le type de fichier selon l'extension
auto ext = SysLib::GetFileExtension(filePathName);
auto filename = SysLib::GetFileName(filePathName);
if ((ext == "pk") || (filename == "ni"))
{
archive.ImportCommercialFormat(filePathName, m_libraryManager.LibraryPath(), m_libraryManager.CommercialDbView());
}
else if ((ext == "json") || (ext == "zip"))
{
archive.ImportStudioFormat(filePathName, m_libraryManager.LibraryPath());
}
else
{
Log("Unknown file format: " + filePathName);
}
}
void MainWindow::RefreshProjectInformation()

View file

@ -128,7 +128,7 @@ private:
// From IStoryManager (proxy to StoryProject class)
virtual void OpenProject(const std::string &uuid) override;
virtual void ImportProject(const std::string &fileName, int format);
virtual void ImportProject(const std::string &filePathName, int format);
virtual void PlaySoundFile(const std::string &fileName) override;;
virtual std::string BuildFullAssetsPath(const std::string_view fileName) const override;
virtual std::pair<FilterIterator, FilterIterator> Images() override;